]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Rollup merge of #101779 - eholk:drop-tracking-test-output, r=jyn514
[rust.git] / compiler / rustc_borrowck / src / type_check / constraint_conversion.rs
1 use rustc_infer::infer::canonical::QueryOutlivesConstraint;
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::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<'a, '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     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
42 }
43
44 impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
45     pub(crate) fn new(
46         infcx: &'a InferCtxt<'a, 'tcx>,
47         universal_regions: &'a UniversalRegions<'tcx>,
48         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
49         implicit_region_bound: ty::Region<'tcx>,
50         param_env: ty::ParamEnv<'tcx>,
51         locations: Locations,
52         span: Span,
53         category: ConstraintCategory<'tcx>,
54         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
55     ) -> Self {
56         Self {
57             infcx,
58             tcx: infcx.tcx,
59             universal_regions,
60             region_bound_pairs,
61             implicit_region_bound,
62             param_env,
63             locations,
64             span,
65             category,
66             constraints,
67         }
68     }
69
70     #[instrument(skip(self), level = "debug")]
71     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
72         let QueryRegionConstraints { outlives, member_constraints } = query_constraints;
73
74         // Annoying: to invoke `self.to_region_vid`, we need access to
75         // `self.constraints`, but we also want to be mutating
76         // `self.member_constraints`. For now, just swap out the value
77         // we want and replace at the end.
78         let mut tmp = std::mem::take(&mut self.constraints.member_constraints);
79         for member_constraint in member_constraints {
80             tmp.push_constraint(member_constraint, |r| self.to_region_vid(r));
81         }
82         self.constraints.member_constraints = tmp;
83
84         for query_constraint in outlives {
85             self.convert(query_constraint);
86         }
87     }
88
89     fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
90         debug!("generate: constraints at: {:#?}", self.locations);
91
92         // Extract out various useful fields we'll need below.
93         let ConstraintConversion {
94             tcx, region_bound_pairs, implicit_region_bound, param_env, ..
95         } = *self;
96
97         // At the moment, we never generate any "higher-ranked"
98         // region constraints like `for<'a> 'a: 'b`. At some point
99         // when we move to universes, we will, and this assertion
100         // will start to fail.
101         let ty::OutlivesPredicate(k1, r2) =
102             query_constraint.0.no_bound_vars().unwrap_or_else(|| {
103                 bug!("query_constraint {:?} contained bound vars", query_constraint,);
104             });
105
106         let constraint_category = query_constraint.1;
107
108         match k1.unpack() {
109             GenericArgKind::Lifetime(r1) => {
110                 let r1_vid = self.to_region_vid(r1);
111                 let r2_vid = self.to_region_vid(r2);
112                 self.add_outlives(r1_vid, r2_vid, constraint_category);
113             }
114
115             GenericArgKind::Type(t1) => {
116                 // we don't actually use this for anything, but
117                 // the `TypeOutlives` code needs an origin.
118                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
119
120                 TypeOutlives::new(
121                     &mut *self,
122                     tcx,
123                     region_bound_pairs,
124                     Some(implicit_region_bound),
125                     param_env,
126                 )
127                 .type_must_outlive(origin, t1, r2, constraint_category);
128             }
129
130             GenericArgKind::Const(_) => {
131                 // Consts cannot outlive one another, so we
132                 // don't need to handle any relations here.
133             }
134         }
135     }
136
137     /// Placeholder regions need to be converted eagerly because it may
138     /// create new region variables, which we must not do when verifying
139     /// our region bounds.
140     ///
141     /// FIXME: This should get removed once higher ranked region obligations
142     /// are dealt with during trait solving.
143     fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
144         if value.has_placeholders() {
145             self.tcx.fold_regions(value, |r, _| match *r {
146                 ty::RePlaceholder(placeholder) => {
147                     self.constraints.placeholder_region(self.infcx, placeholder)
148                 }
149                 _ => r,
150             })
151         } else {
152             value
153         }
154     }
155
156     fn verify_to_type_test(
157         &mut self,
158         generic_kind: GenericKind<'tcx>,
159         region: ty::Region<'tcx>,
160         verify_bound: VerifyBound<'tcx>,
161     ) -> TypeTest<'tcx> {
162         let lower_bound = self.to_region_vid(region);
163         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
164     }
165
166     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
167         if let ty::RePlaceholder(placeholder) = *r {
168             self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
169         } else {
170             self.universal_regions.to_region_vid(r)
171         }
172     }
173
174     fn add_outlives(
175         &mut self,
176         sup: ty::RegionVid,
177         sub: ty::RegionVid,
178         category: ConstraintCategory<'tcx>,
179     ) {
180         let category = match self.category {
181             ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
182             _ => self.category,
183         };
184         self.constraints.outlives_constraints.push(OutlivesConstraint {
185             locations: self.locations,
186             category,
187             span: self.span,
188             sub,
189             sup,
190             variance_info: ty::VarianceDiagInfo::default(),
191         });
192     }
193
194     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
195         debug!("add_type_test(type_test={:?})", type_test);
196         self.constraints.type_tests.push(type_test);
197     }
198 }
199
200 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
201     fn push_sub_region_constraint(
202         &mut self,
203         _origin: SubregionOrigin<'tcx>,
204         a: ty::Region<'tcx>,
205         b: ty::Region<'tcx>,
206         constraint_category: ConstraintCategory<'tcx>,
207     ) {
208         let b = self.to_region_vid(b);
209         let a = self.to_region_vid(a);
210         self.add_outlives(b, a, constraint_category);
211     }
212
213     fn push_verify(
214         &mut self,
215         _origin: SubregionOrigin<'tcx>,
216         kind: GenericKind<'tcx>,
217         a: ty::Region<'tcx>,
218         bound: VerifyBound<'tcx>,
219     ) {
220         let kind = self.replace_placeholders_with_nll(kind);
221         let bound = self.replace_placeholders_with_nll(bound);
222         let type_test = self.verify_to_type_test(kind, a, bound);
223         self.add_type_test(type_test);
224     }
225 }