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