rustc_borrowck/type_check/
constraint_conversion.rs

1use 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    /// Each RBP `GK: 'a` is assumed to be true. These encode
27    /// relationships like `T: 'a` that are added via implicit bounds
28    /// or the `param_env`.
29    ///
30    /// Each region here is guaranteed to be a key in the `indices`
31    /// map. We use the "original" regions (i.e., the keys from the
32    /// map, and not the values) because the code in
33    /// `process_registered_region_obligations` has some special-cased
34    /// logic expecting to see (e.g.) `ReStatic`, and if we supplied
35    /// our special inference variable there, we would mess that up.
36    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    /// Given an instance of the closure type, this method instantiates the "extra" requirements
86    /// that we computed for the closure. This has the effect of adding new outlives obligations
87    /// to existing region variables in `closure_args`.
88    #[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        // Extract the values of the free regions in `closure_args`
96        // into a vector. These are the regions that we will be
97        // relating to one another.
98        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        // Create the predicates.
107        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        // Extract out various useful fields we'll need below.
133        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                        // Normalize the type we receive from a `TypeOutlives` obligation
165                        // in the new trait solver.
166                        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                        // we don't actually use this for anything, but
174                        // the `TypeOutlives` code needs an origin.
175                        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    /// Placeholder regions need to be converted eagerly because it may
201    /// create new region variables, which we must not do when verifying
202    /// our region bounds.
203    ///
204    /// FIXME: This should get removed once higher ranked region obligations
205    /// are dealt with during trait solving.
206    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}