rustc_borrowck/type_check/
constraint_conversion.rs1use rustc_data_structures::fx::FxHashSet;
2use rustc_hir::def_id::LocalDefId;
3use rustc_infer::infer::SubregionOrigin;
4use rustc_infer::infer::canonical::QueryRegionConstraints;
5use rustc_infer::infer::outlives::env::RegionBoundPairs;
6use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
7use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
8use rustc_infer::traits::query::type_op::DeeplyNormalize;
9use rustc_middle::bug;
10use rustc_middle::ty::{
11 self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions,
12};
13use rustc_span::Span;
14use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
15use tracing::{debug, instrument};
16
17use crate::constraints::OutlivesConstraint;
18use crate::region_infer::TypeTest;
19use crate::type_check::{Locations, MirTypeckRegionConstraints};
20use crate::universal_regions::UniversalRegions;
21use crate::{
22 BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory,
23};
24
25pub(crate) struct ConstraintConversion<'a, 'tcx> {
26 infcx: &'a BorrowckInferCtxt<'tcx>,
27 universal_regions: &'a UniversalRegions<'tcx>,
28 region_bound_pairs: &'a RegionBoundPairs<'tcx>,
39 known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
40 locations: Locations,
41 span: Span,
42 category: ConstraintCategory<'tcx>,
43 from_closure: bool,
44 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
45}
46
47impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
48 pub(crate) fn new(
49 infcx: &'a BorrowckInferCtxt<'tcx>,
50 universal_regions: &'a UniversalRegions<'tcx>,
51 region_bound_pairs: &'a RegionBoundPairs<'tcx>,
52 known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
53 locations: Locations,
54 span: Span,
55 category: ConstraintCategory<'tcx>,
56 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
57 ) -> Self {
58 Self {
59 infcx,
60 universal_regions,
61 region_bound_pairs,
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, assumptions } = query_constraints;
74 let assumptions =
75 elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
76
77 for &(predicate, constraint_category) in outlives {
78 self.convert(predicate, constraint_category, &assumptions);
79 }
80 }
81
82 #[instrument(skip(self), level = "debug")]
86 pub(crate) fn apply_closure_requirements(
87 &mut self,
88 closure_requirements: &ClosureRegionRequirements<'tcx>,
89 closure_def_id: LocalDefId,
90 closure_args: ty::GenericArgsRef<'tcx>,
91 ) {
92 let closure_mapping = &UniversalRegions::closure_mapping(
96 self.infcx.tcx,
97 closure_args,
98 closure_requirements.num_external_vids,
99 closure_def_id,
100 );
101 debug!(?closure_mapping);
102
103 let backup = (self.category, self.span, self.from_closure);
105 self.from_closure = true;
106 for outlives_requirement in &closure_requirements.outlives_requirements {
107 let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
108 let subject = match outlives_requirement.subject {
109 ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
110 ClosureOutlivesSubject::Ty(subject_ty) => {
111 subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
112 }
113 };
114
115 self.category = outlives_requirement.category;
116 self.span = outlives_requirement.blame_span;
117 self.convert(
118 ty::OutlivesPredicate(subject, outlived_region),
119 self.category,
120 &Default::default(),
121 );
122 }
123 (self.category, self.span, self.from_closure) = backup;
124 }
125
126 fn convert(
127 &mut self,
128 predicate: ty::ArgOutlivesPredicate<'tcx>,
129 constraint_category: ConstraintCategory<'tcx>,
130 higher_ranked_assumptions: &FxHashSet<ty::ArgOutlivesPredicate<'tcx>>,
131 ) {
132 let tcx = self.infcx.tcx;
133 debug!("generate: constraints at: {:#?}", self.locations);
134
135 let ConstraintConversion {
137 infcx,
138 universal_regions,
139 region_bound_pairs,
140 known_type_outlives_obligations,
141 ..
142 } = *self;
143
144 let mut outlives_predicates = vec![(predicate, constraint_category)];
145 for iteration in 0.. {
146 if outlives_predicates.is_empty() {
147 break;
148 }
149
150 if !tcx.recursion_limit().value_within_limit(iteration) {
151 bug!(
155 "unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
156 );
157 }
158
159 let mut next_outlives_predicates = vec![];
160 for (pred, constraint_category) in outlives_predicates {
161 if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
163 && higher_ranked_assumptions.contains(&pred)
164 {
165 continue;
166 }
167
168 let ty::OutlivesPredicate(k1, r2) = pred;
169 match k1.kind() {
170 GenericArgKind::Lifetime(r1) => {
171 let r1_vid = self.to_region_vid(r1);
172 let r2_vid = self.to_region_vid(r2);
173 self.add_outlives(r1_vid, r2_vid, constraint_category);
174 }
175
176 GenericArgKind::Type(mut t1) => {
177 t1 = self.infcx.resolve_vars_if_possible(t1);
179
180 if infcx.next_trait_solver() {
183 t1 = self.normalize_and_add_type_outlives_constraints(
184 t1,
185 &mut next_outlives_predicates,
186 );
187 }
188
189 let implicit_region_bound =
190 ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
191 let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
194 TypeOutlives::new(
195 &mut *self,
196 tcx,
197 region_bound_pairs,
198 Some(implicit_region_bound),
199 known_type_outlives_obligations,
200 )
201 .type_must_outlive(
202 origin,
203 t1,
204 r2,
205 constraint_category,
206 );
207 }
208
209 GenericArgKind::Const(_) => unreachable!(),
210 }
211 }
212
213 outlives_predicates = next_outlives_predicates;
214 }
215 }
216
217 fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
224 if value.has_placeholders() {
225 fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
226 ty::RePlaceholder(placeholder) => {
227 self.constraints.placeholder_region(self.infcx, placeholder)
228 }
229 _ => r,
230 })
231 } else {
232 value
233 }
234 }
235
236 fn verify_to_type_test(
237 &mut self,
238 generic_kind: GenericKind<'tcx>,
239 region: ty::Region<'tcx>,
240 verify_bound: VerifyBound<'tcx>,
241 ) -> TypeTest<'tcx> {
242 let lower_bound = self.to_region_vid(region);
243 TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
244 }
245
246 fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
247 if let ty::RePlaceholder(placeholder) = r.kind() {
248 self.constraints.placeholder_region(self.infcx, placeholder).as_var()
249 } else {
250 self.universal_regions.to_region_vid(r)
251 }
252 }
253
254 fn add_outlives(
255 &mut self,
256 sup: ty::RegionVid,
257 sub: ty::RegionVid,
258 category: ConstraintCategory<'tcx>,
259 ) {
260 let category = match self.category {
261 ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
262 _ => self.category,
263 };
264 self.constraints.outlives_constraints.push(OutlivesConstraint {
265 locations: self.locations,
266 category,
267 span: self.span,
268 sub,
269 sup,
270 variance_info: ty::VarianceDiagInfo::default(),
271 from_closure: self.from_closure,
272 });
273 }
274
275 fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
276 debug!("add_type_test(type_test={:?})", type_test);
277 self.constraints.type_tests.push(type_test);
278 }
279
280 fn normalize_and_add_type_outlives_constraints(
281 &self,
282 ty: Ty<'tcx>,
283 next_outlives_predicates: &mut Vec<(
284 ty::ArgOutlivesPredicate<'tcx>,
285 ConstraintCategory<'tcx>,
286 )>,
287 ) -> Ty<'tcx> {
288 match self.infcx.param_env.and(DeeplyNormalize { value: ty }).fully_perform(
289 self.infcx,
290 self.infcx.root_def_id,
291 self.span,
292 ) {
293 Ok(TypeOpOutput { output: ty, constraints, .. }) => {
294 if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
296 next_outlives_predicates.extend(outlives.iter().copied());
297 }
298 ty
299 }
300 Err(_) => ty,
301 }
302 }
303}
304
305impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
306 fn push_sub_region_constraint(
307 &mut self,
308 _origin: SubregionOrigin<'tcx>,
309 a: ty::Region<'tcx>,
310 b: ty::Region<'tcx>,
311 constraint_category: ConstraintCategory<'tcx>,
312 ) {
313 let b = self.to_region_vid(b);
314 let a = self.to_region_vid(a);
315 self.add_outlives(b, a, constraint_category);
316 }
317
318 fn push_verify(
319 &mut self,
320 _origin: SubregionOrigin<'tcx>,
321 kind: GenericKind<'tcx>,
322 a: ty::Region<'tcx>,
323 bound: VerifyBound<'tcx>,
324 ) {
325 let kind = self.replace_placeholders_with_nll(kind);
326 let bound = self.replace_placeholders_with_nll(bound);
327 let type_test = self.verify_to_type_test(kind, a, bound);
328 self.add_type_test(type_test);
329 }
330}