summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/type_check/constraint_conversion.rs')
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs204
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);
+ }
+}