]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Rollup merge of #99837 - TaKO8Ki:avoid-symbol-to-string-conversions, r=fee1-dead
[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::TypeVisitable;
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     pub(super) 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) = query_constraint.no_bound_vars().unwrap_or_else(|| {
102             bug!("query_constraint {:?} contained bound vars", query_constraint,);
103         });
104
105         match k1.unpack() {
106             GenericArgKind::Lifetime(r1) => {
107                 let r1_vid = self.to_region_vid(r1);
108                 let r2_vid = self.to_region_vid(r2);
109                 self.add_outlives(r1_vid, r2_vid);
110             }
111
112             GenericArgKind::Type(mut t1) => {
113                 // we don't actually use this for anything, but
114                 // the `TypeOutlives` code needs an origin.
115                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
116
117                 // Placeholder regions need to be converted now because it may
118                 // create new region variables, which can't be done later when
119                 // verifying these bounds.
120                 if t1.has_placeholders() {
121                     t1 = tcx.fold_regions(t1, |r, _| match *r {
122                         ty::RePlaceholder(placeholder) => {
123                             self.constraints.placeholder_region(self.infcx, placeholder)
124                         }
125                         _ => r,
126                     });
127                 }
128
129                 TypeOutlives::new(
130                     &mut *self,
131                     tcx,
132                     region_bound_pairs,
133                     Some(implicit_region_bound),
134                     param_env,
135                 )
136                 .type_must_outlive(origin, t1, r2);
137             }
138
139             GenericArgKind::Const(_) => {
140                 // Consts cannot outlive one another, so we
141                 // don't need to handle any relations here.
142             }
143         }
144     }
145
146     fn verify_to_type_test(
147         &mut self,
148         generic_kind: GenericKind<'tcx>,
149         region: ty::Region<'tcx>,
150         verify_bound: VerifyBound<'tcx>,
151     ) -> TypeTest<'tcx> {
152         let lower_bound = self.to_region_vid(region);
153
154         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
155     }
156
157     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
158         if let ty::RePlaceholder(placeholder) = *r {
159             self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
160         } else {
161             self.universal_regions.to_region_vid(r)
162         }
163     }
164
165     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
166         self.constraints.outlives_constraints.push(OutlivesConstraint {
167             locations: self.locations,
168             category: self.category,
169             span: self.span,
170             sub,
171             sup,
172             variance_info: ty::VarianceDiagInfo::default(),
173         });
174     }
175
176     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
177         debug!("add_type_test(type_test={:?})", type_test);
178         self.constraints.type_tests.push(type_test);
179     }
180 }
181
182 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
183     fn push_sub_region_constraint(
184         &mut self,
185         _origin: SubregionOrigin<'tcx>,
186         a: ty::Region<'tcx>,
187         b: ty::Region<'tcx>,
188     ) {
189         let b = self.to_region_vid(b);
190         let a = self.to_region_vid(a);
191         self.add_outlives(b, a);
192     }
193
194     fn push_verify(
195         &mut self,
196         _origin: SubregionOrigin<'tcx>,
197         kind: GenericKind<'tcx>,
198         a: ty::Region<'tcx>,
199         bound: VerifyBound<'tcx>,
200     ) {
201         let type_test = self.verify_to_type_test(kind, a, bound);
202         self.add_type_test(type_test);
203     }
204 }