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};
14 constraints::OutlivesConstraint,
16 region_infer::TypeTest,
17 type_check::{Locations, MirTypeckRegionConstraints},
18 universal_regions::UniversalRegions,
21 pub(crate) struct ConstraintConversion<'a, 'tcx> {
22 infcx: &'a InferCtxt<'a, '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`.
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>,
40 category: ConstraintCategory<'tcx>,
41 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
44 impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
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>,
53 category: ConstraintCategory<'tcx>,
54 constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
61 implicit_region_bound,
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;
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));
82 self.constraints.member_constraints = tmp;
84 for query_constraint in outlives {
85 self.convert(query_constraint);
89 pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
90 debug!("generate: constraints at: {:#?}", self.locations);
92 // Extract out various useful fields we'll need below.
93 let ConstraintConversion {
94 tcx, region_bound_pairs, implicit_region_bound, param_env, ..
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,);
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);
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);
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)
133 Some(implicit_region_bound),
136 .type_must_outlive(origin, t1, r2);
139 GenericArgKind::Const(_) => {
140 // Consts cannot outlive one another, so we
141 // don't need to handle any relations here.
146 fn verify_to_type_test(
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);
154 TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
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()
161 self.universal_regions.to_region_vid(r)
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,
172 variance_info: ty::VarianceDiagInfo::default(),
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);
182 impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
183 fn push_sub_region_constraint(
185 _origin: SubregionOrigin<'tcx>,
189 let b = self.to_region_vid(b);
190 let a = self.to_region_vid(a);
191 self.add_outlives(b, a);
196 _origin: SubregionOrigin<'tcx>,
197 kind: GenericKind<'tcx>,
199 bound: VerifyBound<'tcx>,
201 let type_test = self.verify_to_type_test(kind, a, bound);
202 self.add_type_test(type_test);