about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/outlives/mod.rs2
-rw-r--r--src/librustc/infer/outlives/obligations.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs140
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness.rs21
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs47
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs62
6 files changed, 175 insertions, 101 deletions
diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs
index 6aafebe79c6..93079b04669 100644
--- a/src/librustc/infer/outlives/mod.rs
+++ b/src/librustc/infer/outlives/mod.rs
@@ -13,4 +13,4 @@
 pub mod env;
 pub mod free_region_map;
 pub mod bounds;
-mod obligations;
+pub mod obligations;
diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs
index c0d530618ec..07286f1250c 100644
--- a/src/librustc/infer/outlives/obligations.rs
+++ b/src/librustc/infer/outlives/obligations.rs
@@ -250,7 +250,7 @@ impl<'cx, 'gcx, 'tcx, D> TypeOutlives<'cx, 'gcx, 'tcx, D>
 where
     D: TypeOutlivesDelegate<'tcx>,
 {
-    fn new(
+    pub fn new(
         delegate: D,
         tcx: TyCtxt<'cx, 'gcx, 'tcx>,
         region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
@@ -274,7 +274,7 @@ where
     /// - `origin`, the reason we need this constraint
     /// - `ty`, the type `T`
     /// - `region`, the region `'a`
-    fn type_must_outlive(
+    pub fn type_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         ty: Ty<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 06aaf6810fa..44f8420ca7e 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -11,64 +11,66 @@
 use borrow_check::location::LocationTable;
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
-use borrow_check::nll::type_check::Locations;
+use borrow_check::nll::type_check::{Locations, LexicalRegionConstraintData};
 use borrow_check::nll::universal_regions::UniversalRegions;
-use rustc::infer::region_constraints::Constraint;
-use rustc::infer::region_constraints::RegionConstraintData;
-use rustc::infer::region_constraints::{Verify, VerifyBound};
+use rustc::infer::{self, RegionObligation, SubregionOrigin};
+use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
+use rustc::infer::region_constraints::{Constraint, GenericKind, VerifyBound};
 use rustc::mir::{Location, Mir};
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
 use syntax::codemap::Span;
 
-crate struct ConstraintConversion<'a, 'tcx: 'a> {
+crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
     mir: &'a Mir<'tcx>,
     universal_regions: &'a UniversalRegions<'tcx>,
     location_table: &'a LocationTable,
+    region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
+    implicit_region_bound: Option<ty::Region<'tcx>>,
+    param_env: ty::ParamEnv<'tcx>,
+    locations: Locations,
     outlives_constraints: &'a mut Vec<OutlivesConstraint>,
     type_tests: &'a mut Vec<TypeTest<'tcx>>,
     all_facts: &'a mut Option<AllFacts>,
-
 }
 
-impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
+impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     crate fn new(
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
         mir: &'a Mir<'tcx>,
         universal_regions: &'a UniversalRegions<'tcx>,
         location_table: &'a LocationTable,
+        region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
+        implicit_region_bound: Option<ty::Region<'tcx>>,
+        param_env: ty::ParamEnv<'tcx>,
+        locations: Locations,
         outlives_constraints: &'a mut Vec<OutlivesConstraint>,
         type_tests: &'a mut Vec<TypeTest<'tcx>>,
         all_facts: &'a mut Option<AllFacts>,
     ) -> Self {
         Self {
+            tcx,
             mir,
             universal_regions,
             location_table,
+            region_bound_pairs,
+            implicit_region_bound,
+            param_env,
+            locations,
             outlives_constraints,
             type_tests,
             all_facts,
         }
     }
 
-    crate fn convert(
-        &mut self,
-        locations: Locations,
-        data: &RegionConstraintData<'tcx>,
-    ) {
-        debug!("generate: constraints at: {:#?}", locations);
-        let RegionConstraintData {
+    pub(super) fn convert(&mut self, data: &LexicalRegionConstraintData<'tcx>) {
+        debug!("generate: constraints at: {:#?}", self.locations);
+        let LexicalRegionConstraintData {
             constraints,
-            verifys,
-            givens,
+            region_obligations,
         } = data;
 
-        let span = self
-            .mir
-            .source_info(locations.from_location().unwrap_or(Location::START))
-            .span;
-
-        let at_location = locations.at_location().unwrap_or(Location::START);
-
-        for constraint in constraints.keys() {
+        for constraint in constraints {
             debug!("generate: constraint: {:?}", constraint);
             let (a_vid, b_vid) = match constraint {
                 Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid),
@@ -84,13 +86,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             // reverse direction, because `regioncx` talks about
             // "outlives" (`>=`) whereas the region constraints
             // talk about `<=`.
-            self.add_outlives(span, b_vid, a_vid, at_location);
+            self.add_outlives(b_vid, a_vid);
 
             // In the new analysis, all outlives relations etc
             // "take effect" at the mid point of the statement
             // that requires them, so ignore the `at_location`.
             if let Some(all_facts) = &mut self.all_facts {
-                if let Some(from_location) = locations.from_location() {
+                if let Some(from_location) = self.locations.from_location() {
                     all_facts.outlives.push((
                         b_vid,
                         a_vid,
@@ -104,36 +106,50 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             }
         }
 
-        for verify in verifys {
-            let type_test = self.verify_to_type_test(verify, span, locations);
-            self.add_type_test(type_test);
+        let ConstraintConversion {
+            tcx,
+            region_bound_pairs,
+            implicit_region_bound,
+            param_env,
+            ..
+        } = *self;
+        for r_o in region_obligations {
+            let RegionObligation {
+                sup_type,
+                sub_region,
+                cause,
+            } = r_o;
+
+            // we don't actually use this for anything.
+            let origin = infer::RelateParamBound(cause.span, sup_type);
+
+            TypeOutlives::new(
+                &mut *self,
+                tcx,
+                region_bound_pairs,
+                implicit_region_bound,
+                param_env,
+            ).type_must_outlive(origin, sup_type, sub_region);
         }
-
-        assert!(
-            givens.is_empty(),
-            "MIR type-checker does not use givens (thank goodness)"
-        );
     }
 
     fn verify_to_type_test(
         &self,
-        verify: &Verify<'tcx>,
-        span: Span,
-        locations: Locations,
+        generic_kind: GenericKind<'tcx>,
+        region: ty::Region<'tcx>,
+        bound: VerifyBound<'tcx>,
     ) -> TypeTest<'tcx> {
-        let generic_kind = verify.kind;
+        let lower_bound = self.to_region_vid(region);
 
-        let lower_bound = self.to_region_vid(verify.region);
+        let point = self.locations.at_location().unwrap_or(Location::START);
 
-        let point = locations.at_location().unwrap_or(Location::START);
-
-        let test = self.verify_bound_to_region_test(&verify.bound);
+        let test = self.verify_bound_to_region_test(&bound);
 
         TypeTest {
             generic_kind,
             lower_bound,
             point,
-            span,
+            span: self.span(),
             test,
         }
     }
@@ -168,13 +184,21 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         self.universal_regions.to_region_vid(r)
     }
 
+    fn span(&self) -> Span {
+        self
+            .mir
+            .source_info(self.locations.from_location().unwrap_or(Location::START))
+            .span
+    }
+
     fn add_outlives(
         &mut self,
-        span: Span,
         sup: ty::RegionVid,
         sub: ty::RegionVid,
-        point: Location,
     ) {
+        let span = self.span();
+        let point = self.locations.at_location().unwrap_or(Location::START);
+
         self.outlives_constraints.push(OutlivesConstraint {
             span,
             sub,
@@ -188,3 +212,27 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         self.type_tests.push(type_test);
     }
 }
+
+impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'gcx, 'tcx> {
+    fn push_sub_region_constraint(
+        &mut self,
+        _origin: SubregionOrigin<'tcx>,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) {
+        let b = self.universal_regions.to_region_vid(b);
+        let a = self.universal_regions.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);
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
index 9c854e38cc5..92a60602b79 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
@@ -10,11 +10,10 @@
 
 use borrow_check::nll::region_infer::Cause;
 use borrow_check::nll::type_check::type_op::{DropckOutlives, TypeOp};
-use borrow_check::nll::type_check::AtLocation;
+use borrow_check::nll::type_check::{AtLocation, LexicalRegionConstraintData};
 use dataflow::move_paths::{HasMoveData, MoveData};
 use dataflow::MaybeInitializedPlaces;
 use dataflow::{FlowAtLocation, FlowsAtLocation};
-use rustc::infer::region_constraints::RegionConstraintData;
 use rustc::mir::Local;
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::ty::subst::Kind;
@@ -71,7 +70,7 @@ where
 
 struct DropData<'tcx> {
     dropped_kinds: Vec<Kind<'tcx>>,
-    region_constraint_data: Option<Rc<RegionConstraintData<'tcx>>>,
+    region_constraint_data: Option<Rc<LexicalRegionConstraintData<'tcx>>>,
 }
 
 impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
@@ -198,8 +197,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
         });
 
         if let Some(data) = &drop_data.region_constraint_data {
-            self.cx
-                .push_region_constraints(location.at_self(), data.clone());
+            self.cx.push_region_constraints(location.at_self(), data);
         }
 
         // All things in the `outlives` array may be touched by
@@ -217,16 +215,9 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
         debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
 
         let param_env = cx.param_env;
-        let (dropped_kinds, region_constraint_data) =
-            DropckOutlives::new(
-                param_env,
-                dropped_ty,
-            ).fully_perform(
-                cx.infcx,
-                cx.region_bound_pairs,
-                cx.implicit_region_bound,
-                cx.param_env,
-            ).unwrap();
+        let (dropped_kinds, region_constraint_data) = DropckOutlives::new(param_env, dropped_ty)
+            .fully_perform(cx.infcx)
+            .unwrap();
 
         DropData {
             dropped_kinds,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index e2f6ad0bde3..cb16461de49 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -20,8 +20,8 @@ use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
 use dataflow::MaybeInitializedPlaces;
 use rustc::hir::def_id::DefId;
-use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
-use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, UnitResult};
+use rustc::infer::region_constraints::{Constraint, GenericKind};
+use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, RegionObligation, UnitResult};
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor};
@@ -31,7 +31,6 @@ use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
 use std::fmt;
-use std::rc::Rc;
 use syntax_pos::{Span, DUMMY_SP};
 use transform::{MirPass, MirSource};
 use util::liveness::LivenessResults;
@@ -626,6 +625,21 @@ crate struct MirTypeckRegionConstraints<'tcx> {
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
 
+/// The type checker layers on top of the "old" inference engine.  The
+/// idea is that we run some operations, like trait selection, and
+/// then we "scrape out" the region constraints that have accumulated
+/// from the old lexical solver. This struct just collects the bits of
+/// that data that we care about into one place.
+#[derive(Debug)]
+struct LexicalRegionConstraintData<'tcx> {
+    /// The `'a <= 'b` constraints extracted from `RegionConstraintData`.
+    constraints: Vec<Constraint<'tcx>>,
+
+    /// The `T: 'a` (and `'a: 'b`, in some cases) constraints
+    /// extracted from the pending "region obligations".
+    region_obligations: Vec<RegionObligation<'tcx>>,
+}
+
 /// The `Locations` type summarizes *where* region constraints are
 /// required to hold. Normally, this is at a particular point which
 /// created the obligation, but for constraints that the user gave, we
@@ -733,14 +747,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         locations: Locations,
         op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
     ) -> Result<R, TypeError<'tcx>> {
-        let (r, opt_data) = op.fully_perform(
-            self.infcx,
-            self.region_bound_pairs,
-            self.implicit_region_bound,
-            self.param_env,
-        )?;
-
-        if let Some(data) = opt_data {
+        let (r, opt_data) = op.fully_perform(self.infcx)?;
+
+        if let Some(data) = &opt_data {
             self.push_region_constraints(locations, data);
         }
 
@@ -750,7 +759,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     fn push_region_constraints(
         &mut self,
         locations: Locations,
-        data: Rc<RegionConstraintData<'tcx>>,
+        data: &LexicalRegionConstraintData<'tcx>,
     ) {
         debug!(
             "push_region_constraints: constraints generated at {:?} are {:#?}",
@@ -759,13 +768,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         if let Some(borrowck_context) = &mut self.borrowck_context {
             constraint_conversion::ConstraintConversion::new(
+                self.infcx.tcx,
                 self.mir,
                 borrowck_context.universal_regions,
                 borrowck_context.location_table,
+                self.region_bound_pairs,
+                self.implicit_region_bound,
+                self.param_env,
+                locations,
                 &mut self.constraints.outlives_constraints,
                 &mut self.constraints.type_tests,
                 &mut borrowck_context.all_facts,
-            ).convert(locations, &data);
+            ).convert(&data);
         }
     }
 
@@ -1689,3 +1703,10 @@ impl ToLocations for Location {
         self.at_self()
     }
 }
+
+impl<'tcx> LexicalRegionConstraintData<'tcx> {
+    fn is_empty(&self) -> bool {
+        let LexicalRegionConstraintData { constraints, region_obligations } = self;
+        constraints.is_empty() && region_obligations.is_empty()
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs
index c3801b4fbac..263bce8067f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs
@@ -8,16 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use borrow_check::nll::type_check::LexicalRegionConstraintData;
+use rustc::infer::region_constraints::RegionConstraintData;
 use rustc::infer::{InferCtxt, InferOk, InferResult};
-use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
 use rustc::traits::query::NoSolution;
 use rustc::traits::{Normalized, Obligation, ObligationCause, PredicateObligation, TraitEngine};
 use rustc::ty::error::TypeError;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Kind;
-use rustc::ty::{self, ParamEnv, Predicate, Ty};
-use std::rc::Rc;
+use rustc::ty::{ParamEnv, Predicate, Ty};
 use std::fmt;
+use std::rc::Rc;
 use syntax::codemap::DUMMY_SP;
 
 pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
@@ -43,10 +44,7 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
     fn fully_perform(
         self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
-        region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
-        implicit_region_bound: Option<ty::Region<'tcx>>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Result<(Self::Output, Option<Rc<RegionConstraintData<'tcx>>>), TypeError<'tcx>> {
+    ) -> Result<(Self::Output, Option<Rc<LexicalRegionConstraintData<'tcx>>>), TypeError<'tcx>> {
         let op = match self.trivial_noop() {
             Ok(r) => return Ok((r, None)),
             Err(op) => op,
@@ -68,14 +66,29 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
             );
         }
 
-        infcx.process_registered_region_obligations(
-            region_bound_pairs,
-            implicit_region_bound,
-            param_env,
-            dummy_body_id,
-        );
+        let region_obligations: Vec<_> = infcx
+            .take_registered_region_obligations()
+            .into_iter()
+            .map(|(_node_id, region_obligation)| region_obligation)
+            .collect();
+
+        let RegionConstraintData {
+            constraints,
+            verifys,
+            givens,
+        } = infcx.take_and_reset_region_constraints();
 
-        let data = infcx.take_and_reset_region_constraints();
+        // These are created when we "process" the registered region
+        // obliations, and that hasn't happened yet.
+        assert!(verifys.is_empty());
+
+        // NLL doesn't use givens (and thank goodness!).
+        assert!(givens.is_empty());
+
+        let data = LexicalRegionConstraintData {
+            constraints: constraints.keys().cloned().collect(),
+            region_obligations,
+        };
         if data.is_empty() {
             Ok((value, None))
         } else {
@@ -84,8 +97,6 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
     }
 }
 
-
-
 pub(super) struct CustomTypeOp<F, G> {
     closure: F,
     description: G,
@@ -97,7 +108,10 @@ impl<F, G> CustomTypeOp<F, G> {
         F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>,
         G: Fn() -> String,
     {
-        CustomTypeOp { closure, description }
+        CustomTypeOp {
+            closure,
+            description,
+        }
     }
 }
 
@@ -277,11 +291,11 @@ pub(super) struct DropckOutlives<'tcx> {
 }
 
 impl<'tcx> DropckOutlives<'tcx> {
-    pub(super) fn new(
-        param_env: ParamEnv<'tcx>,
-        dropped_ty: Ty<'tcx>,
-    ) -> Self {
-        DropckOutlives { param_env, dropped_ty }
+    pub(super) fn new(param_env: ParamEnv<'tcx>, dropped_ty: Ty<'tcx>) -> Self {
+        DropckOutlives {
+            param_env,
+            dropped_ty,
+        }
     }
 }
 
@@ -294,7 +308,7 @@ impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> {
 
     fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
         Ok(infcx
-           .at(&ObligationCause::dummy(), self.param_env)
-           .dropck_outlives(self.dropped_ty))
+            .at(&ObligationCause::dummy(), self.param_env)
+            .dropck_outlives(self.dropped_ty))
     }
 }