]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
e15d1b99ad205229e2d7b901e101da1bcc5614b5
[rust.git] / compiler / rustc_borrowck / src / type_check / constraint_conversion.rs
1 use rustc_hir::def_id::DefId;
2 use rustc_infer::infer::canonical::QueryRegionConstraints;
3 use rustc_infer::infer::outlives::env::RegionBoundPairs;
4 use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
5 use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
6 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
7 use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
8 use rustc_middle::ty::subst::GenericArgKind;
9 use rustc_middle::ty::TypeFoldable;
10 use rustc_middle::ty::{self, TyCtxt};
11 use rustc_span::{Span, DUMMY_SP};
12
13 use crate::{
14     constraints::OutlivesConstraint,
15     nll::ToRegionVid,
16     region_infer::TypeTest,
17     type_check::{Locations, MirTypeckRegionConstraints},
18     universal_regions::UniversalRegions,
19 };
20
21 pub(crate) struct ConstraintConversion<'a, 'tcx> {
22     infcx: &'a InferCtxt<'tcx>,
23     tcx: TyCtxt<'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     implicit_region_bound: ty::Region<'tcx>,
37     param_env: ty::ParamEnv<'tcx>,
38     locations: Locations,
39     span: Span,
40     category: ConstraintCategory<'tcx>,
41     from_closure: bool,
42     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
43 }
44
45 impl<'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         implicit_region_bound: ty::Region<'tcx>,
51         param_env: ty::ParamEnv<'tcx>,
52         locations: Locations,
53         span: Span,
54         category: ConstraintCategory<'tcx>,
55         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
56     ) -> Self {
57         Self {
58             infcx,
59             tcx: infcx.tcx,
60             universal_regions,
61             region_bound_pairs,
62             implicit_region_bound,
63             param_env,
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, member_constraints } = query_constraints;
75
76         // Annoying: to invoke `self.to_region_vid`, we need access to
77         // `self.constraints`, but we also want to be mutating
78         // `self.member_constraints`. For now, just swap out the value
79         // we want and replace at the end.
80         let mut tmp = std::mem::take(&mut self.constraints.member_constraints);
81         for member_constraint in member_constraints {
82             tmp.push_constraint(member_constraint, |r| self.to_region_vid(r));
83         }
84         self.constraints.member_constraints = tmp;
85
86         for (predicate, constraint_category) in outlives {
87             // At the moment, we never generate any "higher-ranked"
88             // region constraints like `for<'a> 'a: 'b`. At some point
89             // when we move to universes, we will, and this assertion
90             // will start to fail.
91             let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
92                 bug!("query_constraint {:?} contained bound vars", predicate,);
93             });
94
95             self.convert(predicate, *constraint_category);
96         }
97     }
98
99     /// Given an instance of the closure type, this method instantiates the "extra" requirements
100     /// that we computed for the closure. This has the effect of adding new outlives obligations
101     /// to existing region variables in `closure_substs`.
102     #[instrument(skip(self), level = "debug")]
103     pub fn apply_closure_requirements(
104         &mut self,
105         closure_requirements: &ClosureRegionRequirements<'tcx>,
106         closure_def_id: DefId,
107         closure_substs: ty::SubstsRef<'tcx>,
108     ) {
109         // Extract the values of the free regions in `closure_substs`
110         // into a vector. These are the regions that we will be
111         // relating to one another.
112         let closure_mapping = &UniversalRegions::closure_mapping(
113             self.tcx,
114             closure_substs,
115             closure_requirements.num_external_vids,
116             closure_def_id.expect_local(),
117         );
118         debug!(?closure_mapping);
119
120         // Create the predicates.
121         let backup = (self.category, self.span, self.from_closure);
122         self.from_closure = true;
123         for outlives_requirement in &closure_requirements.outlives_requirements {
124             let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
125             let subject = match outlives_requirement.subject {
126                 ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
127                 ClosureOutlivesSubject::Ty(ty) => ty.into(),
128             };
129
130             self.category = outlives_requirement.category;
131             self.span = outlives_requirement.blame_span;
132             self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
133         }
134         (self.category, self.span, self.from_closure) = backup;
135     }
136
137     fn convert(
138         &mut self,
139         predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
140         constraint_category: ConstraintCategory<'tcx>,
141     ) {
142         debug!("generate: constraints at: {:#?}", self.locations);
143
144         // Extract out various useful fields we'll need below.
145         let ConstraintConversion {
146             tcx, region_bound_pairs, implicit_region_bound, param_env, ..
147         } = *self;
148
149         let ty::OutlivesPredicate(k1, r2) = predicate;
150         match k1.unpack() {
151             GenericArgKind::Lifetime(r1) => {
152                 let r1_vid = self.to_region_vid(r1);
153                 let r2_vid = self.to_region_vid(r2);
154                 self.add_outlives(r1_vid, r2_vid, constraint_category);
155             }
156
157             GenericArgKind::Type(t1) => {
158                 // we don't actually use this for anything, but
159                 // the `TypeOutlives` code needs an origin.
160                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
161
162                 TypeOutlives::new(
163                     &mut *self,
164                     tcx,
165                     region_bound_pairs,
166                     Some(implicit_region_bound),
167                     param_env,
168                 )
169                 .type_must_outlive(origin, t1, r2, constraint_category);
170             }
171
172             GenericArgKind::Const(_) => unreachable!(),
173         }
174     }
175
176     /// Placeholder regions need to be converted eagerly because it may
177     /// create new region variables, which we must not do when verifying
178     /// our region bounds.
179     ///
180     /// FIXME: This should get removed once higher ranked region obligations
181     /// are dealt with during trait solving.
182     fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
183         if value.has_placeholders() {
184             self.tcx.fold_regions(value, |r, _| match *r {
185                 ty::RePlaceholder(placeholder) => {
186                     self.constraints.placeholder_region(self.infcx, placeholder)
187                 }
188                 _ => r,
189             })
190         } else {
191             value
192         }
193     }
194
195     fn verify_to_type_test(
196         &mut self,
197         generic_kind: GenericKind<'tcx>,
198         region: ty::Region<'tcx>,
199         verify_bound: VerifyBound<'tcx>,
200     ) -> TypeTest<'tcx> {
201         let lower_bound = self.to_region_vid(region);
202         TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
203     }
204
205     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
206         if let ty::RePlaceholder(placeholder) = *r {
207             self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
208         } else {
209             self.universal_regions.to_region_vid(r)
210         }
211     }
212
213     fn add_outlives(
214         &mut self,
215         sup: ty::RegionVid,
216         sub: ty::RegionVid,
217         category: ConstraintCategory<'tcx>,
218     ) {
219         let category = match self.category {
220             ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
221             _ => self.category,
222         };
223         self.constraints.outlives_constraints.push(OutlivesConstraint {
224             locations: self.locations,
225             category,
226             span: self.span,
227             sub,
228             sup,
229             variance_info: ty::VarianceDiagInfo::default(),
230             from_closure: self.from_closure,
231         });
232     }
233
234     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
235         debug!("add_type_test(type_test={:?})", type_test);
236         self.constraints.type_tests.push(type_test);
237     }
238 }
239
240 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
241     fn push_sub_region_constraint(
242         &mut self,
243         _origin: SubregionOrigin<'tcx>,
244         a: ty::Region<'tcx>,
245         b: ty::Region<'tcx>,
246         constraint_category: ConstraintCategory<'tcx>,
247     ) {
248         let b = self.to_region_vid(b);
249         let a = self.to_region_vid(a);
250         self.add_outlives(b, a, constraint_category);
251     }
252
253     fn push_verify(
254         &mut self,
255         _origin: SubregionOrigin<'tcx>,
256         kind: GenericKind<'tcx>,
257         a: ty::Region<'tcx>,
258         bound: VerifyBound<'tcx>,
259     ) {
260         let kind = self.replace_placeholders_with_nll(kind);
261         let bound = self.replace_placeholders_with_nll(bound);
262         let type_test = self.verify_to_type_test(kind, a, bound);
263         self.add_type_test(type_test);
264     }
265 }