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