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::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    /// Each RBP `GK: 'a` is assumed to be true. These encode
26    /// relationships like `T: 'a` that are added via implicit bounds
27    /// or the `param_env`.
28    ///
29    /// Each region here is guaranteed to be a key in the `indices`
30    /// map. We use the "original" regions (i.e., the keys from the
31    /// map, and not the values) because the code in
32    /// `process_registered_region_obligations` has some special-cased
33    /// logic expecting to see (e.g.) `ReStatic`, and if we supplied
34    /// our special inference variable there, we would mess that up.
35    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    /// Given an instance of the closure type, this method instantiates the "extra" requirements
81    /// that we computed for the closure. This has the effect of adding new outlives obligations
82    /// to existing region variables in `closure_args`.
83    #[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        // Extract the values of the free regions in `closure_args`
91        // into a vector. These are the regions that we will be
92        // relating to one another.
93        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        // Create the predicates.
102        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        // Extract out various useful fields we'll need below.
129        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                // This may actually be reachable. If so, we should convert
145                // this to a proper error/consider whether we should detect
146                // this somewhere else.
147                bug!(
148                    "unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
149                );
150            }
151
152            let mut next_outlives_predicates = vec![];
153            for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
154                match k1.kind() {
155                    GenericArgKind::Lifetime(r1) => {
156                        let r1_vid = self.to_region_vid(r1);
157                        let r2_vid = self.to_region_vid(r2);
158                        self.add_outlives(r1_vid, r2_vid, constraint_category);
159                    }
160
161                    GenericArgKind::Type(mut t1) => {
162                        // Normalize the type we receive from a `TypeOutlives` obligation
163                        // in the new trait solver.
164                        if infcx.next_trait_solver() {
165                            t1 = self.normalize_and_add_type_outlives_constraints(
166                                t1,
167                                &mut next_outlives_predicates,
168                            );
169                        }
170
171                        let implicit_region_bound =
172                            ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
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                        TypeOutlives::new(
177                            &mut *self,
178                            tcx,
179                            region_bound_pairs,
180                            Some(implicit_region_bound),
181                            known_type_outlives_obligations,
182                        )
183                        .type_must_outlive(
184                            origin,
185                            t1,
186                            r2,
187                            constraint_category,
188                        );
189                    }
190
191                    GenericArgKind::Const(_) => unreachable!(),
192                }
193            }
194
195            outlives_predicates = next_outlives_predicates;
196        }
197    }
198
199    /// Placeholder regions need to be converted eagerly because it may
200    /// create new region variables, which we must not do when verifying
201    /// our region bounds.
202    ///
203    /// FIXME: This should get removed once higher ranked region obligations
204    /// are dealt with during trait solving.
205    fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
206        if value.has_placeholders() {
207            fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
208                ty::RePlaceholder(placeholder) => {
209                    self.constraints.placeholder_region(self.infcx, placeholder)
210                }
211                _ => r,
212            })
213        } else {
214            value
215        }
216    }
217
218    fn verify_to_type_test(
219        &mut self,
220        generic_kind: GenericKind<'tcx>,
221        region: ty::Region<'tcx>,
222        verify_bound: VerifyBound<'tcx>,
223    ) -> TypeTest<'tcx> {
224        let lower_bound = self.to_region_vid(region);
225        TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
226    }
227
228    fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
229        if let ty::RePlaceholder(placeholder) = r.kind() {
230            self.constraints.placeholder_region(self.infcx, placeholder).as_var()
231        } else {
232            self.universal_regions.to_region_vid(r)
233        }
234    }
235
236    fn add_outlives(
237        &mut self,
238        sup: ty::RegionVid,
239        sub: ty::RegionVid,
240        category: ConstraintCategory<'tcx>,
241    ) {
242        let category = match self.category {
243            ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
244            _ => self.category,
245        };
246        self.constraints.outlives_constraints.push(OutlivesConstraint {
247            locations: self.locations,
248            category,
249            span: self.span,
250            sub,
251            sup,
252            variance_info: ty::VarianceDiagInfo::default(),
253            from_closure: self.from_closure,
254        });
255    }
256
257    fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
258        debug!("add_type_test(type_test={:?})", type_test);
259        self.constraints.type_tests.push(type_test);
260    }
261
262    fn normalize_and_add_type_outlives_constraints(
263        &self,
264        ty: Ty<'tcx>,
265        next_outlives_predicates: &mut Vec<(
266            ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
267            ConstraintCategory<'tcx>,
268        )>,
269    ) -> Ty<'tcx> {
270        match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
271        {
272            Ok(TypeOpOutput { output: ty, constraints, .. }) => {
273                if let Some(QueryRegionConstraints { outlives }) = constraints {
274                    next_outlives_predicates.extend(outlives.iter().copied());
275                }
276                ty
277            }
278            Err(_) => ty,
279        }
280    }
281}
282
283impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
284    fn push_sub_region_constraint(
285        &mut self,
286        _origin: SubregionOrigin<'tcx>,
287        a: ty::Region<'tcx>,
288        b: ty::Region<'tcx>,
289        constraint_category: ConstraintCategory<'tcx>,
290    ) {
291        let b = self.to_region_vid(b);
292        let a = self.to_region_vid(a);
293        self.add_outlives(b, a, constraint_category);
294    }
295
296    fn push_verify(
297        &mut self,
298        _origin: SubregionOrigin<'tcx>,
299        kind: GenericKind<'tcx>,
300        a: ty::Region<'tcx>,
301        bound: VerifyBound<'tcx>,
302    ) {
303        let kind = self.replace_placeholders_with_nll(kind);
304        let bound = self.replace_placeholders_with_nll(bound);
305        let type_test = self.verify_to_type_test(kind, a, bound);
306        self.add_type_test(type_test);
307    }
308}