rustc_borrowck/type_check/
constraint_conversion.rs

1use 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    /// 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    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    /// Given an instance of the closure type, this method instantiates the "extra" requirements
84    /// that we computed for the closure. This has the effect of adding new outlives obligations
85    /// to existing region variables in `closure_args`.
86    #[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        // Extract the values of the free regions in `closure_args`
94        // into a vector. These are the regions that we will be
95        // relating to one another.
96        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        // Create the predicates.
105        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        // Extract out various useful fields we'll need below.
137        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                // This may actually be reachable. If so, we should convert
153                // this to a proper error/consider whether we should detect
154                // this somewhere else.
155                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                // Constraint is implied by a coroutine's well-formedness.
163                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                        // Scraped constraints may have had inference vars.
179                        t1 = self.infcx.resolve_vars_if_possible(t1);
180
181                        // Normalize the type we receive from a `TypeOutlives` obligation
182                        // in the new trait solver.
183                        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                        // we don't actually use this for anything, but
193                        // the `TypeOutlives` code needs an origin.
194                        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    /// Placeholder regions need to be converted eagerly because it may
219    /// create new region variables, which we must not do when verifying
220    /// our region bounds.
221    ///
222    /// FIXME: This should get removed once higher ranked region obligations
223    /// are dealt with during trait solving.
224    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                // FIXME(higher_ranked_auto): What should we do with the assumptions here?
293                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}