rustc_borrowck/type_check/
constraint_conversion.rs

1use 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    /// Each RBP `GK: 'a` is assumed to be true. These encode
29    /// relationships like `T: 'a` that are added via implicit bounds
30    /// or the `param_env`.
31    ///
32    /// Each region here is guaranteed to be a key in the `indices`
33    /// map. We use the "original" regions (i.e., the keys from the
34    /// map, and not the values) because the code in
35    /// `process_registered_region_obligations` has some special-cased
36    /// logic expecting to see (e.g.) `ReStatic`, and if we supplied
37    /// our special inference variable there, we would mess that up.
38    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    /// Given an instance of the closure type, this method instantiates the "extra" requirements
83    /// that we computed for the closure. This has the effect of adding new outlives obligations
84    /// to existing region variables in `closure_args`.
85    #[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        // Extract the values of the free regions in `closure_args`
93        // into a vector. These are the regions that we will be
94        // relating to one another.
95        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        // Create the predicates.
104        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        // Extract out various useful fields we'll need below.
136        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                // This may actually be reachable. If so, we should convert
152                // this to a proper error/consider whether we should detect
153                // this somewhere else.
154                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                // Constraint is implied by a coroutine's well-formedness.
162                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                        // Scraped constraints may have had inference vars.
178                        t1 = self.infcx.resolve_vars_if_possible(t1);
179
180                        // Normalize the type we receive from a `TypeOutlives` obligation
181                        // in the new trait solver.
182                        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                        // we don't actually use this for anything, but
192                        // the `TypeOutlives` code needs an origin.
193                        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    /// Placeholder regions need to be converted eagerly because it may
218    /// create new region variables, which we must not do when verifying
219    /// our region bounds.
220    ///
221    /// FIXME: This should get removed once higher ranked region obligations
222    /// are dealt with during trait solving.
223    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                // FIXME(higher_ranked_auto): What should we do with the assumptions here?
295                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}