rustc_borrowck/type_check/
constraint_conversion.rs1use rustc_hir::def_id::LocalDefId;
2use rustc_infer::infer::canonical::QueryRegionConstraints;
3use rustc_infer::infer::outlives::env::RegionBoundPairs;
4use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
5use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
6use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
7use rustc_infer::traits::query::type_op::DeeplyNormalize;
8use rustc_middle::bug;
9use rustc_middle::ty::{
10 self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
11};
12use rustc_span::Span;
13use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
14use tracing::{debug, instrument};
15
16use crate::constraints::OutlivesConstraint;
17use crate::region_infer::TypeTest;
18use crate::type_check::{Locations, MirTypeckRegionConstraints};
19use crate::universal_regions::UniversalRegions;
20use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
21
22pub(crate) struct ConstraintConversion<'a, 'tcx> {
23 infcx: &'a InferCtxt<'tcx>,
24 universal_regions: &'a UniversalRegions<'tcx>,
25 region_bound_pairs: &'a RegionBoundPairs<'tcx>,
36 param_env: ty::ParamEnv<'tcx>,
37 known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
38 locations: Locations,
39 span: Span,
40 category: ConstraintCategory<'tcx>,
41 from_closure: bool,
42 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
43}
44
45impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
46 pub(crate) fn new(
47 infcx: &'a InferCtxt<'tcx>,
48 universal_regions: &'a UniversalRegions<'tcx>,
49 region_bound_pairs: &'a RegionBoundPairs<'tcx>,
50 param_env: ty::ParamEnv<'tcx>,
51 known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
52 locations: Locations,
53 span: Span,
54 category: ConstraintCategory<'tcx>,
55 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
56 ) -> Self {
57 Self {
58 infcx,
59 universal_regions,
60 region_bound_pairs,
61 param_env,
62 known_type_outlives_obligations,
63 locations,
64 span,
65 category,
66 constraints,
67 from_closure: false,
68 }
69 }
70
71 #[instrument(skip(self), level = "debug")]
72 pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
73 let QueryRegionConstraints { outlives } = query_constraints;
74
75 for &(predicate, constraint_category) in outlives {
76 self.convert(predicate, constraint_category);
77 }
78 }
79
80 #[instrument(skip(self), level = "debug")]
84 pub(crate) fn apply_closure_requirements(
85 &mut self,
86 closure_requirements: &ClosureRegionRequirements<'tcx>,
87 closure_def_id: LocalDefId,
88 closure_args: ty::GenericArgsRef<'tcx>,
89 ) {
90 let closure_mapping = &UniversalRegions::closure_mapping(
94 self.infcx.tcx,
95 closure_args,
96 closure_requirements.num_external_vids,
97 closure_def_id,
98 );
99 debug!(?closure_mapping);
100
101 let backup = (self.category, self.span, self.from_closure);
103 self.from_closure = true;
104 for outlives_requirement in &closure_requirements.outlives_requirements {
105 let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
106 let subject = match outlives_requirement.subject {
107 ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
108 ClosureOutlivesSubject::Ty(subject_ty) => {
109 subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
110 }
111 };
112
113 self.category = outlives_requirement.category;
114 self.span = outlives_requirement.blame_span;
115 self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
116 }
117 (self.category, self.span, self.from_closure) = backup;
118 }
119
120 fn convert(
121 &mut self,
122 predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
123 constraint_category: ConstraintCategory<'tcx>,
124 ) {
125 let tcx = self.infcx.tcx;
126 debug!("generate: constraints at: {:#?}", self.locations);
127
128 let ConstraintConversion {
130 infcx,
131 universal_regions,
132 region_bound_pairs,
133 known_type_outlives_obligations,
134 ..
135 } = *self;
136
137 let mut outlives_predicates = vec![(predicate, constraint_category)];
138 for iteration in 0.. {
139 if outlives_predicates.is_empty() {
140 break;
141 }
142
143 if !tcx.recursion_limit().value_within_limit(iteration) {
144 bug!(
145 "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
146 );
147 }
148
149 let mut next_outlives_predicates = vec![];
150 for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
151 match k1.kind() {
152 GenericArgKind::Lifetime(r1) => {
153 let r1_vid = self.to_region_vid(r1);
154 let r2_vid = self.to_region_vid(r2);
155 self.add_outlives(r1_vid, r2_vid, constraint_category);
156 }
157
158 GenericArgKind::Type(mut t1) => {
159 if infcx.next_trait_solver() {
162 t1 = self.normalize_and_add_type_outlives_constraints(
163 t1,
164 &mut next_outlives_predicates,
165 );
166 }
167
168 let implicit_region_bound =
169 ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
170 let origin = infer::RelateParamBound(self.span, t1, None);
173 TypeOutlives::new(
174 &mut *self,
175 tcx,
176 region_bound_pairs,
177 Some(implicit_region_bound),
178 known_type_outlives_obligations,
179 )
180 .type_must_outlive(
181 origin,
182 t1,
183 r2,
184 constraint_category,
185 );
186 }
187
188 GenericArgKind::Const(_) => unreachable!(),
189 }
190 }
191
192 outlives_predicates = next_outlives_predicates;
193 }
194 }
195
196 fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
203 if value.has_placeholders() {
204 fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
205 ty::RePlaceholder(placeholder) => {
206 self.constraints.placeholder_region(self.infcx, placeholder)
207 }
208 _ => r,
209 })
210 } else {
211 value
212 }
213 }
214
215 fn verify_to_type_test(
216 &mut self,
217 generic_kind: GenericKind<'tcx>,
218 region: ty::Region<'tcx>,
219 verify_bound: VerifyBound<'tcx>,
220 ) -> TypeTest<'tcx> {
221 let lower_bound = self.to_region_vid(region);
222 TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
223 }
224
225 fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
226 if let ty::RePlaceholder(placeholder) = r.kind() {
227 self.constraints.placeholder_region(self.infcx, placeholder).as_var()
228 } else {
229 self.universal_regions.to_region_vid(r)
230 }
231 }
232
233 fn add_outlives(
234 &mut self,
235 sup: ty::RegionVid,
236 sub: ty::RegionVid,
237 category: ConstraintCategory<'tcx>,
238 ) {
239 let category = match self.category {
240 ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
241 _ => self.category,
242 };
243 self.constraints.outlives_constraints.push(OutlivesConstraint {
244 locations: self.locations,
245 category,
246 span: self.span,
247 sub,
248 sup,
249 variance_info: ty::VarianceDiagInfo::default(),
250 from_closure: self.from_closure,
251 });
252 }
253
254 fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
255 debug!("add_type_test(type_test={:?})", type_test);
256 self.constraints.type_tests.push(type_test);
257 }
258
259 fn normalize_and_add_type_outlives_constraints(
260 &self,
261 ty: Ty<'tcx>,
262 next_outlives_predicates: &mut Vec<(
263 ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
264 ConstraintCategory<'tcx>,
265 )>,
266 ) -> Ty<'tcx> {
267 match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
268 {
269 Ok(TypeOpOutput { output: ty, constraints, .. }) => {
270 if let Some(QueryRegionConstraints { outlives }) = constraints {
271 next_outlives_predicates.extend(outlives.iter().copied());
272 }
273 ty
274 }
275 Err(_) => ty,
276 }
277 }
278}
279
280impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
281 fn push_sub_region_constraint(
282 &mut self,
283 _origin: SubregionOrigin<'tcx>,
284 a: ty::Region<'tcx>,
285 b: ty::Region<'tcx>,
286 constraint_category: ConstraintCategory<'tcx>,
287 ) {
288 let b = self.to_region_vid(b);
289 let a = self.to_region_vid(a);
290 self.add_outlives(b, a, constraint_category);
291 }
292
293 fn push_verify(
294 &mut self,
295 _origin: SubregionOrigin<'tcx>,
296 kind: GenericKind<'tcx>,
297 a: ty::Region<'tcx>,
298 bound: VerifyBound<'tcx>,
299 ) {
300 let kind = self.replace_placeholders_with_nll(kind);
301 let bound = self.replace_placeholders_with_nll(bound);
302 let type_test = self.verify_to_type_test(kind, a, bound);
303 self.add_type_test(type_test);
304 }
305}