diff options
| -rw-r--r-- | src/librustc/infer/mod.rs | 8 | ||||
| -rw-r--r-- | src/librustc/infer/outlives/env.rs | 36 | ||||
| -rw-r--r-- | src/librustc/infer/outlives/free_region_map.rs | 27 | ||||
| -rw-r--r-- | src/librustc/traits/mod.rs | 10 | ||||
| -rw-r--r-- | src/librustc_driver/test.rs | 9 | ||||
| -rw-r--r-- | src/librustc_typeck/check/dropck.rs | 18 | ||||
| -rw-r--r-- | src/librustc_typeck/check/regionck.rs | 5 | ||||
| -rw-r--r-- | src/librustc_typeck/coherence/builtin.rs | 11 | ||||
| -rw-r--r-- | src/test/compile-fail/regions-normalize-in-where-clause-list.rs | 37 |
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: ®ion::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(¶m_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, ®ion_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, ®ion_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, ®ion_scope_tree, &free_regions); + infcx.resolve_regions_and_report_errors(def_id, ®ion_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, ®ion_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, ®ion_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(¶m_env.caller_bounds); - infcx.resolve_regions_and_report_errors(impl_did, ®ion_scope_tree, &free_regions); + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.resolve_regions_and_report_errors( + impl_did, + ®ion_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() { } |
