about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/mod.rs8
-rw-r--r--src/librustc/infer/outlives/env.rs36
-rw-r--r--src/librustc/infer/outlives/free_region_map.rs27
-rw-r--r--src/librustc/traits/mod.rs10
-rw-r--r--src/librustc_driver/test.rs9
-rw-r--r--src/librustc_typeck/check/dropck.rs18
-rw-r--r--src/librustc_typeck/check/regionck.rs5
-rw-r--r--src/librustc_typeck/coherence/builtin.rs11
-rw-r--r--src/test/compile-fail/regions-normalize-in-where-clause-list.rs37
9 files changed, 108 insertions, 53 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 72d8077b4c5..96a980a1545 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -44,7 +44,7 @@ use self::higher_ranked::HrMatchResult;
 use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
 use self::region_constraints::{GenericKind, VerifyBound, RegionConstraintData, VarOrigins};
 use self::lexical_region_resolve::LexicalRegionResolutions;
-use self::outlives::free_region_map::FreeRegionMap;
+use self::outlives::env::OutlivesEnvironment;
 use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
 
@@ -66,8 +66,6 @@ mod sub;
 pub mod type_variable;
 pub mod unify_key;
 
-pub use self::outlives::env::OutlivesEnvironment;
-
 #[must_use]
 pub struct InferOk<'tcx, T> {
     pub value: T,
@@ -1158,7 +1156,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn resolve_regions_and_report_errors(&self,
                                              region_context: DefId,
                                              region_map: &region::ScopeTree,
-                                             free_regions: &FreeRegionMap<'tcx>) {
+                                             outlives_env: &OutlivesEnvironment<'tcx>) {
         assert!(self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
                 "region_obligations not empty: {:#?}",
                 self.region_obligations.borrow());
@@ -1166,7 +1164,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let region_rels = &RegionRelations::new(self.tcx,
                                                 region_context,
                                                 region_map,
-                                                free_regions);
+                                                outlives_env.free_region_map());
         let (var_origins, data) = self.region_constraints.borrow_mut()
                                                          .take()
                                                          .expect("regions already resolved")
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs
index 67f19b2c50d..9f00fc78cc0 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc/infer/outlives/env.rs
@@ -44,14 +44,15 @@ pub struct OutlivesEnvironment<'tcx> {
 
 impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
     pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
-        let mut free_region_map = FreeRegionMap::new();
-        free_region_map.relate_free_regions_from_predicates(&param_env.caller_bounds);
-
-        OutlivesEnvironment {
+        let mut env = OutlivesEnvironment {
             param_env,
-            free_region_map,
+            free_region_map: FreeRegionMap::new(),
             region_bound_pairs: vec![],
-        }
+        };
+
+        env.init_free_regions_from_predicates();
+
+        env
     }
 
     /// Borrows current value of the `free_region_map`.
@@ -183,4 +184,27 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
             }
         }
     }
+
+    fn init_free_regions_from_predicates(&mut self) {
+        debug!("init_free_regions_from_predicates()");
+        for predicate in self.param_env.caller_bounds {
+            debug!("init_free_regions_from_predicates: predicate={:?}", predicate);
+            match *predicate {
+                ty::Predicate::Projection(..) |
+                ty::Predicate::Trait(..) |
+                ty::Predicate::Equate(..) |
+                ty::Predicate::Subtype(..) |
+                ty::Predicate::WellFormed(..) |
+                ty::Predicate::ObjectSafe(..) |
+                ty::Predicate::ClosureKind(..) |
+                ty::Predicate::TypeOutlives(..) |
+                ty::Predicate::ConstEvaluatable(..) => {
+                    // No region bounds here
+                }
+                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
+                    self.free_region_map.relate_regions(r_b, r_a);
+                }
+            }
+        }
+    }
 }
diff --git a/src/librustc/infer/outlives/free_region_map.rs b/src/librustc/infer/outlives/free_region_map.rs
index 1d235eb244d..36e0d6dba5e 100644
--- a/src/librustc/infer/outlives/free_region_map.rs
+++ b/src/librustc/infer/outlives/free_region_map.rs
@@ -29,31 +29,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
         self.relation.is_empty()
     }
 
-    pub fn relate_free_regions_from_predicates(&mut self,
-                                               predicates: &[ty::Predicate<'tcx>]) {
-        debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
-        for predicate in predicates {
-            match *predicate {
-                ty::Predicate::Projection(..) |
-                ty::Predicate::Trait(..) |
-                ty::Predicate::Equate(..) |
-                ty::Predicate::Subtype(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::TypeOutlives(..) |
-                ty::Predicate::ConstEvaluatable(..) => {
-                    // No region bounds here
-                }
-                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
-                    self.relate_regions(r_b, r_a);
-                }
-            }
-        }
-    }
-
-    /// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
-    /// (with the exception that `'static: 'x` is not notable)
+    // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
+    // (with the exception that `'static: 'x` is not notable)
     pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
         debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
         if is_free_or_static(sub) && is_free(sup) {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index ac08ff34518..d6f8a5f9cc6 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -17,7 +17,7 @@ pub use self::ObligationCauseCode::*;
 
 use hir;
 use hir::def_id::DefId;
-use infer::outlives::free_region_map::FreeRegionMap;
+use infer::outlives::env::OutlivesEnvironment;
 use middle::const_val::ConstEvalErr;
 use middle::region;
 use ty::subst::Substs;
@@ -554,9 +554,13 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             predicates);
 
         let region_scope_tree = region::ScopeTree::default();
-        let free_regions = FreeRegionMap::new();
 
-        infcx.resolve_regions_and_report_errors(region_context, &region_scope_tree, &free_regions);
+        // We can use the `elaborated_env` here; the region code only
+        // cares about declarations like `'a: 'b`.
+        let outlives_env = OutlivesEnvironment::new(elaborated_env);
+
+        infcx.resolve_regions_and_report_errors(region_context, &region_scope_tree, &outlives_env);
+
         let predicates = match infcx.fully_resolve(&predicates) {
             Ok(predicates) => predicates,
             Err(fixup_err) => {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 78ce959e5c9..0818b929ee7 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -17,7 +17,6 @@ use driver;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
 use rustc_trans;
-use rustc::middle::free_region::FreeRegionMap;
 use rustc::middle::region;
 use rustc::middle::resolve_lifetime;
 use rustc::ty::subst::{Kind, Subst};
@@ -25,6 +24,7 @@ use rustc::traits::{ObligationCause, Reveal};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::maps::OnDiskCache;
 use rustc::infer::{self, InferOk, InferResult};
+use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
@@ -162,14 +162,15 @@ fn test_env<F>(source_string: &str,
                              |tcx| {
         tcx.infer_ctxt().enter(|infcx| {
             let mut region_scope_tree = region::ScopeTree::default();
+            let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
             body(Env {
                 infcx: &infcx,
                 region_scope_tree: &mut region_scope_tree,
-                param_env: ty::ParamEnv::empty(Reveal::UserFacing),
+                param_env: param_env,
             });
-            let free_regions = FreeRegionMap::new();
+            let outlives_env = OutlivesEnvironment::new(param_env);
             let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
-            infcx.resolve_regions_and_report_errors(def_id, &region_scope_tree, &free_regions);
+            infcx.resolve_regions_and_report_errors(def_id, &region_scope_tree, &outlives_env);
             assert_eq!(tcx.sess.err_count(), expected_err_count);
         });
     });
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index f150c7db9b1..55700c452e5 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -12,11 +12,11 @@ use check::regionck::RegionCtxt;
 
 use hir::def_id::DefId;
 use rustc::infer::{self, InferOk};
-use rustc::infer::outlives::free_region_map::FreeRegionMap;
+use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::middle::region;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ObligationCause};
+use rustc::traits::{self, Reveal, ObligationCause};
 use util::common::ErrorReported;
 use util::nodemap::FxHashSet;
 
@@ -115,8 +115,18 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
         }
 
         let region_scope_tree = region::ScopeTree::default();
-        let free_regions = FreeRegionMap::new();
-        infcx.resolve_regions_and_report_errors(drop_impl_did, &region_scope_tree, &free_regions);
+
+        // NB. It seems a bit... suspicious to use an empty param-env
+        // here. The correct thing, I imagine, would be
+        // `OutlivesEnvironment::new(impl_param_env)`, which would
+        // allow region solving to take any `a: 'b` relations on the
+        // impl into account. But I could not create a test case where
+        // it did the wrong thing, so I chose to preserve existing
+        // behavior, since it ought to be simply more
+        // conservative. -nmatsakis
+        let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty(Reveal::UserFacing));
+
+        infcx.resolve_regions_and_report_errors(drop_impl_did, &region_scope_tree, &outlives_env);
         Ok(())
     })
 }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index b91137aeb68..7ef6027772b 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -90,7 +90,8 @@ use middle::region;
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty};
-use rustc::infer::{self, OutlivesEnvironment};
+use rustc::infer;
+use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::ty::adjustment;
 use rustc::ty::outlives::Component;
 
@@ -553,7 +554,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     fn resolve_regions_and_report_errors(&self) {
         self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
                                                    &self.region_scope_tree,
-                                                   self.outlives_environment.free_region_map());
+                                                   &self.outlives_environment);
     }
 
     fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 01d0a7a3f85..d63980eaa50 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -11,7 +11,7 @@
 //! Check properties that are required by built-in traits and set
 //! up data structures required by type-checking/translation.
 
-use rustc::infer::outlives::free_region_map::FreeRegionMap;
+use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::middle::region;
 use rustc::middle::lang_items::UnsizeTraitLangItem;
 
@@ -391,9 +391,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Finally, resolve all regions.
         let region_scope_tree = region::ScopeTree::default();
-        let mut free_regions = FreeRegionMap::new();
-        free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
-        infcx.resolve_regions_and_report_errors(impl_did, &region_scope_tree, &free_regions);
+        let outlives_env = OutlivesEnvironment::new(param_env);
+        infcx.resolve_regions_and_report_errors(
+            impl_did,
+            &region_scope_tree,
+            &outlives_env,
+        );
 
         CoerceUnsizedInfo {
             custom_kind: kind
diff --git a/src/test/compile-fail/regions-normalize-in-where-clause-list.rs b/src/test/compile-fail/regions-normalize-in-where-clause-list.rs
new file mode 100644
index 00000000000..68642598ed2
--- /dev/null
+++ b/src/test/compile-fail/regions-normalize-in-where-clause-list.rs
@@ -0,0 +1,37 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we are able to normalize in the list of where-clauses,
+// even if `'a: 'b` is required.
+
+trait Project<'a, 'b> {
+    type Item;
+}
+
+impl<'a, 'b> Project<'a, 'b> for ()
+    where 'a: 'b
+{
+    type Item = ();
+}
+
+// No error here, we have 'a: 'b. We used to report an error here
+// though, see https://github.com/rust-lang/rust/issues/45937.
+fn foo<'a: 'b, 'b>()
+    where <() as Project<'a, 'b>>::Item : Eq
+{
+}
+
+// Here we get an error: we need `'a: 'b`.
+fn bar<'a, 'b>() //~ ERROR cannot infer
+    where <() as Project<'a, 'b>>::Item : Eq
+{
+}
+
+fn main() { }