]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Rollup merge of #107771 - estebank:ice-msg, r=compiler-errors
[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             self.convert(predicate, constraint_category);
88         }
89     }
90
91     /// Given an instance of the closure type, this method instantiates the "extra" requirements
92     /// that we computed for the closure. This has the effect of adding new outlives obligations
93     /// to existing region variables in `closure_substs`.
94     #[instrument(skip(self), level = "debug")]
95     pub fn apply_closure_requirements(
96         &mut self,
97         closure_requirements: &ClosureRegionRequirements<'tcx>,
98         closure_def_id: DefId,
99         closure_substs: ty::SubstsRef<'tcx>,
100     ) {
101         // Extract the values of the free regions in `closure_substs`
102         // into a vector. These are the regions that we will be
103         // relating to one another.
104         let closure_mapping = &UniversalRegions::closure_mapping(
105             self.tcx,
106             closure_substs,
107             closure_requirements.num_external_vids,
108             closure_def_id.expect_local(),
109         );
110         debug!(?closure_mapping);
111
112         // Create the predicates.
113         let backup = (self.category, self.span, self.from_closure);
114         self.from_closure = true;
115         for outlives_requirement in &closure_requirements.outlives_requirements {
116             let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
117             let subject = match outlives_requirement.subject {
118                 ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
119                 ClosureOutlivesSubject::Ty(ty) => ty.into(),
120             };
121
122             self.category = outlives_requirement.category;
123             self.span = outlives_requirement.blame_span;
124             self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
125         }
126         (self.category, self.span, self.from_closure) = backup;
127     }
128
129     fn convert(
130         &mut self,
131         predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
132         constraint_category: ConstraintCategory<'tcx>,
133     ) {
134         debug!("generate: constraints at: {:#?}", self.locations);
135
136         // Extract out various useful fields we'll need below.
137         let ConstraintConversion {
138             tcx, region_bound_pairs, implicit_region_bound, param_env, ..
139         } = *self;
140
141         let ty::OutlivesPredicate(k1, r2) = predicate;
142         match k1.unpack() {
143             GenericArgKind::Lifetime(r1) => {
144                 let r1_vid = self.to_region_vid(r1);
145                 let r2_vid = self.to_region_vid(r2);
146                 self.add_outlives(r1_vid, r2_vid, constraint_category);
147             }
148
149             GenericArgKind::Type(t1) => {
150                 // we don't actually use this for anything, but
151                 // the `TypeOutlives` code needs an origin.
152                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
153
154                 TypeOutlives::new(
155                     &mut *self,
156                     tcx,
157                     region_bound_pairs,
158                     Some(implicit_region_bound),
159                     param_env,
160                 )
161                 .type_must_outlive(origin, t1, r2, constraint_category);
162             }
163
164             GenericArgKind::Const(_) => unreachable!(),
165         }
166     }
167
168     /// Placeholder regions need to be converted eagerly because it may
169     /// create new region variables, which we must not do when verifying
170     /// our region bounds.
171     ///
172     /// FIXME: This should get removed once higher ranked region obligations
173     /// are dealt with during trait solving.
174     fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
175         if value.has_placeholders() {
176             self.tcx.fold_regions(value, |r, _| match *r {
177                 ty::RePlaceholder(placeholder) => {
178                     self.constraints.placeholder_region(self.infcx, placeholder)
179                 }
180                 _ => r,
181             })
182         } else {
183             value
184         }
185     }
186
187     fn verify_to_type_test(
188         &mut self,
189         generic_kind: GenericKind<'tcx>,
190         region: ty::Region<'tcx>,
191         verify_bound: VerifyBound<'tcx>,
192     ) -> TypeTest<'tcx> {
193         let lower_bound = self.to_region_vid(region);
194         TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
195     }
196
197     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
198         if let ty::RePlaceholder(placeholder) = *r {
199             self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
200         } else {
201             self.universal_regions.to_region_vid(r)
202         }
203     }
204
205     fn add_outlives(
206         &mut self,
207         sup: ty::RegionVid,
208         sub: ty::RegionVid,
209         category: ConstraintCategory<'tcx>,
210     ) {
211         let category = match self.category {
212             ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
213             _ => self.category,
214         };
215         self.constraints.outlives_constraints.push(OutlivesConstraint {
216             locations: self.locations,
217             category,
218             span: self.span,
219             sub,
220             sup,
221             variance_info: ty::VarianceDiagInfo::default(),
222             from_closure: self.from_closure,
223         });
224     }
225
226     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
227         debug!("add_type_test(type_test={:?})", type_test);
228         self.constraints.type_tests.push(type_test);
229     }
230 }
231
232 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
233     fn push_sub_region_constraint(
234         &mut self,
235         _origin: SubregionOrigin<'tcx>,
236         a: ty::Region<'tcx>,
237         b: ty::Region<'tcx>,
238         constraint_category: ConstraintCategory<'tcx>,
239     ) {
240         let b = self.to_region_vid(b);
241         let a = self.to_region_vid(a);
242         self.add_outlives(b, a, constraint_category);
243     }
244
245     fn push_verify(
246         &mut self,
247         _origin: SubregionOrigin<'tcx>,
248         kind: GenericKind<'tcx>,
249         a: ty::Region<'tcx>,
250         bound: VerifyBound<'tcx>,
251     ) {
252         let kind = self.replace_placeholders_with_nll(kind);
253         let bound = self.replace_placeholders_with_nll(bound);
254         let type_test = self.verify_to_type_test(kind, a, bound);
255         self.add_type_test(type_test);
256     }
257 }