diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_borrowck/src/type_check/constraint_conversion.rs | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs new file mode 100644 index 000000000..167960918 --- /dev/null +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -0,0 +1,204 @@ +use rustc_infer::infer::canonical::QueryOutlivesConstraint; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; +use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; +use rustc_middle::mir::ConstraintCategory; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{Span, DUMMY_SP}; + +use crate::{ + constraints::OutlivesConstraint, + nll::ToRegionVid, + region_infer::TypeTest, + type_check::{Locations, MirTypeckRegionConstraints}, + universal_regions::UniversalRegions, +}; + +pub(crate) struct ConstraintConversion<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + tcx: TyCtxt<'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + /// Each RBP `GK: 'a` is assumed to be true. These encode + /// relationships like `T: 'a` that are added via implicit bounds + /// or the `param_env`. + /// + /// Each region here is guaranteed to be a key in the `indices` + /// map. We use the "original" regions (i.e., the keys from the + /// map, and not the values) because the code in + /// `process_registered_region_obligations` has some special-cased + /// logic expecting to see (e.g.) `ReStatic`, and if we supplied + /// our special inference variable there, we would mess that up. + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: ty::Region<'tcx>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, + span: Span, + category: ConstraintCategory<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, +} + +impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { + pub(crate) fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + universal_regions: &'a UniversalRegions<'tcx>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + implicit_region_bound: ty::Region<'tcx>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, + span: Span, + category: ConstraintCategory<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + ) -> Self { + Self { + infcx, + tcx: infcx.tcx, + universal_regions, + region_bound_pairs, + implicit_region_bound, + param_env, + locations, + span, + category, + constraints, + } + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { + let QueryRegionConstraints { outlives, member_constraints } = query_constraints; + + // Annoying: to invoke `self.to_region_vid`, we need access to + // `self.constraints`, but we also want to be mutating + // `self.member_constraints`. For now, just swap out the value + // we want and replace at the end. + let mut tmp = std::mem::take(&mut self.constraints.member_constraints); + for member_constraint in member_constraints { + tmp.push_constraint(member_constraint, |r| self.to_region_vid(r)); + } + self.constraints.member_constraints = tmp; + + for query_constraint in outlives { + self.convert(query_constraint); + } + } + + pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { + debug!("generate: constraints at: {:#?}", self.locations); + + // Extract out various useful fields we'll need below. + let ConstraintConversion { + tcx, region_bound_pairs, implicit_region_bound, param_env, .. + } = *self; + + // At the moment, we never generate any "higher-ranked" + // region constraints like `for<'a> 'a: 'b`. At some point + // when we move to universes, we will, and this assertion + // will start to fail. + let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", query_constraint,); + }); + + match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + let r1_vid = self.to_region_vid(r1); + let r2_vid = self.to_region_vid(r2); + self.add_outlives(r1_vid, r2_vid); + } + + GenericArgKind::Type(mut t1) => { + // we don't actually use this for anything, but + // the `TypeOutlives` code needs an origin. + let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + + // Placeholder regions need to be converted now because it may + // create new region variables, which can't be done later when + // verifying these bounds. + if t1.has_placeholders() { + t1 = tcx.fold_regions(t1, |r, _| match *r { + ty::RePlaceholder(placeholder) => { + self.constraints.placeholder_region(self.infcx, placeholder) + } + _ => r, + }); + } + + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + Some(implicit_region_bound), + param_env, + ) + .type_must_outlive(origin, t1, r2); + } + + GenericArgKind::Const(_) => { + // Consts cannot outlive one another, so we + // don't need to handle any relations here. + } + } + } + + fn verify_to_type_test( + &mut self, + generic_kind: GenericKind<'tcx>, + region: ty::Region<'tcx>, + verify_bound: VerifyBound<'tcx>, + ) -> TypeTest<'tcx> { + let lower_bound = self.to_region_vid(region); + + TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } + } + + fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { + if let ty::RePlaceholder(placeholder) = *r { + self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid() + } else { + self.universal_regions.to_region_vid(r) + } + } + + fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { + self.constraints.outlives_constraints.push(OutlivesConstraint { + locations: self.locations, + category: self.category, + span: self.span, + sub, + sup, + variance_info: ty::VarianceDiagInfo::default(), + }); + } + + fn add_type_test(&mut self, type_test: TypeTest<'tcx>) { + debug!("add_type_test(type_test={:?})", type_test); + self.constraints.type_tests.push(type_test); + } +} + +impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> { + fn push_sub_region_constraint( + &mut self, + _origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { + let b = self.to_region_vid(b); + let a = self.to_region_vid(a); + self.add_outlives(b, a); + } + + fn push_verify( + &mut self, + _origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + let type_test = self.verify_to_type_test(kind, a, bound); + self.add_type_test(type_test); + } +} |