From 6c4b961effdbec1bb2fc5aaed5aeb219eb7f3b19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 May 2017 08:01:04 -0400 Subject: [PATCH 1/8] move projection mode into parameter environment --- src/librustc/infer/mod.rs | 58 +++++++------------ src/librustc/middle/intrinsicck.rs | 3 +- src/librustc/traits/mod.rs | 9 +-- src/librustc/traits/project.rs | 16 ++--- src/librustc/traits/select.rs | 2 +- src/librustc/traits/specialize/mod.rs | 4 +- .../traits/specialize/specialization_graph.rs | 2 +- src/librustc/traits/trans/mod.rs | 2 +- src/librustc/ty/maps.rs | 6 ++ src/librustc/ty/mod.rs | 14 +++-- src/librustc/ty/util.rs | 28 ++++++--- src/librustc_const_eval/check_match.rs | 3 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_lint/types.rs | 2 +- src/librustc_mir/build/mod.rs | 5 +- src/librustc_mir/transform/inline.rs | 6 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/type_check.rs | 4 +- src/librustc_passes/consts.rs | 4 +- src/librustc_trans/context.rs | 8 +-- src/librustc_trans/glue.rs | 2 +- src/librustc_typeck/check/compare_method.rs | 7 ++- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/mod.rs | 4 +- src/librustc_typeck/coherence/builtin.rs | 4 +- .../coherence/inherent_impls_overlap.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- 28 files changed, 110 insertions(+), 99 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f05f411945089..5dbf30d8fa8a4 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -174,11 +174,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // avoid reporting the same error twice. pub reported_trait_errors: RefCell>>, - // Sadly, the behavior of projection varies a bit depending on the - // stage of compilation. The specifics are given in the - // documentation for `Reveal`. - projection_mode: Reveal, - // When an error occurs, we want to avoid reporting "derived" // errors that are due to this original failure. Normally, we // handle this with the `err_count_on_creation` count, which @@ -406,15 +401,15 @@ pub trait InferEnv<'a, 'tcx> { fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>); + ty::ParamEnv<'tcx>); } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for () { +impl<'a, 'tcx> InferEnv<'a, 'tcx> for Reveal { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { - (None, None, None) + ty::ParamEnv<'tcx>) { + (None, None, ty::ParamEnv::empty(self)) } } @@ -422,8 +417,8 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { - (None, None, Some(self)) + ty::ParamEnv<'tcx>) { + (None, None, self) } } @@ -431,8 +426,8 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv< fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { - (Some(self.0), None, Some(self.1)) + ty::ParamEnv<'tcx>) { + (Some(self.0), None, self.1) } } @@ -440,8 +435,8 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { - (None, Some(self.0), Some(self.1)) + ty::ParamEnv<'tcx>) { + (None, Some(self.0), self.1) } } @@ -449,11 +444,11 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { + ty::ParamEnv<'tcx>) { let def_id = tcx.hir.body_owner_def_id(self); (Some(tcx.typeck_tables_of(def_id)), None, - Some(tcx.param_env(def_id))) + tcx.param_env(def_id)) } } @@ -465,15 +460,11 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { arena: DroplessArena, fresh_tables: Option>>, tables: Option<&'a ty::TypeckTables<'gcx>>, - param_env: Option>, - projection_mode: Reveal, + param_env: ty::ParamEnv<'gcx>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { - pub fn infer_ctxt>(self, - env: E, - projection_mode: Reveal) - -> InferCtxtBuilder<'a, 'gcx, 'tcx> { + pub fn infer_ctxt>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { let (tables, fresh_tables, param_env) = env.to_parts(self); InferCtxtBuilder { global_tcx: self, @@ -481,7 +472,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { fresh_tables: fresh_tables.map(RefCell::new), tables: tables, param_env: param_env, - projection_mode: projection_mode, } } @@ -498,12 +488,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { int_unification_table: RefCell::new(UnificationTable::new()), float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(self), - param_env: param_env.unwrap(), + param_env: param_env, selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), reported_trait_errors: RefCell::new(FxHashSet()), - projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), in_snapshot: Cell::new(false), @@ -520,13 +509,11 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { ref arena, ref fresh_tables, tables, - ref mut param_env, - projection_mode, + param_env, } = *self; let tables = tables.map(InferTables::Interned).unwrap_or_else(|| { fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress) }); - let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty()); global_tcx.enter_local(arena, |tcx| f(InferCtxt { tcx: tcx, tables: tables, @@ -539,7 +526,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), reported_trait_errors: RefCell::new(FxHashSet()), - projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), @@ -643,11 +629,15 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt((), Reveal::All).enter(|infcx| { + self.infer_ctxt(Reveal::All).enter(|infcx| { value.trans_normalize(&infcx) }) } + /// Does a best-effort to normalize any associated types in + /// `value`; this includes revealing specializable types, so this + /// should be not be used during type-checking, but only during + /// optimization and code generation. pub fn normalize_associated_type_in_env( self, value: &T, env: ty::ParamEnv<'tcx> ) -> T @@ -661,7 +651,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(env, Reveal::All).enter(|infcx| { + self.infer_ctxt(env.reveal_all()).enter(|infcx| { value.trans_normalize(&infcx) }) } @@ -728,10 +718,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn projection_mode(&self) -> Reveal { - self.projection_mode - } - pub fn is_in_snapshot(&self) -> bool { self.in_snapshot.get() } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index a759a9061f842..08f731ae34def 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -11,7 +11,6 @@ use hir::def::Def; use hir::def_id::DefId; use infer::InferCtxt; -use traits::Reveal; use ty::{self, Ty, TyCtxt}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; @@ -140,7 +139,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> { fn visit_nested_body(&mut self, body_id: hir::BodyId) { let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| { + self.tcx.infer_ctxt(body_id).enter(|infcx| { let mut visitor = ExprVisitor { infcx: &infcx }; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e358f39bd9a3a..fee6ce95a3f7f 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -477,9 +477,10 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates)); + let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), + unnormalized_env.reveal); - tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(elaborated_env).enter(|infcx| { let predicates = match fully_normalize( &infcx, cause, // You would really want to pass infcx.param_env.caller_bounds here, @@ -528,7 +529,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: resolved predicates={:?}", predicates); - ty::ParamEnv::new(tcx.intern_predicates(&predicates)) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal) }) } @@ -590,7 +591,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { + tcx.infer_ctxt(Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = FulfillmentContext::new(); let cause = ObligationCause::dummy(); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f5672ffbdc534..467783fcd7d86 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -36,7 +36,7 @@ use util::common::FN_OUTPUT_NAME; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Reveal { /// At type-checking time, we refuse to project any associated /// type that is marked `default`. Non-`default` ("final") types @@ -278,12 +278,14 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, match ty.sty { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. - if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.fold_ty(concrete_ty) - } else { - ty + match self.param_env.reveal { + Reveal::UserFacing => ty, + + Reveal::All => { + let generic_ty = self.tcx().type_of(def_id); + let concrete_ty = generic_ty.subst(self.tcx(), substs); + self.fold_ty(concrete_ty) + } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7366ed45f31bd..12f9e2f355bb9 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -324,7 +324,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } pub fn projection_mode(&self) -> Reveal { - self.infcx.projection_mode() + self.param_env().reveal } /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index e0f28e3b49e91..4d7fdbd881ec3 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -122,7 +122,7 @@ pub fn find_associated_item<'a, 'tcx>( let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { - let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| { + let substs = tcx.infer_ctxt(Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs(&infcx, impl_data.impl_def_id, substs, node_item.node); @@ -184,7 +184,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| { + let result = tcx.infer_ctxt(penv).enter(|infcx| { // Normalize the trait reference. The WF rules ought to ensure // that this always succeeds. let impl1_trait_ref = diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 87c98a0ef0ed6..aa35dfd1d70ad 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children { let possible_sibling = *slot; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + let (le, ge) = tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index e38306aed2a91..4cffe6af083b6 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - self.infer_ctxt((), Reveal::All).enter(|infcx| { + self.infer_ctxt(Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::misc(span, diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index cfb9e648d3b7e..da85d40b2c3e8 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -906,6 +906,12 @@ define_maps! { <'tcx> [] specialization_graph_of: SpecializationGraph(DefId) -> Rc, [] is_object_safe: ObjectSafety(DefId) -> bool, + // Get the ParameterEnvironment for a given item; this environment + // will be in "user-facing" mode, meaning that it is suitabe for + // type-checking etc, and it does not normalize specializable + // associated types. This is almost always what you want, + // unless you are doing MIR optimizations, in which case you + // might want to use `reveal_all()` method to change modes. [] param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b495b5ee81a9a..0a25cd638cc30 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1191,6 +1191,11 @@ pub struct ParamEnv<'tcx> { /// the set of bounds on the in-scope type parameters, translated /// into Obligations, and elaborated and normalized. pub caller_bounds: &'tcx Slice>, + + /// Typically, this is `Reveal::UserFacing`, but during trans we + /// want `Reveal::All` -- note that this is always paired with an + /// empty environment. To get that, use `ParamEnv::reveal()`. + pub reveal: traits::Reveal, } impl<'tcx> ParamEnv<'tcx> { @@ -1218,7 +1223,7 @@ impl<'tcx> ParamEnv<'tcx> { } } else { ParamEnvAnd { - param_env: ParamEnv::empty(), + param_env: ParamEnv::empty(self.reveal), value: value, } } @@ -2467,8 +2472,8 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option /// See `ParamEnv` struct def'n for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> ParamEnv<'tcx> { + def_id: DefId) + -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); @@ -2486,7 +2491,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates)); + let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), + traits::Reveal::UserFacing); let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| { tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ce0f1ed5bb86c..31c099c661df0 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -150,20 +150,32 @@ pub enum Representability { impl<'tcx> ty::ParamEnv<'tcx> { /// Construct a trait environment suitable for contexts where /// there are no where clauses in scope. - pub fn empty() -> Self { - Self::new(ty::Slice::empty()) + pub fn empty(reveal: Reveal) -> Self { + Self::new(ty::Slice::empty(), reveal) } /// Construct a trait environment with the given set of predicates. - pub fn new(caller_bounds: &'tcx ty::Slice>) -> Self { - ty::ParamEnv { caller_bounds } + pub fn new(caller_bounds: &'tcx ty::Slice>, + reveal: Reveal) + -> Self { + ty::ParamEnv { caller_bounds, reveal } + } + + /// Returns a new parameter environment with the same clauses, but + /// which "reveals" the true results of projections in all cases + /// (even for associated types that are specializable). This is + /// the desired behavior during trans and certain other special + /// contexts; normally though we want to use `Reveal::UserFacing`, + /// which is the default. + pub fn reveal_all(self) -> Self { + ty::ParamEnv { reveal: Reveal::All, ..self } } pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type: Ty<'tcx>, span: Span) -> Result<(), CopyImplementationError> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(self.clone()).enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), @@ -970,7 +982,7 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); - tcx.infer_ctxt(param_env, Reveal::UserFacing) + tcx.infer_ctxt(param_env) .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) } @@ -980,7 +992,7 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); - tcx.infer_ctxt(param_env, Reveal::UserFacing) + tcx.infer_ctxt(param_env) .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) } @@ -990,7 +1002,7 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); - tcx.infer_ctxt(param_env, Reveal::UserFacing) + tcx.infer_ctxt(param_env) .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index b35b086599165..39db384e2ded2 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -20,7 +20,6 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization::{cmt}; use rustc::middle::region::RegionMaps; use rustc::session::Session; -use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; use rustc::lint; use rustc_errors::{Diagnostic, Level, DiagnosticBuilder}; @@ -518,7 +517,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, /// /// FIXME: this should be done by borrowck. fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { - cx.tcx.infer_ctxt((cx.tables, cx.param_env), Reveal::UserFacing).enter(|infcx| { + cx.tcx.infer_ctxt((cx.tables, cx.param_env)).enter(|infcx| { let mut checker = MutationChecker { cx: cx, }; diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a6b39f22277de..1364898b549d4 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -483,7 +483,7 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), trait_ref.to_poly_trait_predicate()); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 12bfb1e02cf6f..619e7ec6a4f60 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -488,7 +488,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if def.has_dtor(cx.tcx) { return; } - let param_env = ty::ParamEnv::empty(); + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); if !ty.moves_by_default(cx.tcx, param_env, item.span) { return; } @@ -956,7 +956,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { trait_ref.to_poly_trait_predicate()); let param_env = tcx.param_env(method.def_id); - tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(param_env).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { // The method comes from a `T: Trait` bound. diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index c2181c9764c6c..1b86085d99d1b 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -725,7 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); - let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| { + let layout = cx.tcx.infer_ctxt(Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", t, e) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 407b08d283149..e9cf3115ddab1 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -18,7 +18,6 @@ use rustc::middle::region::CodeExtent; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; -use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; @@ -84,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t }; let src = MirSource::from_node(tcx, id); - tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(body_id).enter(|infcx| { let cx = Cx::new(&infcx, src); let mut mir = if cx.tables().tainted_by_errors { build::construct_error(cx, body_id) @@ -173,7 +172,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { let pe = tcx.param_env(tcx.hir.local_def_id(ctor_id)); - tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(pe).enter(|infcx| { let (mut mir, src) = shim::build_adt_ctor(&infcx, ctor_id, fields, span); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index edb2f44d18e35..8842d30b65c27 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -18,7 +18,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::*; -use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Subst,Substs}; @@ -545,9 +544,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } -fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option { - tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| { + tcx.infer_ctxt(param_env.reveal_all()).enter(|infcx| { ty.layout(&infcx).ok().map(|layout| { layout.size(&tcx.data_layout).bytes() }) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 3b1c54f68e49b..7c49a11ca1f71 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -998,7 +998,7 @@ impl MirPass for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty; - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); fulfillment_cx.register_bound(&infcx, ty, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 8258627748f30..f7055f90f0f83 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -12,7 +12,7 @@ #![allow(unreachable_code)] use rustc::infer::{self, InferCtxt, InferOk}; -use rustc::traits::{self, Reveal}; +use rustc::traits; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; @@ -752,7 +752,7 @@ impl MirPass for TypeckMir { return; } let param_env = tcx.param_env(def_id); - tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(param_env).enter(|infcx| { let mut checker = TypeChecker::new(&infcx, item_id); { let mut verifier = TypeVerifier::new(&mut checker, mir); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index fecde3a636cda..2a4a13932e3fa 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(&body.value); } - let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { + let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| { let param_env = infcx.param_env.clone(); let outer_penv = mem::replace(&mut self.param_env, param_env); let region_maps = &self.tcx.region_maps(item_def_id); @@ -468,7 +468,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { in_fn: false, promotable: false, mut_rvalue_borrows: NodeSet(), - param_env: ty::ParamEnv::empty(), + param_env: ty::ParamEnv::empty(Reveal::UserFacing), }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c3b16c2d07d07..56f51cae147ad 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -320,15 +320,15 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx, ty::ParamEnv::empty()) + ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All)) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, ty::ParamEnv::empty(), DUMMY_SP) + ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, ty::ParamEnv::empty(), DUMMY_SP) + ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { @@ -735,7 +735,7 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { return TyLayout { ty: ty, layout: layout, variant_index: None }; } - self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + self.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { infcx.layout_of(ty).unwrap_or_else(|e| { match e { ty::layout::LayoutError::SizeOverflow(_) => diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index fa400b54d2708..f473d957a9031 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -46,7 +46,7 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx> ty::TyAdt(def, _) if def.is_box() => { let typ = t.boxed_ty(); if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { - scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + scx.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { let layout = t.layout(&infcx).unwrap(); if layout.size(scx).bytes() == 0 { // `Box` does not allocate. diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 3121f4948504e..1d6d7fa61001a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -212,13 +212,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id); - let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates)); + let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), + Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause.clone()); - tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(param_env).enter(|infcx| { let inh = Inherited::new(infcx, impl_m.def_id); let infcx = &inh.infcx; @@ -713,7 +714,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 3ed0da05dc2c2..06f405120ae42 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use rustc::infer::{self, InferOk}; use rustc::middle::region::{self, RegionMaps}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::traits::{self, ObligationCause, Reveal}; +use rustc::traits::{self, ObligationCause}; use util::common::ErrorReported; use util::nodemap::FxHashSet; @@ -80,7 +80,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. let impl_param_env = tcx.param_env(self_type_did); - tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| { + tcx.infer_ctxt(impl_param_env).enter(|ref infcx| { let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 32c3f5c8a5edd..8074c0630e395 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region::CodeExtent; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; @@ -530,7 +530,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { let tables = ty::TypeckTables::empty(); let param_env = tcx.param_env(def_id); InheritedBuilder { - infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing), + infcx: tcx.infer_ctxt((tables, param_env)), def_id, } } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index ff5599fb1bdbf..89f2595d1a8fb 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -15,7 +15,7 @@ use rustc::middle::free_region::FreeRegionMap; use rustc::middle::region::RegionMaps; use rustc::middle::lang_items::UnsizeTraitLangItem; -use rustc::traits::{self, ObligationCause, Reveal}; +use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::TypeFoldable; use rustc::ty::adjustment::CoerceUnsizedInfo; @@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(param_env).enter(|infcx| { let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 2751e1ff38a50..4aa12d08f61c5 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + self.tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index baef48fe7d2cd..91dec958a161c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| { + tcx.infer_ctxt(Reveal::UserFacing).enter(|ref infcx| { let mut fulfill_cx = FulfillmentContext::new(); match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { From 541523d10dce98dc266f6d4e6fb6131182c0f791 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 19 May 2017 17:27:25 -0400 Subject: [PATCH 2/8] rewrite layout to take a (param-env, ty) pair instead of infcx --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/middle/intrinsicck.rs | 51 +++--- src/librustc/ty/layout.rs | 236 ++++++++++++++------------- src/librustc/ty/maps.rs | 15 ++ src/librustc/ty/util.rs | 52 +++--- src/librustc_lint/types.rs | 13 +- src/librustc_mir/transform/inline.rs | 6 +- src/librustc_trans/context.rs | 46 ++---- src/librustc_trans/glue.rs | 16 +- 9 files changed, 225 insertions(+), 212 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 38ad473e4042f..c38b3745f4c72 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -112,6 +112,7 @@ pub enum DepNode { IsSized(D), IsFreeze(D), NeedsDrop(D), + Layout(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -241,6 +242,7 @@ impl DepNode { IsSized(ref d) => op(d).map(IsSized), IsFreeze(ref d) => op(d).map(IsFreeze), NeedsDrop(ref d) => op(d).map(NeedsDrop), + Layout(ref d) => op(d).map(Layout), Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 08f731ae34def..57815b7f0b690 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -10,7 +10,6 @@ use hir::def::Def; use hir::def_id::DefId; -use infer::InferCtxt; use ty::{self, Ty, TyCtxt}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; @@ -30,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } -struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx> +struct ExprVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + tables: &'tcx ty::TypeckTables<'tcx>, + param_env: ty::ParamEnv<'tcx>, } /// If the type is `Option`, it will return `T`, otherwise @@ -63,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty } -impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ExprVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.type_of(def_id).sty { + let intrinsic = match self.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, _ => return false }; - intrinsic && self.infcx.tcx.item_name(def_id) == "transmute" + intrinsic && self.tcx.item_name(def_id) == "transmute" } - fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) { - let sk_from = SizeSkeleton::compute(from, self.infcx); - let sk_to = SizeSkeleton::compute(to, self.infcx); + fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { + let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env); + let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env); // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { @@ -84,11 +85,11 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { // Special-case transmutting from `typeof(function)` and // `Option` to present a clearer error. - let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); + let from = unpack_option_like(self.tcx.global_tcx(), from); match (&from.sty, sk_to) { (&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) - if size_to == Pointer.size(self.infcx) => { - struct_span_err!(self.infcx.tcx.sess, span, E0591, + if size_to == Pointer.size(self.tcx) => { + struct_span_err!(self.tcx.sess, span, E0591, "`{}` is zero-sized and can't be transmuted to `{}`", from, to) .span_note(span, "cast with `as` to a pointer instead") @@ -100,7 +101,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { } // Try to display a sensible error with as much information as possible. - let skeleton_string = |ty: Ty<'gcx>, sk| { + let skeleton_string = |ty: Ty<'tcx>, sk| { match sk { Ok(SizeSkeleton::Known(size)) => { format!("{} bits", size.bits()) @@ -119,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { } }; - struct_span_err!(self.infcx.tcx.sess, span, E0512, + struct_span_err!(self.tcx.sess, span, E0512, "transmute called with differently sized types: \ {} ({}) to {} ({})", from, skeleton_string(from, sk_from), @@ -138,32 +139,30 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> { } fn visit_nested_body(&mut self, body_id: hir::BodyId) { + let owner_def_id = self.tcx.hir.body_owner_def_id(body_id); let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id).enter(|infcx| { - let mut visitor = ExprVisitor { - infcx: &infcx - }; - visitor.visit_body(body); - }); + let param_env = self.tcx.param_env(owner_def_id); + let tables = self.tcx.typeck_tables_of(owner_def_id); + ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body); self.visit_body(body); } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { +impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } - fn visit_expr(&mut self, expr: &'gcx hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { let def = if let hir::ExprPath(ref qpath) = expr.node { - self.infcx.tables.borrow().qpath_def(qpath, expr.id) + self.tables.qpath_def(qpath, expr.id) } else { Def::Err }; match def { Def::Fn(did) if self.def_id_is_transmute(did) => { - let typ = self.infcx.tables.borrow().node_id_to_type(expr.id); - let typ = self.infcx.tcx.lift_to_global(&typ).unwrap(); + let typ = self.tables.node_id_to_type(expr.id); + let typ = self.tcx.lift_to_global(&typ).unwrap(); match typ.sty { ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => { let from = sig.inputs().skip_binder()[0]; diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1a8c74ff1f943..4dc764f6d30c2 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,9 +12,7 @@ pub use self::Integer::*; pub use self::Layout::*; pub use self::Primitive::*; -use infer::InferCtxt; use session::Session; -use traits; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; use syntax::ast::{FloatTy, IntTy, UintTy}; @@ -212,6 +210,12 @@ impl<'a> HasDataLayout for &'a TargetDataLayout { } } +impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.data_layout + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone)] pub enum Endian { @@ -457,8 +461,12 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) - -> (Integer, bool) { + fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + repr: &ReprOptions, + min: i64, + max: i64) + -> (Integer, bool) { // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there // are any negative values, the only valid unsigned representation is u64 @@ -583,10 +591,13 @@ enum StructKind { EnumVariant, } -impl<'a, 'gcx, 'tcx> Struct { - fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, - repr: &ReprOptions, kind: StructKind, - scapegoat: Ty<'gcx>) -> Result> { +impl<'a, 'tcx> Struct { + fn new(dl: &TargetDataLayout, + fields: &Vec<&'a Layout>, + repr: &ReprOptions, + kind: StructKind, + scapegoat: Ty<'tcx>) + -> Result> { if repr.packed() && repr.align > 0 { bug!("Struct cannot be packed and aligned"); } @@ -723,8 +734,8 @@ impl<'a, 'gcx, 'tcx> Struct { /// Determine whether a structure would be zero-sized, given its fields. fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) - -> Result> - where I: Iterator>> { + -> Result> + where I: Iterator>> { for field in fields { let field = field?; if field.is_unsized() || field.size(dl).bytes() > 0 { @@ -764,11 +775,11 @@ impl<'a, 'gcx, 'tcx> Struct { /// The tuple is `(path, source_path)`, /// where `path` is in memory order and `source_path` in source order. // FIXME(eddyb) track value ranges and traverse already optimized enums. - fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Result, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); - match (ty.layout(infcx)?, &ty.sty) { + fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>) + -> Result, LayoutError<'tcx>> { + match (ty.layout(tcx, param_env)?, &ty.sty) { (&Scalar { non_zero: true, .. }, _) | (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))), (&FatPointer { non_zero: true, .. }, _) => { @@ -779,7 +790,7 @@ impl<'a, 'gcx, 'tcx> Struct { (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); - match *fields[0].ty(tcx, substs).layout(infcx)? { + match *fields[0].ty(tcx, substs).layout(tcx, param_env)? { // FIXME(eddyb) also allow floating-point types here. Scalar { value: Int(_), non_zero: false } | Scalar { value: Pointer, non_zero: false } => { @@ -796,37 +807,49 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the fields of this struct is non-zero // let's recurse and find out (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { - Struct::non_zero_field_paths(infcx, def.struct_variant().fields - .iter().map(|field| { - field.ty(tcx, substs) - }), - Some(&variant.memory_index[..])) + Struct::non_zero_field_paths( + tcx, + param_env, + def.struct_variant().fields.iter().map(|field| { + field.ty(tcx, substs) + }), + Some(&variant.memory_index[..])) } // Perhaps one of the upvars of this closure is non-zero (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => { let upvar_tys = substs.upvar_tys(def, tcx); - Struct::non_zero_field_paths(infcx, upvar_tys, + Struct::non_zero_field_paths( + tcx, + param_env, + upvar_tys, Some(&variant.memory_index[..])) } // Can we use one of the fields in this tuple? (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => { - Struct::non_zero_field_paths(infcx, tys.iter().cloned(), + Struct::non_zero_field_paths( + tcx, + param_env, + tys.iter().cloned(), Some(&variant.memory_index[..])) } // Is this a fixed-size array of something non-zero // with at least one element? (_, &ty::TyArray(ety, d)) if d > 0 => { - Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None) + Struct::non_zero_field_paths( + tcx, + param_env, + Some(ety).into_iter(), + None) } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { return Ok(None); } - return Struct::non_zero_field_in_type(infcx, normalized); + return Struct::non_zero_field_in_type(tcx, param_env, normalized); } // Anything else is not a non-zero type. @@ -838,13 +861,15 @@ impl<'a, 'gcx, 'tcx> Struct { /// the given set of fields and recursing through aggregates. /// Returns Some((path, source_path)) on success. /// `path` is translated to memory order. `source_path` is not. - fn non_zero_field_paths(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - fields: I, - permutation: Option<&[u32]>) - -> Result, LayoutError<'gcx>> - where I: Iterator> { + fn non_zero_field_paths(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fields: I, + permutation: Option<&[u32]>) + -> Result, LayoutError<'tcx>> + where I: Iterator> { for (i, ty) in fields.enumerate() { - if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? { + let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?; + if let Some((mut path, mut source_path)) = r { source_path.push(i as u32); let index = if let Some(p) = permutation { p[i] as usize @@ -881,7 +906,7 @@ pub struct Union { pub packed: bool, } -impl<'a, 'gcx, 'tcx> Union { +impl<'a, 'tcx> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union { let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { @@ -895,9 +920,9 @@ impl<'a, 'gcx, 'tcx> Union { /// Extend the Struct with more fields. fn extend(&mut self, dl: &TargetDataLayout, fields: I, - scapegoat: Ty<'gcx>) - -> Result<(), LayoutError<'gcx>> - where I: Iterator>> { + scapegoat: Ty<'tcx>) + -> Result<(), LayoutError<'tcx>> + where I: Iterator>> { for (index, field) in fields.enumerate() { let field = field?; if field.is_unsized() { @@ -1067,19 +1092,19 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -impl<'a, 'gcx, 'tcx> Layout { - pub fn compute_uncached(ty: Ty<'gcx>, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<&'gcx Layout, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); +impl<'a, 'tcx> Layout { + pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>) + -> Result<&'tcx Layout, LayoutError<'tcx>> { let success = |layout| Ok(tcx.intern_layout(layout)); let dl = &tcx.data_layout; assert!(!ty.has_infer_types()); - let ptr_layout = |pointee: Ty<'gcx>| { + let ptr_layout = |pointee: Ty<'tcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = infcx.normalize_projections(pointee); - if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) { + let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); + if pointee.is_sized(tcx, param_env, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { let unsized_part = tcx.struct_tail(pointee); @@ -1132,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout { // Arrays and slices. ty::TyArray(element, count) => { - let element = element.layout(infcx)?; + let element = element.layout(tcx, param_env)?; let element_size = element.size(dl); // FIXME(eddyb) Don't use host `usize` for array lengths. let usize_count: usize = count; @@ -1149,7 +1174,7 @@ impl<'a, 'gcx, 'tcx> Layout { } } ty::TySlice(element) => { - let element = element.layout(infcx)?; + let element = element.layout(tcx, param_env)?; Array { sized: false, align: element.align(dl), @@ -1187,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout { ty::TyClosure(def_id, ref substs) => { let tys = substs.upvar_tys(def_id, tcx); let st = Struct::new(dl, - &tys.map(|ty| ty.layout(infcx)) + &tys.map(|ty| ty.layout(tcx, param_env)) .collect::, _>>()?, &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; @@ -1198,7 +1223,7 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked. // See the univariant case below to learn how. let st = Struct::new(dl, - &tys.iter().map(|ty| ty.layout(infcx)) + &tys.iter().map(|ty| ty.layout(tcx, param_env)) .collect::, _>>()?, &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; Univariant { variant: st, non_zero: false } @@ -1207,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> Layout { // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { let element = ty.simd_type(tcx); - match *element.layout(infcx)? { + match *element.layout(tcx, param_env)? { Scalar { value, .. } => { return success(Vector { element: value, @@ -1278,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> Layout { }; let fields = def.variants[0].fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + field.ty(tcx, substs).layout(tcx, param_env) }).collect::, _>>()?; let layout = if def.is_union() { let mut un = Union::new(dl, def.repr.packed()); @@ -1312,20 +1337,21 @@ impl<'a, 'gcx, 'tcx> Layout { // Nullable pointer optimization for discr in 0..2 { let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) + ty.layout(tcx, param_env) }); if !Struct::would_be_zero_sized(dl, other_fields)? { continue; } - let paths = Struct::non_zero_field_paths(infcx, - variants[discr].iter().cloned(), - None)?; + let paths = Struct::non_zero_field_paths(tcx, + param_env, + variants[discr].iter().cloned(), + None)?; let (mut path, mut path_source) = if let Some(p) = paths { p } else { continue }; // FIXME(eddyb) should take advantage of a newtype. if path == &[0] && variants[discr].len() == 1 { - let value = match *variants[discr][0].layout(infcx)? { + let value = match *variants[discr][0].layout(tcx, param_env)? { Scalar { value, .. } => value, CEnum { discr, .. } => Int(discr), _ => bug!("Layout::compute: `{}`'s non-zero \ @@ -1339,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> Layout { } let st = Struct::new(dl, - &variants[discr].iter().map(|ty| ty.layout(infcx)) + &variants[discr].iter().map(|ty| ty.layout(tcx, param_env)) .collect::, _>>()?, &def.repr, StructKind::AlwaysSizedUnivariant, ty)?; @@ -1377,7 +1403,7 @@ impl<'a, 'gcx, 'tcx> Layout { let discr = Scalar { value: Int(min_ity), non_zero: false }; let mut variants = variants.into_iter().map(|fields| { let mut fields = fields.into_iter().map(|field| { - field.layout(infcx) + field.layout(tcx, param_env) }).collect::, _>>()?; fields.insert(0, &discr); let st = Struct::new(dl, @@ -1470,11 +1496,11 @@ impl<'a, 'gcx, 'tcx> Layout { // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { return Err(LayoutError::Unknown(ty)); } - return normalized.layout(infcx); + return normalized.layout(tcx, param_env); } ty::TyParam(_) => { return Err(LayoutError::Unknown(ty)); @@ -1686,21 +1712,22 @@ pub enum SizeSkeleton<'tcx> { } } -impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { - pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); +impl<'a, 'tcx> SizeSkeleton<'tcx> { + pub fn compute(ty: Ty<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Result, LayoutError<'tcx>> { assert!(!ty.has_infer_types()); // First try computing a static layout. - let err = match ty.layout(infcx) { + let err = match ty.layout(tcx, param_env) { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size(tcx))); } Err(err) => err }; - let ptr_skeleton = |pointee: Ty<'gcx>| { + let ptr_skeleton = |pointee: Ty<'tcx>| { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail(pointee); match tail.sty { @@ -1737,7 +1764,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { // Get a zero-sized variant or a pointer newtype. let zero_or_ptr_variant = |i: usize| { let fields = def.variants[i].fields.iter().map(|field| { - SizeSkeleton::compute(field.ty(tcx, substs), infcx) + SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env) }); let mut ptr = None; for field in fields { @@ -1788,11 +1815,11 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { Err(err) } else { - SizeSkeleton::compute(normalized, infcx) + SizeSkeleton::compute(normalized, tcx, param_env) } } @@ -1826,71 +1853,53 @@ impl<'tcx> Deref for TyLayout<'tcx> { } } -pub trait HasTyCtxt<'tcx>: HasDataLayout { +pub trait LayoutTyper<'tcx>: HasDataLayout { + type TyLayout; + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; } -impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { - fn data_layout(&self) -> &TargetDataLayout { - &self.data_layout - } +/// Combines a tcx with the parameter environment so that you can +/// compute layout operations. +#[derive(Copy, Clone)] +pub struct LayoutCx<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, } -impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { - self.global_tcx() +impl<'a, 'tcx> LayoutCx<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + LayoutCx { tcx, param_env } } } -impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> { fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout } } -impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { - self.tcx.global_tcx() - } -} - -pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { - type TyLayout; - - fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; - fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; -} +impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> { + type TyLayout = Result, LayoutError<'tcx>>; -impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { - type TyLayout = Result, LayoutError<'gcx>>; + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } - fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { let ty = self.normalize_projections(ty); Ok(TyLayout { ty: ty, - layout: ty.layout(self)?, + layout: ty.layout(self.tcx, self.param_env)?, variant_index: None }) } - fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(self); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self, obligation); - } - - self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx.normalize_associated_type_in_env(&ty, self.param_env) } } @@ -1943,7 +1952,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } - pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { + pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { let tcx = cx.tcx(); let ptr_field_type = |pointee: Ty<'tcx>| { @@ -2014,7 +2023,10 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } - pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { + pub fn field>(&self, + cx: C, + i: usize) + -> C::TyLayout { cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index da85d40b2c3e8..b5adcc8ed757d 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; use traits::specialization_graph; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::layout::{Layout, LayoutError}; use ty::item_path; use ty::steal::Steal; use ty::subst::Substs; @@ -293,6 +294,12 @@ impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> { } } +impl<'tcx> QueryDescription for queries::layout_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing layout of `{}`", env.value) + } +} + impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", @@ -920,6 +927,8 @@ define_maps! { <'tcx> [] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx Layout, LayoutError<'tcx>>, } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -987,3 +996,9 @@ fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { + let def_id = ty::item_path::characteristic_def_id_of_type(key.value) + .unwrap_or(DefId::local(CRATE_DEF_INDEX)); + DepNode::Layout(def_id) +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 31c099c661df0..6d55f04e86aaa 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -12,7 +12,6 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; -use infer::InferCtxt; use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -791,35 +790,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx.needs_drop_raw(param_env.and(self)) } + /// Computes the layout of a type. Note that this implicitly + /// executes in "reveal all" mode. #[inline] - pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) + pub fn layout<'lcx>(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { - let tcx = infcx.tcx.global_tcx(); - let can_cache = !self.has_param_types() && !self.has_self_ty(); - if can_cache { - if let Some(&cached) = tcx.layout_cache.borrow().get(&self) { - return Ok(cached); - } - } - - let rec_limit = tcx.sess.recursion_limit.get(); - let depth = tcx.layout_depth.get(); - if depth > rec_limit { - tcx.sess.fatal( - &format!("overflow representing the type `{}`", self)); - } - - tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(self, infcx); - tcx.layout_depth.set(depth); - let layout = layout?; - if can_cache { - tcx.layout_cache.borrow_mut().insert(self, layout); - } - Ok(layout) + let ty = tcx.erase_regions(&self); + tcx.layout_raw(param_env.reveal_all().and(ty)) } - /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. pub fn is_representable(&'tcx self, @@ -1074,6 +1055,24 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx Layout, LayoutError<'tcx>> +{ + let (param_env, ty) = query.into_parts(); + + let rec_limit = tcx.sess.recursion_limit.get(); + let depth = tcx.layout_depth.get(); + if depth > rec_limit { + tcx.sess.fatal( + &format!("overflow representing the type `{}`", ty)); + } + + tcx.layout_depth.set(depth+1); + let layout = Layout::compute_uncached(tcx, param_env, ty); + tcx.layout_depth.set(depth); + layout +} pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { @@ -1081,6 +1080,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { is_sized_raw, is_freeze_raw, needs_drop_raw, + layout_raw, ..*providers }; } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1b86085d99d1b..3019165bfbf9a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{Layout, Primitive}; -use rustc::traits::Reveal; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; use util::nodemap::FxHashSet; @@ -724,12 +723,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); - let layout = cx.tcx.infer_ctxt(Reveal::All).enter(|infcx| { - let ty = cx.tcx.erase_regions(&t); - ty.layout(&infcx).unwrap_or_else(|e| { - bug!("failed to get layout for `{}`: {}", t, e) - }) + let item_def_id = cx.tcx.hir.local_def_id(it.id); + let t = cx.tcx.type_of(item_def_id); + let param_env = cx.tcx.param_env(item_def_id).reveal_all(); + let ty = cx.tcx.erase_regions(&t); + let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| { + bug!("failed to get layout for `{}`: {}", t, e) }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 8842d30b65c27..0ac35a5fdd472 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -547,10 +547,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option { - tcx.infer_ctxt(param_env.reveal_all()).enter(|infcx| { - ty.layout(&infcx).ok().map(|layout| { - layout.size(&tcx.data_layout).bytes() - }) + ty.layout(tcx, param_env).ok().map(|layout| { + layout.size(&tcx.data_layout).bytes() }) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 56f51cae147ad..1a13c8e6f3def 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -25,10 +25,10 @@ use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::{LayoutTyper, TyLayout}; -use rustc::session::config::{self, NoDebugInfo}; -use rustc::session::Session; -use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; +use session::config::{self, NoDebugInfo}; +use session::Session; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -709,41 +709,27 @@ impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> { } } -impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.tcx - } -} - impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> { fn data_layout(&self) -> &ty::layout::TargetDataLayout { &self.shared.tcx.data_layout } } -impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.shared.tcx - } -} - impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; - fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { - return TyLayout { ty: ty, layout: layout, variant_index: None }; - } + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } - self.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { - infcx.layout_of(ty).unwrap_or_else(|e| { - match e { - ty::layout::LayoutError::SizeOverflow(_) => - self.sess().fatal(&e.to_string()), - _ => bug!("failed to get layout for `{}`: {}", ty, e) - } + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + LayoutCx::new(self.tcx, param_env) + .layout_of(ty) + .unwrap_or_else(|e| match e { + LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) }) - }) } fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -754,6 +740,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.shared.tcx + } + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { self.shared.layout_of(ty) } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index f473d957a9031..367f0398fa838 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -46,15 +46,13 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx> ty::TyAdt(def, _) if def.is_box() => { let typ = t.boxed_ty(); if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { - scx.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { - let layout = t.layout(&infcx).unwrap(); - if layout.size(scx).bytes() == 0 { - // `Box` does not allocate. - false - } else { - true - } - }) + let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap(); + if layout.size(scx).bytes() == 0 { + // `Box` does not allocate. + false + } else { + true + } } else { true } From 5fb0f0dc2e7f50b12272e274b084c16b048510db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 May 2017 04:19:47 -0400 Subject: [PATCH 3/8] strip param-env from infcx --- src/librustc/infer/combine.rs | 2 + src/librustc/infer/mod.rs | 186 ++++++++++-------- src/librustc/infer/sub.rs | 1 + src/librustc/lib.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 28 ++- src/librustc/traits/coherence.rs | 45 ++++- src/librustc/traits/error_reporting.rs | 19 +- src/librustc/traits/fulfill.rs | 18 +- src/librustc/traits/mod.rs | 77 ++++---- src/librustc/traits/project.rs | 52 +++-- src/librustc/traits/select.rs | 116 +++++++---- src/librustc/traits/specialize/mod.rs | 34 ++-- .../traits/specialize/specialization_graph.rs | 4 +- src/librustc/traits/structural_impls.rs | 1 + src/librustc/traits/trans/mod.rs | 4 +- src/librustc/traits/util.rs | 24 ++- src/librustc/ty/context.rs | 31 +++ src/librustc/ty/mod.rs | 23 --- src/librustc/ty/structural_impls.rs | 25 +++ src/librustc/ty/util.rs | 35 ++-- src/librustc/ty/wf.rs | 37 +++- src/librustc_borrowck/borrowck/check_loans.rs | 8 +- .../borrowck/gather_loans/mod.rs | 7 +- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 4 +- src/librustc_const_eval/eval.rs | 4 +- src/librustc_lint/builtin.rs | 5 +- src/librustc_mir/build/mod.rs | 3 +- src/librustc_mir/hair/cx/mod.rs | 12 +- src/librustc_mir/transform/qualify_consts.rs | 7 +- src/librustc_mir/transform/type_check.rs | 21 +- src/librustc_passes/consts.rs | 4 +- src/librustc_trans/context.rs | 6 +- src/librustc_typeck/check/autoderef.rs | 5 +- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/closure.rs | 6 +- src/librustc_typeck/check/coercion.rs | 23 ++- src/librustc_typeck/check/compare_method.rs | 39 ++-- src/librustc_typeck/check/demand.rs | 4 +- src/librustc_typeck/check/dropck.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 13 +- src/librustc_typeck/check/method/probe.rs | 13 +- src/librustc_typeck/check/method/suggest.rs | 5 +- src/librustc_typeck/check/mod.rs | 57 ++++-- src/librustc_typeck/check/op.rs | 12 +- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/check/upvar.rs | 2 + src/librustc_typeck/check/wfcheck.rs | 14 +- src/librustc_typeck/coherence/builtin.rs | 14 +- .../coherence/inherent_impls_overlap.rs | 4 +- src/librustc_typeck/lib.rs | 5 +- 52 files changed, 694 insertions(+), 383 deletions(-) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index aabb6aff55140..14920b8b668ec 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -55,6 +55,7 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>, pub trace: TypeTrace<'tcx>, pub cause: Option, + pub param_env: ty::ParamEnv<'tcx>, pub obligations: PredicateObligations<'tcx>, } @@ -215,6 +216,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { if needs_wf { self.obligations.push(Obligation::new(self.trace.cause.clone(), + self.param_env, ty::Predicate::WellFormed(b_ty))); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 5dbf30d8fa8a4..a16f7fb208175 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -161,8 +161,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // For region variables. region_vars: RegionVarBindings<'a, 'gcx, 'tcx>, - pub param_env: ty::ParamEnv<'gcx>, - /// Caches the results of trait selection. This cache is used /// for things that have to do with the parameters in scope. pub selection_cache: traits::SelectionCache<'tcx>, @@ -400,55 +398,39 @@ impl fmt::Display for FixupError { pub trait InferEnv<'a, 'tcx> { fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>); -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for Reveal { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>) { - (None, None, ty::ParamEnv::empty(self)) - } + Option>); } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> { +impl<'a, 'tcx> InferEnv<'a, 'tcx> for () { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>) { - (None, None, self) + Option>) { + (None, None) } } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) { +impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>) { - (Some(self.0), None, self.1) + Option>) { + (Some(self), None) } } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) { +impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>) { - (None, Some(self.0), self.1) + Option>) { + (None, Some(self)) } } impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>, - ty::ParamEnv<'tcx>) { + Option>) { let def_id = tcx.hir.body_owner_def_id(self); - (Some(tcx.typeck_tables_of(def_id)), - None, - tcx.param_env(def_id)) + (Some(tcx.typeck_tables_of(def_id)), None) } } @@ -460,18 +442,16 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { arena: DroplessArena, fresh_tables: Option>>, tables: Option<&'a ty::TypeckTables<'gcx>>, - param_env: ty::ParamEnv<'gcx>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { pub fn infer_ctxt>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { - let (tables, fresh_tables, param_env) = env.to_parts(self); + let (tables, fresh_tables) = env.to_parts(self); InferCtxtBuilder { global_tcx: self, arena: DroplessArena::new(), fresh_tables: fresh_tables.map(RefCell::new), tables: tables, - param_env: param_env, } } @@ -480,7 +460,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { /// If any inference functionality is used, ICEs will occur. pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId) -> InferCtxt<'a, 'gcx, 'gcx> { - let (tables, _, param_env) = body.to_parts(self); + let (tables, _) = body.to_parts(self); InferCtxt { tcx: self, tables: InferTables::Interned(tables.unwrap()), @@ -488,7 +468,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { int_unification_table: RefCell::new(UnificationTable::new()), float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(self), - param_env: param_env, selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), @@ -509,7 +488,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { ref arena, ref fresh_tables, tables, - param_env, } = *self; let tables = tables.map(InferTables::Interned).unwrap_or_else(|| { fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress) @@ -522,7 +500,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { int_unification_table: RefCell::new(UnificationTable::new()), float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(tcx), - param_env: param_env, selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), reported_trait_errors: RefCell::new(FxHashSet()), @@ -563,7 +540,10 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> { /// Helper trait for shortening the lifetimes inside a /// value for post-type-checking normalization. pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> { - fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self; + fn trans_normalize<'a, 'tcx>(&self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Self; } macro_rules! items { ($($item:item)+) => ($($item)+) } @@ -571,9 +551,10 @@ macro_rules! impl_trans_normalize { ($lt_gcx:tt, $($ty:ty),+) => { items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty { fn trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>) + infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) -> Self { - infcx.normalize_projections_in(self) + infcx.normalize_projections_in(param_env, self) } })+); } @@ -590,13 +571,16 @@ impl_trans_normalize!('gcx, ); impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> { - fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn trans_normalize<'a, 'tcx>(&self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Self { match *self { - LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx) }, + LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx, param_env) }, LvalueTy::Downcast { adt_def, substs, variant_index } => { LvalueTy::Downcast { adt_def: adt_def, - substs: substs.trans_normalize(infcx), + substs: substs.trans_normalize(infcx, param_env), variant_index: variant_index } } @@ -618,19 +602,23 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self.normalize_associated_type(&value) } + /// Fully normalizes any associated types in `value`, using an + /// empty environment and `Reveal::All` mode (therefore, suitable + /// only for monomorphized code during trans, basically). pub fn normalize_associated_type(self, value: &T) -> T where T: TransNormalize<'tcx> { debug!("normalize_associated_type(t={:?})", value); + let param_env = ty::ParamEnv::empty(Reveal::All); let value = self.erase_regions(value); if !value.has_projection_types() { return value; } - self.infer_ctxt(Reveal::All).enter(|infcx| { - value.trans_normalize(&infcx) + self.infer_ctxt(()).enter(|infcx| { + value.trans_normalize(&infcx, param_env) }) } @@ -651,20 +639,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(env.reveal_all()).enter(|infcx| { - value.trans_normalize(&infcx) + self.infer_ctxt(()).enter(|infcx| { + value.trans_normalize(&infcx, env.reveal_all()) }) } } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn normalize_projections_in(&self, value: &T) -> T::Lifted + fn normalize_projections_in(&self, param_env: ty::ParamEnv<'tcx>, value: &T) -> T::Lifted where T: TypeFoldable<'tcx> + ty::Lift<'gcx> { let mut selcx = traits::SelectionContext::new(self); let cause = traits::ObligationCause::dummy(); let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, value); + traits::normalize(&mut selcx, param_env, cause, value); debug!("normalize_projections_in: result={:?} obligations={:?}", result, obligations); @@ -803,48 +791,69 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return variables; } - fn combine_fields(&'a self, trace: TypeTrace<'tcx>) + fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, trace: trace, cause: None, + param_env, obligations: PredicateObligations::new(), } } - pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) + pub fn equate(&'a self, + a_is_expected: bool, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: &T, + b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut fields = self.combine_fields(trace); + let mut fields = self.combine_fields(trace, param_env); let result = fields.equate(a_is_expected).relate(a, b); result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) + pub fn sub(&'a self, + a_is_expected: bool, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: &T, + b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut fields = self.combine_fields(trace); + let mut fields = self.combine_fields(trace, param_env); let result = fields.sub(a_is_expected).relate(a, b); result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) + pub fn lub(&'a self, + a_is_expected: bool, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: &T, + b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut fields = self.combine_fields(trace); + let mut fields = self.combine_fields(trace, param_env); let result = fields.lub(a_is_expected).relate(a, b); result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) + pub fn glb(&'a self, + a_is_expected: bool, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: &T, + b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut fields = self.combine_fields(trace); + let mut fields = self.combine_fields(trace, param_env); let result = fields.glb(a_is_expected).relate(a, b); result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } @@ -1011,18 +1020,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_types(&self, a_is_expected: bool, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> InferResult<'tcx, ()> + -> InferResult<'tcx, ()> { debug!("sub_types({:?} <: {:?})", a, b); self.commit_if_ok(|_| { let trace = TypeTrace::types(cause, a_is_expected, a, b); - self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) + self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) }) } pub fn can_sub_types(&self, + param_env: ty::ParamEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> UnitResult<'tcx> @@ -1030,7 +1041,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| { + self.sub(true, trace, param_env, &a, &b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) @@ -1040,21 +1051,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn eq_types(&self, a_is_expected: bool, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { let trace = TypeTrace::types(cause, a_is_expected, a, b); - self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) + self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) }) } pub fn eq_trait_refs(&self, - a_is_expected: bool, - cause: &ObligationCause<'tcx>, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>) + a_is_expected: bool, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>) -> InferResult<'tcx, ()> { debug!("eq_trait_refs({:?} = {:?})", a, b); @@ -1063,21 +1076,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cause: cause.clone(), values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; - self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) + self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) }) } pub fn eq_impl_headers(&self, a_is_expected: bool, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: &ty::ImplHeader<'tcx>, b: &ty::ImplHeader<'tcx>) -> InferResult<'tcx, ()> { debug!("eq_impl_header({:?} = {:?})", a, b); match (a.trait_ref, b.trait_ref) { - (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref), - (None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty), + (Some(a_ref), Some(b_ref)) => + self.eq_trait_refs(a_is_expected, cause, param_env, a_ref, b_ref), + (None, None) => + self.eq_types(a_is_expected, cause, param_env, a.self_ty, b.self_ty), _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), } } @@ -1085,6 +1101,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_poly_trait_refs(&self, a_is_expected: bool, cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) -> InferResult<'tcx, ()> @@ -1095,7 +1112,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cause: cause, values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) }; - self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit()) + self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) }) } @@ -1109,6 +1126,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn equality_predicate(&self, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, predicate: &ty::PolyEquatePredicate<'tcx>) -> InferResult<'tcx, ()> { @@ -1116,7 +1134,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let cause_span = cause.span; - let eqty_ok = self.eq_types(false, cause, a, b)?; + let eqty_ok = self.eq_types(false, cause, param_env, a, b)?; self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(eqty_ok.unit()) @@ -1125,6 +1143,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn subtype_predicate(&self, cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, predicate: &ty::PolySubtypePredicate<'tcx>) -> Option> { @@ -1153,7 +1172,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.skolemize_late_bound_regions(predicate, snapshot); let cause_span = cause.span; - let ok = self.sub_types(a_is_expected, cause, a, b)?; + let ok = self.sub_types(a_is_expected, cause, param_env, a, b)?; self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(ok.unit()) @@ -1555,6 +1574,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// details. pub fn match_poly_projection_predicate(&self, cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, match_a: ty::PolyProjectionPredicate<'tcx>, match_b: ty::TraitRef<'tcx>) -> InferResult<'tcx, HrMatchResult>> @@ -1567,7 +1587,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty)); - let mut combine = self.combine_fields(trace); + let mut combine = self.combine_fields(trace, param_env); let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; Ok(InferOk { value: result, obligations: combine.obligations }) } @@ -1586,7 +1606,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bound); } - pub fn can_equate(&self, a: &T, b: &T) -> UnitResult<'tcx> + pub fn can_equate(&self, param_env: ty::ParamEnv<'tcx>, a: &T, b: &T) -> UnitResult<'tcx> where T: Relate<'tcx> + fmt::Debug { debug!("can_equate({:?}, {:?})", a, b); @@ -1596,7 +1616,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // generic so we don't have to do anything quite this // terrible. let trace = TypeTrace::dummy(self.tcx); - self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| { + self.equate(true, trace, param_env, a, b).map(|InferOk { obligations: _, .. }| { // We can intentionally ignore obligations here, since // this is part of a simple test for general // "equatability". However, it's not entirely clear @@ -1617,9 +1637,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.resolve_type_vars_or_error(&ty) } - pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { + pub fn type_moves_by_default(&self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span) + -> bool { let ty = self.resolve_type_vars_if_possible(&ty); - if let Some(ty) = self.tcx.lift_to_global(&ty) { + if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { // Even if the type may have no inference variables, during // type-checking closure types are in local tables only. let local_closures = match self.tables { @@ -1627,7 +1651,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => false }; if !local_closures { - return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span); + return ty.moves_by_default(self.tcx.global_tcx(), param_env, span); } } @@ -1637,17 +1661,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - !traits::type_known_to_meet_bound(self, ty, copy_def_id, span) + !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span) } pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } - pub fn param_env(&self) -> ty::ParamEnv<'gcx> { - self.param_env - } - pub fn closure_kind(&self, def_id: DefId) -> Option diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 487195fdfae9f..4056999681352 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -96,6 +96,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> self.fields.obligations.push( Obligation::new( self.fields.trace.cause.clone(), + self.fields.param_env, ty::Predicate::Subtype( ty::Binder(ty::SubtypePredicate { a_is_expected: self.a_is_expected, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2a877aca53b7c..2216103636fb6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -47,7 +47,7 @@ #![cfg_attr(stage0, feature(staged_api))] #![cfg_attr(stage0, feature(loop_break_value))] -#![recursion_limit="192"] +#![recursion_limit="256"] extern crate arena; extern crate core; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index bb56439a157fe..7ab534605c251 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -242,6 +242,7 @@ impl OverloadedCallType { pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, delegate: &'a mut Delegate<'tcx>, + param_env: ty::ParamEnv<'tcx>, } // If the TYPER results in an error, it's because the type check @@ -266,24 +267,28 @@ macro_rules! return_if_err { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), region_maps: &'a RegionMaps, - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) -> Self { ExprUseVisitor::with_options(delegate, infcx, + param_env, region_maps, mc::MemCategorizationOptions::default()) } pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, region_maps: &'a RegionMaps, options: mc::MemCategorizationOptions) -> Self { ExprUseVisitor { mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options), - delegate: delegate + delegate, + param_env, } } @@ -318,7 +323,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("delegate_consume(consume_id={}, cmt={:?})", consume_id, cmt); - let mode = copy_or_move(self.mc.infcx, &cmt, DirectRefMove); + let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove); self.delegate.consume(consume_id, consume_span, cmt, mode); } @@ -797,7 +802,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { PatKind::Binding(hir::BindByRef(..), ..) => mode.lub(BorrowingMatch), PatKind::Binding(hir::BindByValue(..), ..) => { - match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) { + match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) { Copy => mode.lub(CopyingMatch), Move(..) => mode.lub(MovingMatch), } @@ -813,10 +818,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); - let tcx = &self.tcx(); - let mc = &self.mc; + let tcx = self.tcx(); let infcx = self.mc.infcx; - let delegate = &mut self.delegate; + let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { if let PatKind::Binding(bmode, def_id, ..) = pat.node { debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); @@ -840,7 +844,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } hir::BindByValue(..) => { - let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove); + let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove); debug!("walk_pat binding consuming pat"); delegate.consume_pat(pat, cmt_pat, mode); } @@ -899,7 +903,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { freevar.def)); match upvar_capture { ty::UpvarCapture::ByValue => { - let mode = copy_or_move(self.mc.infcx, &cmt_var, CaptureMove); + let mode = copy_or_move(self.mc.infcx, + self.param_env, + &cmt_var, + CaptureMove); self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { @@ -929,11 +936,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, cmt: &mc::cmt<'tcx>, move_reason: MoveReason) -> ConsumeMode { - if infcx.type_moves_by_default(cmt.ty, cmt.span) { + if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) { Move(move_reason) } else { Copy diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index a943ef30e534b..c7d069053e9d0 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -10,10 +10,11 @@ //! See `README.md` for high-level documentation -use super::{SelectionContext, Obligation, ObligationCause}; - use hir::def_id::{DefId, LOCAL_CRATE}; +use syntax_pos::DUMMY_SP; +use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal}; use ty::{self, Ty, TyCtxt}; +use ty::subst::Subst; use infer::{InferCtxt, InferOk}; @@ -37,6 +38,28 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>, overlap(selcx, impl1_def_id, impl2_def_id) } +fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: DefId) + -> ty::ImplHeader<'tcx> +{ + let tcx = selcx.tcx(); + let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); + + let header = ty::ImplHeader { + impl_def_id: impl_def_id, + self_ty: tcx.type_of(impl_def_id), + trait_ref: tcx.impl_trait_ref(impl_def_id), + predicates: tcx.predicates_of(impl_def_id).predicates + }.subst(tcx, impl_substs); + + let Normalized { value: mut header, obligations } = + traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); + + header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); + header +} + /// Can both impl `a` and impl `b` be satisfied by a common type (including /// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls. fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, @@ -48,17 +71,24 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, a_def_id, b_def_id); - let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id); - let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id); + // For the purposes of this check, we don't bring any skolemized + // types into scope; instead, we replace the generic types with + // fresh type variables, and hence we do our evaluations in an + // empty environment. + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + + let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); + let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); debug!("overlap: a_impl_header={:?}", a_impl_header); debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. let obligations = match selcx.infcx().eq_impl_headers(true, - &ObligationCause::dummy(), - &a_impl_header, - &b_impl_header) { + &ObligationCause::dummy(), + param_env, + &a_impl_header, + &b_impl_header) { Ok(InferOk { obligations, .. }) => { obligations } @@ -75,6 +105,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, .chain(&b_impl_header.predicates) .map(|p| infcx.resolve_type_vars_if_possible(p)) .map(|p| Obligation { cause: ObligationCause::dummy(), + param_env: param_env, recursion_depth: 0, predicate: p }) .chain(obligations) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3c7761c6cd3bc..6635a1f1f271e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -179,12 +179,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { data); let normalized = super::normalize_projection_type( &mut selcx, + obligation.param_env, data.projection_ty, obligation.cause.clone(), 0 ); if let Err(error) = self.eq_types( - false, &obligation.cause, + false, &obligation.cause, obligation.param_env, data.ty, normalized.value ) { values = Some(infer::ValuePairs::Types(ExpectedFound { @@ -251,7 +252,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> Option { let tcx = self.tcx; - + let param_env = obligation.param_env; let trait_ref = tcx.erase_late_bound_regions(&trait_ref); let trait_self_ty = trait_ref.self_ty(); @@ -268,7 +269,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let impl_self_ty = impl_trait_ref.self_ty(); - if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) { + if let Ok(..) = self.can_equate(param_env, &trait_self_ty, &impl_self_ty) { self_match_impls.push(def_id); if trait_ref.substs.types().skip(1) @@ -578,7 +579,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Try to report a help message if !trait_ref.has_infer_types() && - self.predicate_can_apply(trait_ref) { + self.predicate_can_apply(obligation.param_env, trait_ref) { // If a where-clause may be useful, remind the // user that they can add it. // @@ -607,7 +608,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.equality_predicate(&obligation.cause, - &predicate).err().unwrap(); + obligation.param_env, + &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0278, "the requirement `{}` is not satisfied (`{}`)", predicate, err) @@ -936,7 +938,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Returns whether the trait predicate may apply for *some* assignment /// to the type parameters. - fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool { + fn predicate_can_apply(&self, + param_env: ty::ParamEnv<'tcx>, + pred: ty::PolyTraitRef<'tcx>) + -> bool { struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, var_map: FxHashMap, Ty<'tcx>> @@ -967,12 +972,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let cleaned_pred = super::project::normalize( &mut selcx, + param_env, ObligationCause::dummy(), &cleaned_pred ).value; let obligation = Obligation::new( ObligationCause::dummy(), + param_env, cleaned_pred.to_predicate() ); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index e8baaa7ffb26d..daeb96e188d37 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -113,6 +113,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { /// `projection_ty` again. pub fn normalize_projection_type(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>) -> Ty<'tcx> @@ -125,7 +126,11 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { // FIXME(#20304) -- cache let mut selcx = SelectionContext::new(infcx); - let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0); + let normalized = project::normalize_projection_type(&mut selcx, + param_env, + projection_ty, + cause, + 0); for obligation in normalized.obligations { self.register_predicate_obligation(infcx, obligation); @@ -136,8 +141,12 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { normalized.value } + /// Requires that `ty` must implement the trait with `def_id` in + /// the given environment. This trait must not have any type + /// parameters (except for `Self`). pub fn register_bound(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, cause: ObligationCause<'tcx>) @@ -149,6 +158,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { self.register_predicate_obligation(infcx, Obligation { cause: cause, recursion_depth: 0, + param_env, predicate: trait_ref.to_predicate() }); } @@ -410,7 +420,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(&obligation.cause, binder) { + match selcx.infcx().equality_predicate(&obligation.cause, obligation.param_env, binder) { Ok(InferOk { obligations, value: () }) => { Ok(Some(obligations)) }, @@ -498,7 +508,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id, + match ty::wf::obligations(selcx.infcx(), obligation.param_env, obligation.cause.body_id, ty, obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; @@ -509,7 +519,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Subtype(ref subtype) => { - match selcx.infcx().subtype_predicate(&obligation.cause, subtype) { + match selcx.infcx().subtype_predicate(&obligation.cause, obligation.param_env, subtype) { None => { // none means that both are unresolved pending_obligation.stalled_on = vec![subtype.skip_binder().a, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index fee6ce95a3f7f..c51974e6e6700 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -68,6 +68,7 @@ mod util; #[derive(Clone, PartialEq, Eq)] pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, pub recursion_depth: usize, pub predicate: T, } @@ -359,10 +360,11 @@ pub struct VtableFnPointerData<'tcx, N> { /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, generic_bounds: &ty::InstantiatedPredicates<'tcx>) -> PredicateObligations<'tcx> { - util::predicates_for_generics(cause, 0, generic_bounds) + util::predicates_for_generics(cause, 0, param_env, generic_bounds) } /// Determines whether the type `ty` is known to meet `bound` and @@ -371,6 +373,7 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, span: Span) @@ -385,6 +388,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx substs: infcx.tcx.mk_substs_trait(ty, &[]), }; let obligation = Obligation { + param_env, cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID), recursion_depth: 0, predicate: trait_ref.to_predicate(), @@ -408,7 +412,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx // anyhow). let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); - fulfill_cx.register_bound(infcx, ty, def_id, cause); + fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); // Note: we only assume something is `Copy` if we can // *definitively* show that it implements `Copy`. Otherwise, @@ -480,22 +484,24 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal); - tcx.infer_ctxt(elaborated_env).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let predicates = match fully_normalize( - &infcx, cause, - // You would really want to pass infcx.param_env.caller_bounds here, - // but that is an interned slice, and fully_normalize takes &T and returns T, so - // without further refactoring, a slice can't be used. Luckily, we still have the - // predicate vector from which we created the ParamEnv in infcx, so we - // can pass that instead. It's roundabout and a bit brittle, but this code path - // ought to be refactored anyway, and until then it saves us from having to copy. - &predicates, + &infcx, + cause, + elaborated_env, + // You would really want to pass infcx.param_env.caller_bounds here, + // but that is an interned slice, and fully_normalize takes &T and returns T, so + // without further refactoring, a slice can't be used. Luckily, we still have the + // predicate vector from which we created the ParamEnv in infcx, so we + // can pass that instead. It's roundabout and a bit brittle, but this code path + // ought to be refactored anyway, and until then it saves us from having to copy. + &predicates, ) { Ok(predicates) => predicates, Err(errors) => { infcx.report_fulfillment_errors(&errors); // An unnormalized env is better than nothing. - return infcx.param_env; + return elaborated_env; } }; @@ -517,17 +523,17 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // all things considered. tcx.sess.span_err(span, &fixup_err.to_string()); // An unnormalized env is better than nothing. - return infcx.param_env; + return elaborated_env; } }; let predicates = match tcx.lift_to_global(&predicates) { Some(predicates) => predicates, - None => return infcx.param_env + None => return elaborated_env, }; debug!("normalize_param_env_or_error: resolved predicates={:?}", - predicates); + predicates); ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal) }) @@ -535,6 +541,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, value: &T) -> Result>> where T : TypeFoldable<'tcx> @@ -558,7 +565,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, let mut fulfill_cx = FulfillmentContext::new(); let Normalized { value: normalized_value, obligations } = - project::normalize(selcx, cause, value); + project::normalize(selcx, param_env, cause, value); debug!("fully_normalize: normalized_value={:?} obligations={:?}", normalized_value, obligations); @@ -580,10 +587,10 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, Ok(resolved_value) } -/// Normalizes the predicates and checks whether they hold. If this -/// returns false, then either normalize encountered an error or one -/// of the predicates did not hold. Used when creating vtables to -/// check for unsatisfiable methods. +/// Normalizes the predicates and checks whether they hold in an empty +/// environment. If this returns false, then either normalize +/// encountered an error or one of the predicates did not hold. Used +/// when creating vtables to check for unsatisfiable methods. pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates: Vec>) -> bool @@ -591,17 +598,18 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.infer_ctxt(Reveal::All).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { + let param_env = ty::ParamEnv::empty(Reveal::All); let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = FulfillmentContext::new(); let cause = ObligationCause::dummy(); let Normalized { value: predicates, obligations } = - normalize(&mut selcx, cause.clone(), &predicates); + normalize(&mut selcx, param_env, cause.clone(), &predicates); for obligation in obligations { fulfill_cx.register_predicate_obligation(&infcx, obligation); } for predicate in predicates { - let obligation = Obligation::new(cause.clone(), predicate); + let obligation = Obligation::new(cause.clone(), param_env, predicate); fulfill_cx.register_predicate_obligation(&infcx, obligation); } @@ -663,30 +671,33 @@ pub fn get_vtable_methods<'a, 'tcx>( impl<'tcx,O> Obligation<'tcx,O> { pub fn new(cause: ObligationCause<'tcx>, - trait_ref: O) + param_env: ty::ParamEnv<'tcx>, + predicate: O) -> Obligation<'tcx, O> { - Obligation { cause: cause, - recursion_depth: 0, - predicate: trait_ref } + Obligation { cause, param_env, recursion_depth: 0, predicate } } fn with_depth(cause: ObligationCause<'tcx>, recursion_depth: usize, - trait_ref: O) + param_env: ty::ParamEnv<'tcx>, + predicate: O) -> Obligation<'tcx, O> { - Obligation { cause: cause, - recursion_depth: recursion_depth, - predicate: trait_ref } + Obligation { cause, param_env, recursion_depth, predicate } } - pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span, body_id), trait_ref) + pub fn misc(span: Span, + body_id: ast::NodeId, + param_env: ty::ParamEnv<'tcx>, + trait_ref: O) + -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) } pub fn with

(&self, value: P) -> Obligation<'tcx,P> { Obligation { cause: self.cause.clone(), + param_env: self.param_env, recursion_depth: self.recursion_depth, predicate: value } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 467783fcd7d86..c155d1bf241b5 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -168,7 +168,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( let Normalized { value: normalized_ty, mut obligations } = match opt_normalize_projection_type(selcx, - obligation.predicate.projection_ty.clone(), + obligation.param_env, + obligation.predicate.projection_ty, obligation.cause.clone(), obligation.recursion_depth) { Some(n) => n, @@ -180,7 +181,11 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations); let infcx = selcx.infcx(); - match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) { + match infcx.eq_types(true, + &obligation.cause, + obligation.param_env, + normalized_ty, + obligation.predicate.ty) { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); Ok(Some(obligations)) @@ -194,17 +199,19 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( /// combines the normalized result and any additional obligations that /// were incurred as result. pub fn normalize<'a, 'b, 'gcx, 'tcx, T>(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, value: &T) -> Normalized<'tcx, T> where T : TypeFoldable<'tcx> { - normalize_with_depth(selcx, cause, 0, value) + normalize_with_depth(selcx, param_env, cause, 0, value) } /// As `normalize`, but with a custom depth. pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize, value: &T) @@ -213,7 +220,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>( where T : TypeFoldable<'tcx> { debug!("normalize_with_depth(depth={}, value={:?})", depth, value); - let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth); + let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth); let result = normalizer.fold(value); debug!("normalize_with_depth: depth={} result={:?} with {} obligations", depth, result, normalizer.obligations.len()); @@ -227,6 +234,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>( struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, obligations: Vec>, depth: usize, @@ -234,12 +242,14 @@ struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { fn new(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, depth: usize) -> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { AssociatedTypeNormalizer { selcx: selcx, + param_env: param_env, cause: cause, obligations: vec![], depth: depth, @@ -305,6 +315,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let Normalized { value: normalized_ty, obligations } = normalize_projection_type(self.selcx, + self.param_env, data.clone(), self.cause.clone(), self.depth); @@ -344,12 +355,13 @@ impl<'tcx,T> Normalized<'tcx,T> { /// obligation `::Item == $X` for later. pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize) -> NormalizedTy<'tcx> { - opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth) + opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth) .unwrap_or_else(move || { // if we bottom out in ambiguity, create a type variable // and a deferred predicate to resolve this when more type @@ -366,7 +378,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( ty: ty_var }); let obligation = Obligation::with_depth( - cause, depth + 1, projection.to_predicate()); + cause, depth + 1, param_env, projection.to_predicate()); Normalized { value: ty_var, obligations: vec![obligation] @@ -380,6 +392,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( /// which indicates that there are unbound type variables. fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize) @@ -449,6 +462,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( let recursion_limit = selcx.tcx().sess.recursion_limit.get(); let obligation = Obligation::with_depth(cause.clone(), recursion_limit, + param_env, projection_ty); selcx.infcx().report_overflow_error(&obligation, false); } @@ -464,11 +478,11 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( Err(ProjectionCacheEntry::Error) => { debug!("opt_normalize_projection_type: \ found error"); - return Some(normalize_to_error(selcx, projection_ty, cause, depth)); + return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth)); } } - let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone()); + let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); match project_type(selcx, &obligation) { Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations, @@ -489,7 +503,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( cacheable); let result = if projected_ty.has_projection_types() { - let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1); + let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth+1); let normalized_ty = normalizer.fold(&projected_ty); debug!("opt_normalize_projection_type: \ @@ -540,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( infcx.projection_cache.borrow_mut() .error(projection_ty); - Some(normalize_to_error(selcx, projection_ty, cause, depth)) + Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth)) } } } @@ -565,6 +579,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( /// because it contains `[type error]`. Yuck! (See issue #29857 for /// one case where this arose.) fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, depth: usize) @@ -573,6 +588,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); let trait_obligation = Obligation { cause: cause, recursion_depth: depth, + param_env, predicate: trait_ref.to_predicate() }; let tcx = selcx.infcx().tcx; let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i| @@ -746,13 +762,12 @@ fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>( candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { debug!("assemble_candidates_from_param_env(..)"); - let env_predicates = selcx.param_env().caller_bounds.iter().cloned(); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, candidate_set, ProjectionTyCandidate::ParamEnv, - env_predicates); + obligation.param_env.caller_bounds.iter().cloned()); } /// In the case of a nested projection like <::FooT as Bar>::BarT, we may find @@ -807,7 +822,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, env_predicates: I) - where I: Iterator> + where I: IntoIterator> { debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); @@ -827,6 +842,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( obligation_trait_ref.to_poly_trait_ref(); infcx.sub_poly_trait_refs(false, obligation.cause.clone(), + obligation.param_env, data_poly_trait_ref, obligation_poly_trait_ref) .map(|InferOk { obligations: _, value: () }| { @@ -936,7 +952,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // get a result which isn't correct for all monomorphizations. let new_candidate = if !is_default { Some(ProjectionTyCandidate::Select) - } else if selcx.projection_mode() == Reveal::All { + } else if obligation.param_env.reveal == Reveal::All { assert!(!poly_trait_ref.needs_infer()); if !poly_trait_ref.needs_subst() { Some(ProjectionTyCandidate::Select) @@ -1096,6 +1112,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( selcx.infcx().probe(|_| { selcx.infcx().sub_poly_trait_refs(false, obligation.cause.clone(), + obligation.param_env, data_poly_trait_ref, obligation_poly_trait_ref).is_ok() }) @@ -1143,6 +1160,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( value: closure_type, obligations } = normalize_with_depth(selcx, + obligation.param_env, obligation.cause.clone(), obligation.recursion_depth+1, &closure_type); @@ -1203,8 +1221,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( { let infcx = selcx.infcx(); let cause = obligation.cause.clone(); + let param_env = obligation.param_env; let trait_ref = obligation.predicate.trait_ref; - match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) { + match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) { Ok(InferOk { value: ty_match, obligations }) => { Progress { ty: ty_match.value, @@ -1233,6 +1252,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( let VtableImplData { substs, nested, impl_def_id } = impl_vtable; let tcx = selcx.tcx(); + let param_env = obligation.param_env; let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx)); let ty = if !assoc_ty.item.defaultness.has_value() { @@ -1247,7 +1267,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( } else { tcx.type_of(assoc_ty.item.def_id) }; - let substs = translate_substs(selcx.infcx(), impl_def_id, substs, assoc_ty.node); + let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); Progress { ty: ty.subst(tcx, substs), obligations: nested, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 12f9e2f355bb9..21d4df3d0990d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -21,7 +21,6 @@ use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; use super::{ObjectCastObligation, Obligation}; -use super::Reveal; use super::TraitNotObjectSafe; use super::Selection; use super::SelectionResult; @@ -315,18 +314,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn param_env(&self) -> ty::ParamEnv<'gcx> { - self.infcx.param_env() - } - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> { self.infcx } - pub fn projection_mode(&self) -> Reveal { - self.param_env().reveal - } - /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection /// context's self. fn in_snapshot(&mut self, f: F) -> R @@ -540,7 +531,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Equate(ref p) => { // does this code ever run? - match self.infcx.equality_predicate(&obligation.cause, p) { + match self.infcx.equality_predicate(&obligation.cause, obligation.param_env, p) { Ok(InferOk { obligations, .. }) => { self.inferred_obligations.extend(obligations); EvaluatedToOk @@ -551,7 +542,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::Subtype(ref p) => { // does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, p) { + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { self.inferred_obligations.extend(obligations); EvaluatedToOk @@ -562,7 +553,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(self.infcx, obligation.cause.body_id, + match ty::wf::obligations(self.infcx, obligation.param_env, obligation.cause.body_id, ty, obligation.cause.span) { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), @@ -628,7 +619,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let stack = self.push_stack(previous_stack, obligation); let fresh_trait_ref = stack.fresh_trait_ref; - if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) { + if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); @@ -640,7 +631,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); - self.insert_evaluation_cache(fresh_trait_ref, result); + self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, result); result } @@ -751,10 +742,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { result } - fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>) + fn check_evaluation_cache(&self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) -> Option { - if self.can_use_global_caches() { + if self.can_use_global_caches(param_env) { let cache = self.tcx().evaluation_cache.hashmap.borrow(); if let Some(cached) = cache.get(&trait_ref) { return Some(cached.clone()); @@ -764,6 +757,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn insert_evaluation_cache(&mut self, + param_env: ty::ParamEnv<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, result: EvaluationResult) { @@ -778,7 +772,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return; } - if self.can_use_global_caches() { + if self.can_use_global_caches(param_env) { let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut(); if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) { cache.insert(trait_ref, result); @@ -819,7 +813,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack); assert!(!stack.obligation.predicate.has_escaping_regions()); - if let Some(c) = self.check_candidate_cache(&cache_fresh_trait_pred) { + if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, + &cache_fresh_trait_pred) { debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); @@ -832,7 +827,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) { debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); - self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone()); + self.insert_candidate_cache(stack.obligation.param_env, + cache_fresh_trait_pred, + candidate.clone()); } candidate @@ -995,7 +992,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Returns true if the global caches can be used. /// Do note that if the type itself is not in the /// global tcx, the local caches will be used. - fn can_use_global_caches(&self) -> bool { + fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { // If there are any where-clauses in scope, then we always use // a cache local to this particular scope. Otherwise, we // switch to a global cache. We used to try and draw @@ -1003,7 +1000,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // annoying and weird bugs like #22019 and #18290. This simple // rule seems to be pretty clearly safe and also still retains // a very high hit rate (~95% when compiling rustc). - if !self.param_env().caller_bounds.is_empty() { + if !param_env.caller_bounds.is_empty() { return false; } @@ -1023,11 +1020,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn check_candidate_cache(&mut self, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) -> Option>> { let trait_ref = &cache_fresh_trait_pred.0.trait_ref; - if self.can_use_global_caches() { + if self.can_use_global_caches(param_env) { let cache = self.tcx().selection_cache.hashmap.borrow(); if let Some(cached) = cache.get(&trait_ref) { return Some(cached.clone()); @@ -1037,11 +1035,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn insert_candidate_cache(&mut self, + param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) { let trait_ref = cache_fresh_trait_pred.0.trait_ref; - if self.can_use_global_caches() { + if self.can_use_global_caches(param_env) { let mut cache = self.tcx().selection_cache.hashmap.borrow_mut(); if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) { if let Some(candidate) = self.tcx().lift_to_global(&candidate) { @@ -1099,6 +1098,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { let TraitObligationStack { obligation, .. } = *stack; let ref obligation = Obligation { + param_env: obligation.param_env, cause: obligation.cause.clone(), recursion_depth: obligation.recursion_depth, predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate) @@ -1272,6 +1272,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let cause = obligation.cause.clone(); match self.infcx.sub_poly_trait_refs(false, cause, + obligation.param_env, trait_bound.clone(), ty::Binder(skol_trait_ref.clone())) { Ok(InferOk { obligations, .. }) => { @@ -1296,9 +1297,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack.obligation); let all_bounds = - self.param_env().caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); + stack.obligation.param_env.caller_bounds + .iter() + .filter_map(|o| o.to_opt_poly_trait_ref()); // micro-optimization: filter out predicates relating to different // traits. @@ -1953,6 +1954,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn collect_predicates_for_types(&mut self, + param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, trait_def_id: DefId, @@ -1981,16 +1983,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { this.infcx().skolemize_late_bound_regions(&ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = project::normalize_with_depth(this, + param_env, cause.clone(), recursion_depth, &skol_ty); let skol_obligation = - this.tcx().predicate_for_trait_def( - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[]); + this.tcx().predicate_for_trait_def(param_env, + cause.clone(), + trait_def_id, + recursion_depth, + normalized_ty, + &[]); obligations.push(skol_obligation); this.infcx().plug_leaks(skol_map, snapshot, obligations) }) @@ -2131,7 +2134,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types(cause, + self.collect_predicates_for_types(obligation.param_env, + cause, obligation.recursion_depth+1, trait_def, nested) @@ -2175,6 +2179,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let cause = obligation.derived_cause(BuiltinDerivedObligation); let mut obligations = self.collect_predicates_for_types( + obligation.param_env, cause, obligation.recursion_depth+1, trait_def_id, @@ -2187,6 +2192,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let cause = obligation.derived_cause(ImplDerivedObligation); this.impl_or_trait_obligations(cause, obligation.recursion_depth + 1, + obligation.param_env, trait_def_id, &trait_ref.substs, skol_map, @@ -2220,9 +2226,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { snapshot); debug!("confirm_impl_candidate substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - this.vtable_impl(impl_def_id, substs, cause, + this.vtable_impl(impl_def_id, + substs, + cause, obligation.recursion_depth + 1, - skol_map, snapshot) + obligation.param_env, + skol_map, + snapshot) }) } @@ -2231,6 +2241,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>, cause: ObligationCause<'tcx>, recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, skol_map: infer::SkolemizationMap<'tcx>, snapshot: &infer::CombinedSnapshot) -> VtableImplData<'tcx, PredicateObligation<'tcx>> @@ -2244,6 +2255,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut impl_obligations = self.impl_or_trait_obligations(cause, recursion_depth, + param_env, impl_def_id, &substs.value, skol_map, @@ -2345,6 +2357,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .map_bound(|(trait_ref, _)| trait_ref); self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.param_env, obligation.predicate.to_poly_trait_ref(), trait_ref)?; Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] }) @@ -2374,12 +2387,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligations); self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.param_env, obligation.predicate.to_poly_trait_ref(), trait_ref)?; obligations.push(Obligation::new( - obligation.cause.clone(), - ty::Predicate::ClosureKind(closure_def_id, kind))); + obligation.cause.clone(), + obligation.param_env, + ty::Predicate::ClosureKind(closure_def_id, kind))); Ok(VtableClosureData { closure_def_id: closure_def_id, @@ -2415,6 +2430,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// report an error to the user. fn confirm_poly_trait_refs(&mut self, obligation_cause: ObligationCause<'tcx>, + obligation_param_env: ty::ParamEnv<'tcx>, obligation_trait_ref: ty::PolyTraitRef<'tcx>, expected_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(), SelectionError<'tcx>> @@ -2422,6 +2438,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let obligation_trait_ref = obligation_trait_ref.clone(); self.infcx.sub_poly_trait_refs(false, obligation_cause.clone(), + obligation_param_env, expected_trait_ref.clone(), obligation_trait_ref.clone()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) @@ -2458,7 +2475,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.eq_types(false, &obligation.cause, new_trait, target) + self.infcx.eq_types(false, + &obligation.cause, + obligation.param_env, + new_trait, + target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2469,6 +2490,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth(cause, obligation.recursion_depth + 1, + obligation.param_env, ty::Binder(outlives).to_predicate())); } @@ -2488,6 +2510,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut push = |predicate| { nested.push(Obligation::with_depth(cause.clone(), obligation.recursion_depth + 1, + obligation.param_env, predicate)); }; @@ -2517,7 +2540,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.eq_types(false, &obligation.cause, a, b) + self.infcx.eq_types(false, &obligation.cause, obligation.param_env, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2580,12 +2603,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.eq_types(false, &obligation.cause, new_struct, target) + self.infcx.eq_types(false, + &obligation.cause, + obligation.param_env, + new_struct, + target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); // Construct the nested Field: Unsize> predicate. nested.push(tcx.predicate_for_trait_def( + obligation.param_env, obligation.cause.clone(), obligation.predicate.def_id(), obligation.recursion_depth + 1, @@ -2655,6 +2683,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let impl_trait_ref = project::normalize_with_depth(self, + obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, &impl_trait_ref); @@ -2669,6 +2698,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let InferOk { obligations, .. } = self.infcx.eq_trait_refs(false, &obligation.cause, + obligation.param_env, impl_trait_ref.value.clone(), skol_obligation_trait_ref) .map_err(|e| { @@ -2742,6 +2772,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.sub_poly_trait_refs(false, obligation.cause.clone(), + obligation.param_env, poly_trait_ref, obligation.predicate.to_poly_trait_ref()) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) @@ -2809,6 +2840,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // A closure signature can contain associated types which // must be normalized. normalize_with_depth(self, + obligation.param_env, obligation.cause.clone(), obligation.recursion_depth+1, &trait_ref) @@ -2821,6 +2853,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn impl_or_trait_obligations(&mut self, cause: ObligationCause<'tcx>, recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, def_id: DefId, // of impl or trait substs: &Substs<'tcx>, // for impl or trait skol_map: infer::SkolemizationMap<'tcx>, @@ -2847,12 +2880,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { - let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, + let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth, &predicate.subst(tcx, substs)); predicate.obligations.into_iter().chain( Some(Obligation { cause: cause.clone(), recursion_depth: recursion_depth, + param_env, predicate: predicate.value })) }).collect(); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 4d7fdbd881ec3..0e9bf93cbd2d1 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -41,6 +41,7 @@ pub struct OverlapError { /// Given a subst for the requested impl, translate it to a subst /// appropriate for the actual item definition (whether it be in that impl, /// a parent impl, or the trait). +/// /// When we have selected one impl, but are actually using item definitions from /// a parent impl providing a default, we need a way to translate between the /// type parameters of the two impls. Here the `source_impl` is the one we've @@ -73,6 +74,7 @@ pub struct OverlapError { /// *fulfillment* to relate the two impls, requiring that all projections are /// resolved. pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, source_impl: DefId, source_substs: &'tcx Substs<'tcx>, target_node: specialization_graph::Node) @@ -91,10 +93,11 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, return source_substs; } - fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| { - bug!("When translating substitutions for specialization, the expected \ - specializaiton failed to hold") - }) + fulfill_implication(infcx, param_env, source_trait_ref, target_impl) + .unwrap_or_else(|_| { + bug!("When translating substitutions for specialization, the expected \ + specializaiton failed to hold") + }) } specialization_graph::Node::Trait(..) => source_trait_ref.substs, }; @@ -122,9 +125,10 @@ pub fn find_associated_item<'a, 'tcx>( let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { - let substs = tcx.infer_ctxt(Reveal::All).enter(|infcx| { + let substs = tcx.infer_ctxt(()).enter(|infcx| { + let param_env = ty::ParamEnv::empty(Reveal::All); let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs(&infcx, impl_data.impl_def_id, + let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id, substs, node_item.node); let substs = infcx.tcx.erase_regions(&substs); tcx.lift(&substs).unwrap_or_else(|| { @@ -184,11 +188,14 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(penv).enter(|infcx| { + let result = tcx.infer_ctxt(()).enter(|infcx| { // Normalize the trait reference. The WF rules ought to ensure // that this always succeeds. let impl1_trait_ref = - match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) { + match traits::fully_normalize(&infcx, + ObligationCause::dummy(), + penv, + &impl1_trait_ref) { Ok(impl1_trait_ref) => impl1_trait_ref, Err(err) => { bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); @@ -196,7 +203,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() + fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() }); tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result); @@ -209,18 +216,21 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// `source_trait_ref` and those whose identity is determined via a where /// clause in the impl. fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, source_trait_ref: ty::TraitRef<'tcx>, target_impl: DefId) -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx, - target_impl, - target_substs); + param_env, + target_impl, + target_substs); // do the impls unify? If not, no specialization. match infcx.eq_trait_refs(true, &ObligationCause::dummy(), + param_env, source_trait_ref, target_trait_ref) { Ok(InferOk { obligations: o, .. }) => { @@ -250,7 +260,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, source_trait_ref, target_trait_ref, errors, - infcx.param_env.caller_bounds); + param_env.caller_bounds); Err(()) } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index aa35dfd1d70ad..702c5035a18b7 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -11,7 +11,7 @@ use super::{OverlapError, specializes}; use hir::def_id::DefId; -use traits::{self, Reveal}; +use traits; use ty::{self, TyCtxt, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use std::rc::Rc; @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children { let possible_sibling = *slot; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { + let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| { let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 9d0b1035ade49..4abb0cb549db4 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -341,6 +341,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx cause: self.cause.clone(), recursion_depth: self.recursion_depth, predicate: self.predicate.fold_with(folder), + param_env: self.param_env.fold_with(folder), } } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 4cffe6af083b6..7ad2ef90f0d49 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -46,12 +46,14 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - self.infer_ctxt(Reveal::All).enter(|infcx| { + self.infer_ctxt(()).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); + let param_env = ty::ParamEnv::empty(Reveal::All); let obligation_cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID); let obligation = Obligation::new(obligation_cause, + param_env, trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 3f5cf7eca5307..c385927811cf7 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -358,6 +358,7 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { /// returning the resulting trait ref and all obligations that arise. /// The obligations are closed under normalization. pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, impl_substs: &Substs<'tcx>) -> (ty::TraitRef<'tcx>, @@ -368,14 +369,14 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); + super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, ObligationCause::dummy(), &predicates); + super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, &predicates); + predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); let impl_obligations: Vec<_> = impl_obligations.into_iter() @@ -389,6 +390,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, /// See `super::obligations_for_generics` pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, generic_bounds: &ty::InstantiatedPredicates<'tcx>) -> Vec> { @@ -398,18 +400,21 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, generic_bounds.predicates.iter().map(|predicate| { Obligation { cause: cause.clone(), recursion_depth: recursion_depth, + param_env: param_env, predicate: predicate.clone() } }).collect() } pub fn predicate_for_trait_ref<'tcx>( cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, recursion_depth: usize) -> PredicateObligation<'tcx> { Obligation { cause: cause, + param_env: param_env, recursion_depth: recursion_depth, predicate: trait_ref.to_predicate(), } @@ -417,18 +422,19 @@ pub fn predicate_for_trait_ref<'tcx>( impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn predicate_for_trait_def(self, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - param_ty: Ty<'tcx>, - ty_params: &[Ty<'tcx>]) + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + trait_def_id: DefId, + recursion_depth: usize, + param_ty: Ty<'tcx>, + ty_params: &[Ty<'tcx>]) -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(param_ty, ty_params) }; - predicate_for_trait_ref(cause, trait_ref, recursion_depth) + predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) } /// Cast a trait reference into a reference to one of its super diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e0e195867131f..87cee2ddc03f8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -765,6 +765,18 @@ pub trait Lift<'tcx> { fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } +impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { + type Lifted = ty::ParamEnv<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { + self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| { + Some(ty::ParamEnv { + reveal: self.reveal, + caller_bounds, + }) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { type Lifted = Ty<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { @@ -851,6 +863,25 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { + type Lifted = &'tcx Slice>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option<&'tcx Slice>> { + if self.is_empty() { + return Some(Slice::empty()); + } + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + pub mod tls { use super::{CtxtInterners, GlobalCtxt, TyCtxt}; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0a25cd638cc30..8c991be0d12d4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -158,29 +158,6 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } -impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { - pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>, - impl_def_id: DefId) - -> ImplHeader<'tcx> - { - let tcx = selcx.tcx(); - let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); - - let header = ImplHeader { - impl_def_id: impl_def_id, - self_ty: tcx.type_of(impl_def_id), - trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.predicates_of(impl_def_id).predicates - }.subst(tcx, impl_substs); - - let traits::Normalized { value: mut header, obligations } = - traits::normalize(selcx, traits::ObligationCause::dummy(), &header); - - header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); - header - } -} - #[derive(Copy, Clone, Debug)] pub struct AssociatedItem { pub def_id: DefId, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 3a6147f911cce..1e2689243903e 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -466,6 +466,20 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } } +impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::ParamEnv { + reveal: self.reveal, + caller_bounds: self.caller_bounds.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + let &ty::ParamEnv { reveal: _, ref caller_bounds } = self; + caller_bounds.super_visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); @@ -771,6 +785,17 @@ impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); + folder.tcx().intern_predicates(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|p| p.visit_with(visitor)) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6d55f04e86aaa..8c2577a382431 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -170,11 +170,12 @@ impl<'tcx> ty::ParamEnv<'tcx> { ty::ParamEnv { reveal: Reveal::All, ..self } } - pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub fn can_type_implement_copy<'a>(self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type: Ty<'tcx>, span: Span) - -> Result<(), CopyImplementationError> { + -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt(self.clone()).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), @@ -182,8 +183,8 @@ impl<'tcx> ty::ParamEnv<'tcx> { let field_implements_copy = |field: &ty::FieldDef| { let cause = traits::ObligationCause::dummy(); - match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) { - Ok(ty) => !infcx.type_moves_by_default(ty, span), + match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) { + Ok(ty) => !infcx.type_moves_by_default(self, ty, span), Err(..) => false, } }; @@ -963,8 +964,12 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); - tcx.infer_ctxt(param_env) - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) + tcx.infer_ctxt(()) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) } fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -973,8 +978,12 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); - tcx.infer_ctxt(param_env) - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) + tcx.infer_ctxt(()) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) } fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -983,8 +992,12 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); - tcx.infer_ctxt(param_env) - .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) + tcx.infer_ctxt(()) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) } fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index d0cbbaf2c10bf..aa2c9802e5473 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -26,12 +26,14 @@ use middle::lang_items; /// make any progress at all. This is to prevent "livelock" where we /// say "$0 is WF if $0 is WF". pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, ty: Ty<'tcx>, span: Span) -> Option>> { let mut wf = WfPredicates { infcx: infcx, + param_env: param_env, body_id: body_id, span: span, out: vec![] }; @@ -50,23 +52,25 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// `trait Set`, then the trait reference `Foo: Set` is WF /// if `Bar: Eq`. pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, trait_ref: &ty::TraitRef<'tcx>, span: Span) -> Vec> { - let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; wf.compute_trait_ref(trait_ref); wf.normalize() } pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, predicate: &ty::Predicate<'tcx>, span: Span) -> Vec> { - let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; // (*) ok to skip binders, because wf code is prepared for it match *predicate { @@ -126,6 +130,7 @@ pub enum ImpliedBound<'tcx> { /// the `ImpliedBound` type for more details. pub fn implied_bounds<'a, 'gcx, 'tcx>( infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, ty: Ty<'tcx>, span: Span) @@ -148,7 +153,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) - let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]); + let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]); // From the full set of obligations, just filter down to the // region relationships. @@ -231,6 +236,7 @@ fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>, struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, span: Span, out: Vec>, @@ -244,11 +250,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn normalize(&mut self) -> Vec> { let cause = self.cause(traits::MiscObligation); let infcx = &mut self.infcx; + let param_env = self.param_env; self.out.iter() .inspect(|pred| assert!(!pred.has_escaping_regions())) .flat_map(|pred| { let mut selcx = traits::SelectionContext::new(infcx); - let pred = traits::normalize(&mut selcx, cause.clone(), pred); + let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred); once(pred.value).chain(pred.obligations) }) .collect() @@ -261,10 +268,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.extend(obligations); let cause = self.cause(traits::MiscObligation); + let param_env = self.param_env; self.out.extend( trait_ref.substs.types() .filter(|ty| !ty.has_escaping_regions()) .map(|ty| traits::Obligation::new(cause.clone(), + param_env, ty::Predicate::WellFormed(ty)))); } @@ -280,7 +289,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { if !data.has_escaping_regions() { let predicate = data.trait_ref.to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); - self.out.push(traits::Obligation::new(cause, predicate)); + self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } } @@ -291,7 +300,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; - self.out.push(traits::Obligation::new(cause, trait_ref.to_predicate())); + self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); } } @@ -301,6 +310,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { let mut subtys = ty0.walk(); + let param_env = self.param_env; while let Some(ty) = subtys.next() { match ty.sty { ty::TyBool | @@ -350,6 +360,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.push( traits::Obligation::new( cause, + param_env, ty::Predicate::TypeOutlives( ty::Binder( ty::OutlivesPredicate(mt.ty, r))))); @@ -389,12 +400,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // checking those let cause = self.cause(traits::MiscObligation); - let component_traits = data.auto_traits().chain(data.principal().map(|p| p.def_id())); self.out.extend( component_traits.map(|did| traits::Obligation::new( cause.clone(), + param_env, ty::Predicate::ObjectSafe(did) )) ); @@ -422,7 +433,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); self.out.push( // ...not the type we started from, so we made progress. - traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); + traits::Obligation::new(cause, + self.param_env, + ty::Predicate::WellFormed(ty))); } else { // Yes, resolved, proceed with the // result. Should never return false because @@ -448,7 +461,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates .into_iter() - .map(|pred| traits::Obligation::new(cause.clone(), pred)) + .map(|pred| traits::Obligation::new(cause.clone(), + self.param_env, + pred)) .filter(|pred| !pred.has_escaping_regions()) .collect() } @@ -497,7 +512,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { for implicit_bound in implicit_bounds { let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); - self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); + self.out.push(traits::Obligation::new(cause, + self.param_env, + outlives.to_predicate())); } } } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 0fe8865f4a268..122a37ee32aea 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -90,7 +90,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> { dfcx_loans: &'a LoanDataFlow<'a, 'tcx>, move_data: &'a move_data::FlowedMoveData<'a, 'tcx>, all_loans: &'a [Loan<'tcx>], - param_env: &'a ty::ParamEnv<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { @@ -191,15 +191,17 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &hir::Body) { debug!("check_loans(body id={})", body.value.id); + let def_id = bccx.tcx.hir.body_owner_def_id(body.id()); let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id()); + let param_env = bccx.tcx.param_env(def_id); let mut clcx = CheckLoanCtxt { bccx: bccx, dfcx_loans: dfcx_loans, move_data: move_data, all_loans: all_loans, - param_env: &infcx.param_env + param_env, }; - euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body); } #[derive(PartialEq)] diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 4cfee36359cd7..85a09969ac81c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -38,9 +38,10 @@ mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: hir::BodyId) - -> (Vec>, - move_data::MoveData<'tcx>) { + -> (Vec>, move_data::MoveData<'tcx>) { + let def_id = bccx.tcx.hir.body_owner_def_id(body); let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body); + let param_env = bccx.tcx.param_env(def_id); let mut glcx = GatherLoanCtxt { bccx: bccx, infcx: &infcx, @@ -51,7 +52,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, }; let body = glcx.bccx.tcx.hir.body(body); - euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2b5bbe0e8a5df..539f1ff3730ee 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { lp: &LoanPath<'tcx>, the_move: &move_data::Move, moved_lp: &LoanPath<'tcx>, - _param_env: &ty::ParamEnv<'tcx>) { + _param_env: ty::ParamEnv<'tcx>) { let (verb, verb_participle) = match use_kind { MovedInUse => ("use", "used"), MovedInCapture => ("capture", "captured"), diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 39db384e2ded2..dd26a3e611f88 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -517,11 +517,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, /// /// FIXME: this should be done by borrowck. fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { - cx.tcx.infer_ctxt((cx.tables, cx.param_env)).enter(|infcx| { + cx.tcx.infer_ctxt(cx.tables).enter(|infcx| { let mut checker = MutationChecker { cx: cx, }; - ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx).walk_expr(guard); + ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard); }); } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 1364898b549d4..3d07ffc2bc77a 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -483,9 +483,11 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), + param_env, trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { Ok(Some(vtable)) => vtable, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 619e7ec6a4f60..3a4729e64548a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -951,12 +951,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); let trait_ref = ty::Binder(trait_ref); let span = tcx.hir.span(expr_id); + let param_env = tcx.param_env(method.def_id); let obligation = traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), + param_env, trait_ref.to_poly_trait_predicate()); - let param_env = tcx.param_env(method.def_id); - tcx.infer_ctxt(param_env).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { // The method comes from a `T: Trait` bound. diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index e9cf3115ddab1..08a5cb37e5788 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -171,8 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { - let pe = tcx.param_env(tcx.hir.local_def_id(ctor_id)); - tcx.infer_ctxt(pe).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let (mut mir, src) = shim::build_adt_ctor(&infcx, ctor_id, fields, span); diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 581a403fb6dee..5b7b52a72b0ab 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -35,6 +35,7 @@ use std::rc::Rc; pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub param_env: ty::ParamEnv<'tcx>, pub region_maps: Rc, /// This is `Constness::Const` if we are compiling a `static`, @@ -64,6 +65,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let src_id = src.item_id(); let src_def_id = tcx.hir.local_def_id(src_id); + let param_env = tcx.param_env(src_def_id); let region_maps = tcx.region_maps(src_def_id); let attrs = tcx.hir.attrs(src_id); @@ -80,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants and const fn's always need overflow checks. check_overflow |= constness == hir::Constness::Const; - Cx { tcx, infcx, region_maps, constness, src, check_overflow } + Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow } } } @@ -169,12 +171,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { - let ty = self.tcx.lift_to_global(&ty).unwrap_or_else(|| { - bug!("MIR: Cx::needs_drop({}) got \ + let (ty, param_env) = self.tcx.lift_to_global(&(ty, self.param_env)).unwrap_or_else(|| { + bug!("MIR: Cx::needs_drop({:?}, {:?}) got \ type with inference types/regions", - ty); + ty, self.param_env); }); - ty.needs_drop(self.tcx.global_tcx(), self.infcx.param_env) + ty.needs_drop(self.tcx.global_tcx(), param_env) } pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7c49a11ca1f71..ef88e813a50c6 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -998,10 +998,13 @@ impl MirPass for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty; - tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, ty, + fulfillment_cx.register_bound(&infcx, + param_env, + ty, tcx.require_lang_item(lang_items::SyncTraitLangItem), cause); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f7055f90f0f83..fb162f354e991 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -320,6 +320,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'gcx>, fulfillment_cx: traits::FulfillmentContext<'tcx>, last_span: Span, body_id: ast::NodeId, @@ -327,12 +328,16 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + body_id: ast::NodeId, + param_env: ty::ParamEnv<'gcx>) + -> Self { TypeChecker { infcx: infcx, fulfillment_cx: traits::FulfillmentContext::new(), last_span: DUMMY_SP, - body_id: body_id, + body_id, + param_env, reported_errors: FxHashSet(), } } @@ -351,14 +356,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub) + self.infcx.sub_types(false, &self.misc(self.last_span), self.param_env, sup, sub) .map(|ok| self.register_infer_ok_obligations(ok)) } fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.eq_types(false, &self.misc(span), a, b) + self.infcx.eq_types(false, &self.misc(span), self.param_env, a, b) .map(|ok| self.register_infer_ok_obligations(ok)) } @@ -665,7 +670,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let span = local_decl.source_info.span; let ty = local_decl.ty; - if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) { + if !ty.is_sized(self.tcx().global_tcx(), self.param_env, span) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough @@ -706,7 +711,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let mut selcx = traits::SelectionContext::new(self.infcx); let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID); let traits::Normalized { value, obligations } = - traits::normalize(&mut selcx, cause, value); + traits::normalize(&mut selcx, self.param_env, cause, value); debug!("normalize: value={:?} obligations={:?}", value, @@ -752,8 +757,8 @@ impl MirPass for TypeckMir { return; } let param_env = tcx.param_env(def_id); - tcx.infer_ctxt(param_env).enter(|infcx| { - let mut checker = TypeChecker::new(&infcx, item_id); + tcx.infer_ctxt(()).enter(|infcx| { + let mut checker = TypeChecker::new(&infcx, item_id, param_env); { let mut verifier = TypeVerifier::new(&mut checker, mir); verifier.visit_mir(mir); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 2a4a13932e3fa..65a9334bbae19 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -139,10 +139,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| { - let param_env = infcx.param_env.clone(); + let param_env = self.tcx.param_env(item_def_id); let outer_penv = mem::replace(&mut self.param_env, param_env); let region_maps = &self.tcx.region_maps(item_def_id); - euv::ExprUseVisitor::new(self, region_maps, &infcx).consume_body(body); + euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body); outer_penv }); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1a13c8e6f3def..151de5ac98df9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -23,12 +23,12 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use type_::Type; use rustc_data_structures::base_n; +use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::Session; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; -use session::config::{self, NoDebugInfo}; -use session::Session; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 92017465f7d74..6aac9dc42ee02 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -118,13 +118,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); let mut selcx = traits::SelectionContext::new(self.fcx); - let obligation = traits::Obligation::new(cause.clone(), trait_ref.to_predicate()); + let obligation = traits::Obligation::new(cause.clone(), + self.fcx.param_env, + trait_ref.to_predicate()); if !selcx.evaluate_obligation(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; } let normalized = traits::normalize_projection_type(&mut selcx, + self.fcx.param_env, ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 72ce7d3b5ed71..91aeade65aa4c 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -555,6 +555,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool { let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem); - traits::type_known_to_meet_bound(self, ty, lang_item, span) + traits::type_known_to_meet_bound(self, self.param_env, ty, lang_item, span) } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index c2e8269aafef9..f041db43e16d7 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -81,9 +81,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig); let fn_sig = self.inh.normalize_associated_types_in(body.value.span, - body.value.id, &fn_sig); + body.value.id, + self.param_env, + &fn_sig); - check_fn(self, fn_sig, decl, expr.id, body); + check_fn(self, self.param_env, fn_sig, decl, expr.id, body); // Tuple up the arguments and insert the resulting function type into // the `closures` table. diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a962cdb8f728f..b1b4e099626cf 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -137,9 +137,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { - self.lub(false, trace, &a, &b) + self.lub(false, trace, self.fcx.param_env, &a, &b) } else { - self.sub(false, trace, &a, &b) + self.sub(false, trace, self.fcx.param_env, &a, &b) } }) } @@ -511,9 +511,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); - queue.push_back(self.tcx - .predicate_for_trait_def(cause, coerce_unsized_did, 0, - coerce_source, &[coerce_target])); + queue.push_back(self.tcx.predicate_for_trait_def(self.fcx.param_env, + cause, + coerce_unsized_did, + 0, + coerce_source, + &[coerce_target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -775,13 +778,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match (&prev_ty.sty, &new_ty.sty) { (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. - let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) + let fty = self.lub(true, trace.clone(), self.param_env, &a_fty, &b_fty) .map(|ok| self.register_infer_ok_obligations(ok))?; if a_def_id == b_def_id { // Same function, maybe the parameters match. let substs = self.commit_if_ok(|_| { - self.lub(true, trace.clone(), &a_substs, &b_substs) + self.lub(true, trace.clone(), self.param_env, &a_substs, &b_substs) .map(|ok| self.register_infer_ok_obligations(ok)) }); @@ -850,7 +853,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !noop { return self.commit_if_ok(|_| { - self.lub(true, trace.clone(), &prev_ty, &new_ty) + self.lub(true, trace.clone(), self.param_env, &prev_ty, &new_ty) .map(|ok| self.register_infer_ok_obligations(ok)) }); } @@ -863,7 +866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(e) } else { self.commit_if_ok(|_| { - self.lub(true, trace, &prev_ty, &new_ty) + self.lub(true, trace, self.param_env, &prev_ty, &new_ty) .map(|ok| self.register_infer_ok_obligations(ok)) }) } @@ -1106,7 +1109,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // Another example is `break` with no argument expression. assert!(expression_ty.is_nil()); assert!(expression_ty.is_nil(), "if let hack without unit type"); - fcx.eq_types(label_expression_as_expected, cause, expression_ty, self.merged_ty()) + fcx.eq_types(label_expression_as_expected, cause, fcx.param_env, expression_ty, self.merged_ty()) .map(|infer_ok| { fcx.register_infer_ok_obligations(infer_ok); expression_ty diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1d6d7fa61001a..50e7e89a5f61a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -219,12 +219,12 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env, normalize_cause.clone()); - tcx.infer_ctxt(param_env).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let inh = Inherited::new(infcx, impl_m.def_id); let infcx = &inh.infcx; debug!("compare_impl_method: caller_bounds={:?}", - infcx.param_env.caller_bounds); + param_env.caller_bounds); let mut selcx = traits::SelectionContext::new(&infcx); @@ -234,10 +234,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); + traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); inh.register_predicates(obligations); - inh.register_predicate(traits::Obligation::new(cause.clone(), predicate)); + inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate)); } // We now need to check that the signature of the impl method is @@ -270,6 +270,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_node_id, + param_env, &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -282,12 +283,13 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_node_id, + param_env, &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty) + let sub_result = infcx.sub_types(false, &cause, param_env, impl_fty, trait_fty) .map(|InferOk { obligations, .. }| { inh.register_predicates(obligations); }); @@ -298,6 +300,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_fty); let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, + param_env, &terr, &cause, impl_m, @@ -345,11 +348,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // pass around temporarily. let region_maps = RegionMaps::new(); let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates( - &infcx.param_env.caller_bounds); + free_regions.relate_free_regions_from_predicates(¶m_env.caller_bounds); infcx.resolve_regions_and_report_errors(impl_m.def_id, ®ion_maps, &free_regions); } else { - let fcx = FnCtxt::new(&inh, impl_m_node_id); + let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id); fcx.regionck_item(impl_m_node_id, impl_m_span, &[]); } @@ -400,6 +402,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, terr: &TypeError, cause: &ObligationCause<'tcx>, impl_m: &ty::AssociatedItem, @@ -458,14 +461,21 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a .zip(impl_m_iter) .zip(trait_m_iter) .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) { + match infcx.sub_types(true, + &cause, + param_env, + trait_arg_ty, + impl_arg_ty) { Ok(_) => None, Err(_) => Some((impl_arg.span, Some(trait_arg.span))), } }) .next() .unwrap_or_else(|| { - if infcx.sub_types(false, &cause, impl_sig.output(), + if infcx.sub_types(false, + &cause, + param_env, + impl_sig.output(), trait_sig.output()) .is_err() { (impl_m_output.span(), Some(trait_m_output.span())) @@ -714,7 +724,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; @@ -737,17 +748,19 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // There is no "body" here, so just pass dummy id. let impl_ty = inh.normalize_associated_types_in(impl_c_span, impl_c_node_id, + param_env, &impl_ty); debug!("compare_const_impl: impl_ty={:?}", impl_ty); let trait_ty = inh.normalize_associated_types_in(impl_c_span, impl_c_node_id, + param_env, &trait_ty); debug!("compare_const_impl: trait_ty={:?}", trait_ty); - let err = infcx.sub_types(false, &cause, impl_ty, trait_ty) + let err = infcx.sub_types(false, &cause, param_env, impl_ty, trait_ty) .map(|ok| inh.register_infer_ok_obligations(ok)); if let Err(terr) = err { @@ -795,7 +808,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } - let fcx = FnCtxt::new(&inh, impl_c_node_id); + let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id); fcx.regionck_item(impl_c_node_id, impl_c_span, &[]); }); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d92dafe690459..9c3dcc3f0e0eb 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -27,7 +27,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { let cause = self.misc(sp); - match self.sub_types(false, &cause, actual, expected) { + match self.sub_types(false, &cause, self.param_env, actual, expected) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); }, @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> Option> { - match self.eq_types(false, cause, actual, expected) { + match self.eq_types(false, cause, self.param_env, actual, expected) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); None diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 06f405120ae42..024d1f09f1cf7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -79,8 +79,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. - let impl_param_env = tcx.param_env(self_type_did); - tcx.infer_ctxt(impl_param_env).enter(|ref infcx| { + tcx.infer_ctxt(()).enter(|ref infcx| { + let impl_param_env = tcx.param_env(self_type_did); let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); @@ -92,7 +92,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); - match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) { + match infcx.eq_types(true, cause, impl_param_env, named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { fulfillment_cx.register_predicate_obligations(infcx, obligations); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 34e8d6b95a926..a5cf4dd268304 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) { + match self.sub_types(false, &self.misc(self.span), self.param_env, self_ty, method_self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index b0ac61d2cc34a..73c1215f275fb 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -205,7 +205,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Construct an obligation let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = - traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate()); + traits::Obligation::misc(span, + self.body_id, + self.param_env, + poly_trait_ref.to_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(self); @@ -262,14 +265,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(!bounds.has_escaping_regions()); let cause = traits::ObligationCause::misc(span, self.body_id); - obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); + obligations.extend(traits::predicates_for_generics(cause.clone(), + self.param_env, + &bounds)); // Also add an obligation for the method type being well-formed. let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, obligation); - obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); + obligations.push(traits::Obligation::new(cause, + self.param_env, + ty::Predicate::WellFormed(method_ty))); let callee = MethodCallee { def_id: def_id, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 1a1a9361a89f9..449c0f0281044 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); let mut selcx = &mut traits::SelectionContext::new(self.fcx); let traits::Normalized { value: xform_self_ty, obligations } = - traits::normalize(selcx, cause, &xform_self_ty); + traits::normalize(selcx, self.param_env, cause, &xform_self_ty); debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", xform_self_ty); @@ -679,7 +679,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let output = fty.output().subst(self.tcx, substs); let (output, _) = self.replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, &output); - self.can_sub_types(output, expected).is_ok() + self.can_sub_types(self.param_env, output, expected).is_ok() }) } _ => false, @@ -751,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.body_id); let mut selcx = &mut traits::SelectionContext::new(self.fcx); let traits::Normalized { value: xform_self_ty, obligations } = - traits::normalize(selcx, cause, &xform_self_ty); + traits::normalize(selcx, self.param_env, cause, &xform_self_ty); debug!("xform_self_ty={:?}", xform_self_ty); @@ -885,7 +885,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { substs, bound); - if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() { + if self.can_equate(self.param_env, &step.self_ty, &bound.self_ty()).is_ok() { let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs); debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}", @@ -1145,6 +1145,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // First check that the self type can be related. let sub_obligations = match self.sub_types(false, &ObligationCause::dummy(), + self.param_env, self_ty, probe.xform_self_ty) { Ok(InferOk { obligations, value: () }) => obligations, @@ -1182,10 +1183,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let impl_bounds = self.tcx.predicates_of(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = - traits::normalize(selcx, cause.clone(), &impl_bounds); + traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds); // Convert the bounds into obligations. - let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds); + let obligations = traits::predicates_for_generics(cause.clone(), self.param_env, &impl_bounds); debug!("impl_obligations={:?}", obligations); // Evaluate those obligations to see if they might possibly hold. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 594f1813a5ab4..c496053a1543b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -57,7 +57,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = - Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate()); + Obligation::misc(span, + self.body_id, + self.param_env, + poly_trait_ref.to_predicate()); SelectionContext::new(self).evaluate_obligation(&obligation) }) }) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8074c0630e395..055ce94d20105 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -450,6 +450,14 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> { pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { body_id: ast::NodeId, + /// The parameter environment used for proving trait obligations + /// in this function. This can change when we descend into + /// closures (as they bring new things into scope), hence it is + /// not part of `Inherited` (as of the time of this writing, + /// closures do not yet change the environment, but they will + /// eventually). + param_env: ty::ParamEnv<'tcx>, + // Number of errors that had been reported when we started // checking this function. On exit, if we find that *more* errors // have been reported, we will skip regionck and other work that @@ -528,9 +536,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId) -> InheritedBuilder<'a, 'gcx, 'tcx> { let tables = ty::TypeckTables::empty(); - let param_env = tcx.param_env(def_id); InheritedBuilder { - infcx: tcx.infer_ctxt((tables, param_env)), + infcx: tcx.infer_ctxt(tables), def_id, } } @@ -590,16 +597,18 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, + param_env: ty::ParamEnv<'tcx>, value: &T) -> T where T : TypeFoldable<'tcx> { - let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value); + let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, param_env, value); self.register_infer_ok_obligations(ok) } fn normalize_associated_types_in_as_infer_ok(&self, span: Span, body_id: ast::NodeId, + param_env: ty::ParamEnv<'tcx>, value: &T) -> InferOk<'tcx, T> where T : TypeFoldable<'tcx> @@ -608,7 +617,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { let mut selcx = traits::SelectionContext::new(self); let cause = ObligationCause::misc(span, body_id); let traits::Normalized { value, obligations } = - traits::normalize(&mut selcx, cause, value); + traits::normalize(&mut selcx, param_env, cause, value); debug!("normalize_associated_types_in: result={:?} predicates={:?}", value, obligations); @@ -797,6 +806,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let body = tcx.hir.body(body_id); Inherited::build(tcx, def_id).enter(|inh| { + let param_env = tcx.param_env(def_id); let fcx = if let Some(decl) = fn_decl { let fn_sig = tcx.type_of(def_id).fn_sig(); @@ -806,11 +816,14 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_sig = inh.liberate_late_bound_regions(def_id, &fn_sig); let fn_sig = - inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig); + inh.normalize_associated_types_in(body.value.span, + body_id.node_id, + param_env, + &fn_sig); - check_fn(&inh, fn_sig, decl, id, body) + check_fn(&inh, param_env, fn_sig, decl, id, body) } else { - let fcx = FnCtxt::new(&inh, body.value.id); + let fcx = FnCtxt::new(&inh, param_env, body.value.id); let expected_type = tcx.type_of(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -919,6 +932,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, fn_sig: ty::FnSig<'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, @@ -927,11 +941,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, { let mut fn_sig = fn_sig.clone(); - debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id); + debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let mut fcx = FnCtxt::new(inherited, body.value.id); + let mut fcx = FnCtxt::new(inherited, param_env, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); let ret_ty = fn_sig.output(); @@ -1633,10 +1647,12 @@ enum TupleArgumentsFlag { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { body_id: body_id, + param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, @@ -1870,7 +1886,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Require that the predicate holds for the concrete type. let cause = traits::ObligationCause::new(span, self.body_id, traits::ReturnType); - self.register_predicate(traits::Obligation::new(cause, predicate)); + self.register_predicate(traits::Obligation::new(cause, + self.param_env, + predicate)); } ty_var @@ -1883,15 +1901,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T : TypeFoldable<'tcx> { - let ok = self.normalize_associated_types_in_as_infer_ok(span, value); - self.register_infer_ok_obligations(ok) + self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) } fn normalize_associated_types_in_as_infer_ok(&self, span: Span, value: &T) -> InferOk<'tcx, T> where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value) + self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, self.param_env, value) } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -1929,7 +1946,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause: traits::ObligationCause<'tcx>) { self.fulfillment_cx.borrow_mut() - .register_bound(self, ty, def_id, cause); + .register_bound(self, self.param_env, ty, def_id, cause); } pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { @@ -1970,7 +1987,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { // WF obligations never themselves fail, so no real need to give a detailed cause: let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); + self.register_predicate(traits::Obligation::new(cause, + self.param_env, + ty::Predicate::WellFormed(ty))); } pub fn register_old_wf_obligation(&self, @@ -2023,7 +2042,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("add_obligations_for_parameters(predicates={:?})", predicates); - for obligation in traits::predicates_for_generics(cause, predicates) { + for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { self.register_predicate(obligation); } } @@ -2704,7 +2723,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = self.misc(call_span); - let ures = self.sub_types(false, &origin, formal_ret, ret_ty); + let ures = self.sub_types(false, &origin, self.param_env, formal_ret, ret_ty); // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. @@ -4199,7 +4218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => return, }; let last_expr_ty = self.expr_ty(last_expr); - if self.can_sub_types(last_expr_ty, expected_ty).is_err() { + if self.can_sub_types(self.param_env, last_expr_ty, expected_ty).is_err() { return; } let original_span = original_sp(last_stmt.span, blk.span); @@ -4459,7 +4478,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { + match self.sub_types(false, &self.misc(span), self.param_env, self_ty, impl_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { span_bug!(span, diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8e5b7a6546973..4d69b37b113cf 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -238,9 +238,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty); if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { - if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(ty_mut.ty, &[rhs_ty], - Op::Binary(op, is_assign)).is_ok() { + if { + !self.infcx.type_moves_by_default(self.param_env, + ty_mut.ty, + lhs_expr.span) && + self.lookup_op_method(ty_mut.ty, + &[rhs_ty], + Op::Binary(op, is_assign)) + .is_ok() + } { err.note( &format!( "this is a reference to a type that `{}` can be applied \ diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index afc003b986d41..db817efe93d4a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { for &ty in fn_sig_tys { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={:?})", ty); - let implied_bounds = ty::wf::implied_bounds(self, body_id, ty, span); + let implied_bounds = ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span); // Record any relations between free regions that we observe into the free-region-map. self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds); @@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // check whether this predicate applies to our current projection let cause = self.fcx.misc(span); - match self.eq_types(false, &cause, ty, outlives.0) { + match self.eq_types(false, &cause, self.fcx.param_env, ty, outlives.0) { Ok(ok) => { self.register_infer_ok_obligations(ok); Ok(outlives.1) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 286d0ad1b35a3..25f5418bea9c5 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -166,9 +166,11 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { { let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id()); let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id); + let param_env = self.fcx.param_env; let mut euv = euv::ExprUseVisitor::with_options(self, self.fcx, + param_env, region_maps, mc::MemCategorizationOptions { during_closure_kind_inference: true diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6895d73862562..26f708e934562 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -37,7 +37,8 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, code: ObligationCauseCode<'gcx>, id: ast::NodeId, - span: Span + span: Span, + param_env: ty::ParamEnv<'tcx>, } impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { @@ -48,8 +49,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let code = self.code.clone(); let id = self.id; let span = self.span; + let param_env = self.param_env; self.inherited.enter(|inh| { - let fcx = FnCtxt::new(&inh, id); + let fcx = FnCtxt::new(&inh, param_env, id); let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { tcx: fcx.tcx.global_tcx(), code: code @@ -206,11 +208,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn for_id<'tcx>(&self, id: ast::NodeId, span: Span) -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { + let def_id = self.tcx.hir.local_def_id(id); CheckWfFcxBuilder { - inherited: Inherited::build(self.tcx, self.tcx.hir.local_def_id(id)), + inherited: Inherited::build(self.tcx, def_id), code: self.code.clone(), id: id, - span: span + span: span, + param_env: self.tcx.param_env(def_id), } } @@ -374,6 +378,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ast_trait_ref.path.span, &trait_ref); let obligations = ty::wf::trait_obligations(fcx, + fcx.param_env, fcx.body_id, &trait_ref, ast_trait_ref.path.span); @@ -405,6 +410,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { predicates.predicates .iter() .flat_map(|p| ty::wf::predicate_obligations(fcx, + fcx.param_env, fcx.body_id, p, span)); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 89f2595d1a8fb..8c2679f1bbf53 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt(param_env).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, @@ -308,7 +308,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // we may have to evaluate constraint // expressions in the course of execution.) // See e.g. #41936. - if let Ok(ok) = infcx.eq_types(false, &cause, b, a) { + if let Ok(ok) = infcx.eq_types(false, &cause, param_env, b, a) { if ok.obligations.is_empty() { return None; } @@ -376,7 +376,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); - let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]); + let predicate = tcx.predicate_for_trait_def(param_env, + cause, + trait_def_id, + 0, + source, + &[target]); fulfill_cx.register_predicate_obligation(&infcx, predicate); // Check that all transitive obligations are satisfied. @@ -387,8 +392,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Finally, resolve all regions. let region_maps = RegionMaps::new(); let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates(&infcx.param_env - .caller_bounds); + free_regions.relate_free_regions_from_predicates(¶m_env.caller_bounds); infcx.resolve_regions_and_report_errors(impl_did, ®ion_maps, &free_regions); CoerceUnsizedInfo { diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 4aa12d08f61c5..afeb85a7a0656 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -11,7 +11,7 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::traits::{self, Reveal}; +use rustc::traits; use rustc::ty::{self, TyCtxt}; pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt(Reveal::UserFacing).enter(|infcx| { + self.tcx.infer_ctxt(()).enter(|infcx| { if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 91dec958a161c..ac0e360adb08a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -155,9 +155,10 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt(Reveal::UserFacing).enter(|ref infcx| { + tcx.infer_ctxt(()).enter(|ref infcx| { + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut fulfill_cx = FulfillmentContext::new(); - match infcx.eq_types(false, &cause, expected, actual) { + match infcx.eq_types(false, &cause, param_env, expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); } From c1e895d92c83bd626dece3410b015253e55fdb74 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 May 2017 14:20:12 -0400 Subject: [PATCH 4/8] remove `layout_cache` and fix `-Z print-type-sizes` now we grow the type-sizes info during execution, rather than walking the cache after the fact --- src/librustc/ty/context.rs | 4 - src/librustc/ty/layout.rs | 217 ++++++++++++++++++- src/librustc/ty/util.rs | 16 +- src/librustc_trans/base.rs | 194 +---------------- src/test/{compile-fail => ui}/issue-26548.rs | 0 src/test/ui/issue-26548.stderr | 9 + 6 files changed, 240 insertions(+), 200 deletions(-) rename src/test/{compile-fail => ui}/issue-26548.rs (100%) create mode 100644 src/test/ui/issue-26548.stderr diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 87cee2ddc03f8..c83f73bff6949 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -519,9 +519,6 @@ pub struct GlobalCtxt<'tcx> { /// Data layout specification for the current target. pub data_layout: TargetDataLayout, - /// Cache for layouts computed from types. - pub layout_cache: RefCell, &'tcx Layout>>, - /// Used to prevent layout from recursing too deeply. pub layout_depth: Cell, @@ -718,7 +715,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { rvalue_promotable_to_static: RefCell::new(NodeMap()), crate_name: Symbol::intern(crate_name), data_layout: data_layout, - layout_cache: RefCell::new(FxHashMap()), layout_interner: RefCell::new(FxHashSet()), layout_depth: Cell::new(0), derive_macros: RefCell::new(NodeMap()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 4dc764f6d30c2..c37fb0f5a778d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,10 +12,10 @@ pub use self::Integer::*; pub use self::Layout::*; pub use self::Primitive::*; -use session::Session; +use session::{self, DataTypeKind, Session}; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; -use syntax::ast::{FloatTy, IntTy, UintTy}; +use syntax::ast::{self, FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; @@ -1690,6 +1690,219 @@ impl<'a, 'tcx> Layout { } } } + + /// This is invoked by the `layout_raw` query to record the final + /// layout of each type. + #[inline] + pub fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + layout: &Layout) { + // If we are running with `-Zprint-type-sizes`, record layouts for + // dumping later. Ignore layouts that are done with non-empty + // environments or non-monomorphic layouts, as the user only wants + // to see the stuff resulting from the final trans session. + if + !tcx.sess.opts.debugging_opts.print_type_sizes || + ty.has_param_types() || + ty.has_self_ty() || + !param_env.caller_bounds.is_empty() + { + return; + } + + Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout) + } + + fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + layout: &Layout) { + // (delay format until we actually need it) + let record = |kind, opt_discr_size, variants| { + let type_desc = format!("{:?}", ty); + let overall_size = layout.size(tcx); + let align = layout.align(tcx); + tcx.sess.code_stats.borrow_mut().record_type_size(kind, + type_desc, + align, + overall_size, + opt_discr_size, + variants); + }; + + let (adt_def, substs) = match ty.sty { + ty::TyAdt(ref adt_def, substs) => { + debug!("print-type-size t: `{:?}` process adt", ty); + (adt_def, substs) + } + + ty::TyClosure(..) => { + debug!("print-type-size t: `{:?}` record closure", ty); + record(DataTypeKind::Closure, None, vec![]); + return; + } + + _ => { + debug!("print-type-size t: `{:?}` skip non-nominal", ty); + return; + } + }; + + let adt_kind = adt_def.adt_kind(); + + let build_field_info = |(field_name, field_ty): (ast::Name, Ty<'tcx>), offset: &Size| { + let layout = field_ty.layout(tcx, param_env); + match layout { + Err(_) => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty), + Ok(field_layout) => { + session::FieldInfo { + name: field_name.to_string(), + offset: offset.bytes(), + size: field_layout.size(tcx).bytes(), + align: field_layout.align(tcx).abi(), + } + } + } + }; + + let build_primitive_info = |name: ast::Name, value: &Primitive| { + session::VariantInfo { + name: Some(name.to_string()), + kind: session::SizeKind::Exact, + align: value.align(tcx).abi(), + size: value.size(tcx).bytes(), + fields: vec![], + } + }; + + enum Fields<'a> { + WithDiscrim(&'a Struct), + NoDiscrim(&'a Struct), + } + + let build_variant_info = |n: Option, + flds: &[(ast::Name, Ty<'tcx>)], + layout: Fields| { + let (s, field_offsets) = match layout { + Fields::WithDiscrim(s) => (s, &s.offsets[1..]), + Fields::NoDiscrim(s) => (s, &s.offsets[0..]), + }; + let field_info: Vec<_> = flds.iter() + .zip(field_offsets.iter()) + .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset)) + .collect(); + + session::VariantInfo { + name: n.map(|n|n.to_string()), + kind: if s.sized { + session::SizeKind::Exact + } else { + session::SizeKind::Min + }, + align: s.align.abi(), + size: s.min_size.bytes(), + fields: field_info, + } + }; + + match *layout { + Layout::StructWrappedNullablePointer { nonnull: ref variant_layout, + nndiscr, + discrfield: _, + discrfield_source: _ } => { + debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}", + ty, nndiscr, variant_layout); + let variant_def = &adt_def.variants[nndiscr as usize]; + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + record(adt_kind.into(), + None, + vec![build_variant_info(Some(variant_def.name), + &fields, + Fields::NoDiscrim(variant_layout))]); + } + Layout::RawNullablePointer { nndiscr, value } => { + debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}", + ty, nndiscr, value); + let variant_def = &adt_def.variants[nndiscr as usize]; + record(adt_kind.into(), None, + vec![build_primitive_info(variant_def.name, &value)]); + } + Layout::Univariant { variant: ref variant_layout, non_zero: _ } => { + let variant_names = || { + adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::>() + }; + debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}", + ty, variant_layout, variant_names()); + assert!(adt_def.variants.len() <= 1, + "univariant with variants {:?}", variant_names()); + if adt_def.variants.len() == 1 { + let variant_def = &adt_def.variants[0]; + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + record(adt_kind.into(), + None, + vec![build_variant_info(Some(variant_def.name), + &fields, + Fields::NoDiscrim(variant_layout))]); + } else { + // (This case arises for *empty* enums; so give it + // zero variants.) + record(adt_kind.into(), None, vec![]); + } + } + + Layout::General { ref variants, discr, .. } => { + debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}", + ty, adt_def.variants.len(), variants.len(), variants); + let variant_infos: Vec<_> = adt_def.variants.iter() + .zip(variants.iter()) + .map(|(variant_def, variant_layout)| { + let fields: Vec<_> = variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); + build_variant_info(Some(variant_def.name), + &fields, + Fields::WithDiscrim(variant_layout)) + }) + .collect(); + record(adt_kind.into(), Some(discr.size()), variant_infos); + } + + Layout::UntaggedUnion { ref variants } => { + debug!("print-type-size t: `{:?}` adt union variants {:?}", + ty, variants); + // layout does not currently store info about each + // variant... + record(adt_kind.into(), None, Vec::new()); + } + + Layout::CEnum { discr, .. } => { + debug!("print-type-size t: `{:?}` adt c-like enum", ty); + let variant_infos: Vec<_> = + adt_def.variants.iter() + .map(|variant_def| { + build_primitive_info(variant_def.name, + &Primitive::Int(discr)) + }) + .collect(); + record(adt_kind.into(), Some(discr.size()), variant_infos); + } + + // other cases provide little interesting (i.e. adjustable + // via representation tweaks) size info beyond total size. + Layout::Scalar { .. } | + Layout::Vector { .. } | + Layout::Array { .. } | + Layout::FatPointer { .. } => { + debug!("print-type-size t: `{:?}` adt other", ty); + record(adt_kind.into(), None, Vec::new()) + } + } + } } /// Type size "skeleton", i.e. the only information determining a type's size. diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 8c2577a382431..ec4ca54d6f5ed 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -799,9 +799,22 @@ impl<'a, 'tcx> ty::TyS<'tcx> { param_env: ty::ParamEnv<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { let ty = tcx.erase_regions(&self); - tcx.layout_raw(param_env.reveal_all().and(ty)) + let layout = tcx.layout_raw(param_env.reveal_all().and(ty)); + + // NB: This recording is normally disabled; when enabled, it + // can however trigger recursive invocations of `layout()`. + // Therefore, we execute it *after* the main query has + // completed, to avoid problems around recursive structures + // and the like. (Admitedly, I wasn't able to reproduce a problem + // here, but it seems like the right thing to do. -nmatsakis) + if let Ok(l) = layout { + Layout::record_layout_for_printing(tcx, ty, param_env, l); + } + + layout } + /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. pub fn is_representable(&'tcx self, @@ -1084,6 +1097,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.layout_depth.set(depth+1); let layout = Layout::compute_uncached(tcx, param_env, ty); tcx.layout_depth.set(depth); + layout } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1b3f0ba7ce5b6..88c30cd866599 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -44,7 +44,7 @@ use rustc::middle::cstore::LinkMeta; use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::session::config::{self, NoDebugInfo}; -use rustc::session::{self, DataTypeKind, Session}; +use rustc::session::Session; use rustc_incremental::IncrementalHashesMap; use abi; use mir::lvalue::LvalueRef; @@ -80,7 +80,6 @@ use std::i32; use syntax_pos::Span; use syntax::attr; use rustc::hir; -use rustc::ty::layout::{self, Layout}; use syntax::ast; use mir::lvalue::Alignment; @@ -1287,10 +1286,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &exported_symbols); }); - if tcx.sess.opts.debugging_opts.print_type_sizes { - gather_type_sizes(tcx); - } - if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { create_imps(sess, &llvm_modules); @@ -1322,193 +1317,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let layout_cache = tcx.layout_cache.borrow(); - for (ty, layout) in layout_cache.iter() { - - // (delay format until we actually need it) - let record = |kind, opt_discr_size, variants| { - let type_desc = format!("{:?}", ty); - let overall_size = layout.size(tcx); - let align = layout.align(tcx); - tcx.sess.code_stats.borrow_mut().record_type_size(kind, - type_desc, - align, - overall_size, - opt_discr_size, - variants); - }; - - let (adt_def, substs) = match ty.sty { - ty::TyAdt(ref adt_def, substs) => { - debug!("print-type-size t: `{:?}` process adt", ty); - (adt_def, substs) - } - - ty::TyClosure(..) => { - debug!("print-type-size t: `{:?}` record closure", ty); - record(DataTypeKind::Closure, None, vec![]); - continue; - } - - _ => { - debug!("print-type-size t: `{:?}` skip non-nominal", ty); - continue; - } - }; - - let adt_kind = adt_def.adt_kind(); - - let build_field_info = |(field_name, field_ty): (ast::Name, Ty), offset: &layout::Size| { - match layout_cache.get(&field_ty) { - None => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty), - Some(field_layout) => { - session::FieldInfo { - name: field_name.to_string(), - offset: offset.bytes(), - size: field_layout.size(tcx).bytes(), - align: field_layout.align(tcx).abi(), - } - } - } - }; - - let build_primitive_info = |name: ast::Name, value: &layout::Primitive| { - session::VariantInfo { - name: Some(name.to_string()), - kind: session::SizeKind::Exact, - align: value.align(tcx).abi(), - size: value.size(tcx).bytes(), - fields: vec![], - } - }; - - enum Fields<'a> { - WithDiscrim(&'a layout::Struct), - NoDiscrim(&'a layout::Struct), - } - - let build_variant_info = |n: Option, flds: &[(ast::Name, Ty)], layout: Fields| { - let (s, field_offsets) = match layout { - Fields::WithDiscrim(s) => (s, &s.offsets[1..]), - Fields::NoDiscrim(s) => (s, &s.offsets[0..]), - }; - let field_info: Vec<_> = flds.iter() - .zip(field_offsets.iter()) - .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset)) - .collect(); - - session::VariantInfo { - name: n.map(|n|n.to_string()), - kind: if s.sized { - session::SizeKind::Exact - } else { - session::SizeKind::Min - }, - align: s.align.abi(), - size: s.min_size.bytes(), - fields: field_info, - } - }; - - match **layout { - Layout::StructWrappedNullablePointer { nonnull: ref variant_layout, - nndiscr, - discrfield: _, - discrfield_source: _ } => { - debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}", - ty, nndiscr, variant_layout); - let variant_def = &adt_def.variants[nndiscr as usize]; - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); - record(adt_kind.into(), - None, - vec![build_variant_info(Some(variant_def.name), - &fields, - Fields::NoDiscrim(variant_layout))]); - } - Layout::RawNullablePointer { nndiscr, value } => { - debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}", - ty, nndiscr, value); - let variant_def = &adt_def.variants[nndiscr as usize]; - record(adt_kind.into(), None, - vec![build_primitive_info(variant_def.name, &value)]); - } - Layout::Univariant { variant: ref variant_layout, non_zero: _ } => { - let variant_names = || { - adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::>() - }; - debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}", - ty, variant_layout, variant_names()); - assert!(adt_def.variants.len() <= 1, - "univariant with variants {:?}", variant_names()); - if adt_def.variants.len() == 1 { - let variant_def = &adt_def.variants[0]; - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); - record(adt_kind.into(), - None, - vec![build_variant_info(Some(variant_def.name), - &fields, - Fields::NoDiscrim(variant_layout))]); - } else { - // (This case arises for *empty* enums; so give it - // zero variants.) - record(adt_kind.into(), None, vec![]); - } - } - - Layout::General { ref variants, discr, .. } => { - debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}", - ty, adt_def.variants.len(), variants.len(), variants); - let variant_infos: Vec<_> = adt_def.variants.iter() - .zip(variants.iter()) - .map(|(variant_def, variant_layout)| { - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); - build_variant_info(Some(variant_def.name), - &fields, - Fields::WithDiscrim(variant_layout)) - }) - .collect(); - record(adt_kind.into(), Some(discr.size()), variant_infos); - } - - Layout::UntaggedUnion { ref variants } => { - debug!("print-type-size t: `{:?}` adt union variants {:?}", - ty, variants); - // layout does not currently store info about each - // variant... - record(adt_kind.into(), None, Vec::new()); - } - - Layout::CEnum { discr, .. } => { - debug!("print-type-size t: `{:?}` adt c-like enum", ty); - let variant_infos: Vec<_> = adt_def.variants.iter() - .map(|variant_def| { - build_primitive_info(variant_def.name, - &layout::Primitive::Int(discr)) - }) - .collect(); - record(adt_kind.into(), Some(discr.size()), variant_infos); - } - - // other cases provide little interesting (i.e. adjustable - // via representation tweaks) size info beyond total size. - Layout::Scalar { .. } | - Layout::Vector { .. } | - Layout::Array { .. } | - Layout::FatPointer { .. } => { - debug!("print-type-size t: `{:?}` adt other", ty); - record(adt_kind.into(), None, Vec::new()) - } - } - } -} - #[inline(never)] // give this a place in the profiler fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I) where I: Iterator> diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/ui/issue-26548.rs similarity index 100% rename from src/test/compile-fail/issue-26548.rs rename to src/test/ui/issue-26548.rs diff --git a/src/test/ui/issue-26548.stderr b/src/test/ui/issue-26548.stderr new file mode 100644 index 0000000000000..8bfe4ac733b6d --- /dev/null +++ b/src/test/ui/issue-26548.stderr @@ -0,0 +1,9 @@ +error[E0391]: unsupported cyclic reference between types/traits detected + | +note: the cycle begins when computing layout of `S`... +note: ...which then requires computing layout of `std::option::Option<::It>`... +note: ...which then requires computing layout of `::It`... + = note: ...which then again requires computing layout of `S`, completing the cycle. + +error: aborting due to previous error + From c7a2e32c102057242950697da6b83b2190b00dfb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 May 2017 09:43:20 -0400 Subject: [PATCH 5/8] ergonomic improvements to the methods in infcx --- src/librustc/infer/at.rs | 310 ++++++++++++++++++++ src/librustc/infer/mod.rs | 191 ++---------- src/librustc/traits/coherence.rs | 9 +- src/librustc/traits/error_reporting.rs | 8 +- src/librustc/traits/project.rs | 32 +- src/librustc/traits/select.rs | 65 ++-- src/librustc/traits/specialize/mod.rs | 7 +- src/librustc_mir/transform/type_check.rs | 12 +- src/librustc_typeck/check/coercion.rs | 29 +- src/librustc_typeck/check/compare_method.rs | 35 +-- src/librustc_typeck/check/demand.rs | 6 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 11 +- src/librustc_typeck/check/mod.rs | 6 +- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- 18 files changed, 434 insertions(+), 297 deletions(-) create mode 100644 src/librustc/infer/at.rs diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs new file mode 100644 index 0000000000000..756e0b5f9fb6a --- /dev/null +++ b/src/librustc/infer/at.rs @@ -0,0 +1,310 @@ +// Copyright 2012-2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A nice interface for working with the infcx. The basic idea is to +//! do `infcx.at(cause, param_env)`, which sets the "cause" of the +//! operation as well as the surrounding parameter environment. Then +//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a +//! subtype or equality relationship respectively. The first argument +//! is always the "expected" output from the POV of diagnostics. +//! +//! Examples: +//! +//! infcx.at(cause, param_env).sub(a, b) +//! // requires that `a <: b`, with `a` considered the "expected" type +//! +//! infcx.at(cause, param_env).sup(a, b) +//! // requires that `b <: a`, with `a` considered the "expected" type +//! +//! infcx.at(cause, param_env).eq(a, b) +//! // requires that `a == b`, with `a` considered the "expected" type +//! +//! For finer-grained control, you can also do use `trace`: +//! +//! infcx.at(...).trace(a, b).sub(&c, &d) +//! +//! This will set `a` and `b` as the "root" values for +//! error-reporting, but actually operate on `c` and `d`. This is +//! sometimes useful when the types of `c` and `d` are not traceable +//! things. (That system should probably be refactored.) + +use super::*; + +use ty::relate::{Relate, TypeRelation}; + +pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> { + at: At<'a, 'gcx, 'tcx>, + a_is_expected: bool, + trace: TypeTrace<'tcx>, +} + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + pub fn at(&'a self, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> At<'a, 'gcx, 'tcx> + { + At { infcx: self, cause, param_env } + } +} + +pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx>; +} + +impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { + /// Hacky routine for equating two impl headers in coherence. + pub fn eq_impl_headers(self, + expected: &ty::ImplHeader<'tcx>, + actual: &ty::ImplHeader<'tcx>) + -> InferResult<'tcx, ()> + { + debug!("eq_impl_header({:?} = {:?})", expected, actual); + match (expected.trait_ref, actual.trait_ref) { + (Some(a_ref), Some(b_ref)) => + self.eq(a_ref, b_ref), + (None, None) => + self.eq(expected.self_ty, actual.self_ty), + _ => + bug!("mk_eq_impl_headers given mismatched impl kinds"), + } + } + + /// Make `a <: b` where `a` may or may not be expected + pub fn sub_exp(self, + a_is_expected: bool, + a: T, + b: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + self.trace_exp(a_is_expected, a, b).sub(&a, &b) + } + + /// Make `actual <: expected`. For example, if type-checking a + /// call like `foo(x)`, where `foo: fn(i32)`, you might have + /// `sup(i32, x)`, since the "expected" type is the type that + /// appears in the signature. + pub fn sup(self, + expected: T, + actual: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + self.sub_exp(false, actual, expected) + } + + /// Make `expected <: actual` + pub fn sub(self, + expected: T, + actual: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + self.sub_exp(true, expected, actual) + } + + /// Make `expected <: actual` + pub fn eq_exp(self, + a_is_expected: bool, + a: T, + b: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + self.trace_exp(a_is_expected, a, b).eq(&a, &b) + } + + /// Make `expected <: actual` + pub fn eq(self, + expected: T, + actual: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + self.trace(expected, actual).eq(&expected, &actual) + } + + /// Compute the least-upper-bound, or mutual supertype, of two + /// values. The order of the arguments doesn't matter, but since + /// this can result in an error (e.g., if asked to compute LUB of + /// u32 and i32), it is meaningful to call one of them the + /// "expected type". + pub fn lub(self, + expected: T, + actual: T) + -> InferResult<'tcx, T> + where T: ToTrace<'tcx> + { + self.trace(expected, actual).lub(&expected, &actual) + } + + /// Compute the greatest-lower-bound, or mutual subtype, of two + /// values. As with `lub` order doesn't matter, except for error + /// cases. + pub fn glb(self, + expected: T, + actual: T) + -> InferResult<'tcx, T> + where T: ToTrace<'tcx> + { + self.trace(expected, actual).glb(&expected, &actual) + } + + /// Sets the "trace" values that will be used for + /// error-repporting, but doesn't actually perform any operation + /// yet (this is useful when you want to set the trace using + /// distinct values from those you wish to operate upon). + pub fn trace(self, + expected: T, + actual: T) + -> Trace<'a, 'gcx, 'tcx> + where T: ToTrace<'tcx> + { + self.trace_exp(true, expected, actual) + } + + /// Like `trace`, but the expected value is determined by the + /// boolean argument (if true, then the first argument `a` is the + /// "expected" value). + pub fn trace_exp(self, + a_is_expected: bool, + a: T, + b: T) + -> Trace<'a, 'gcx, 'tcx> + where T: ToTrace<'tcx> + { + let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); + Trace { at: self, trace: trace, a_is_expected } + } +} + +impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { + /// Make `a <: b` where `a` may or may not be expected (if + /// `a_is_expected` is true, then `a` is expected). + /// Make `expected <: actual` + pub fn sub(self, + a: &T, + b: &T) + -> InferResult<'tcx, ()> + where T: Relate<'tcx> + { + debug!("sub({:?} <: {:?})", a, b); + let Trace { at, trace, a_is_expected } = self; + at.infcx.commit_if_ok(|_| { + let mut fields = at.infcx.combine_fields(trace, at.param_env); + fields.sub(a_is_expected) + .relate(a, b) + .map(move |_| InferOk { value: (), obligations: fields.obligations }) + }) + } + + /// Make `a == b`; the expectation is set by the call to + /// `trace()`. + pub fn eq(self, + a: &T, + b: &T) + -> InferResult<'tcx, ()> + where T: Relate<'tcx> + { + debug!("eq({:?} == {:?})", a, b); + let Trace { at, trace, a_is_expected } = self; + at.infcx.commit_if_ok(|_| { + let mut fields = at.infcx.combine_fields(trace, at.param_env); + fields.equate(a_is_expected) + .relate(a, b) + .map(move |_| InferOk { value: (), obligations: fields.obligations }) + }) + } + + pub fn lub(self, + a: &T, + b: &T) + -> InferResult<'tcx, T> + where T: Relate<'tcx> + { + debug!("lub({:?} \\/ {:?})", a, b); + let Trace { at, trace, a_is_expected } = self; + at.infcx.commit_if_ok(|_| { + let mut fields = at.infcx.combine_fields(trace, at.param_env); + fields.lub(a_is_expected) + .relate(a, b) + .map(move |t| InferOk { value: t, obligations: fields.obligations }) + }) + } + + pub fn glb(self, + a: &T, + b: &T) + -> InferResult<'tcx, T> + where T: Relate<'tcx> + { + debug!("glb({:?} /\\ {:?})", a, b); + let Trace { at, trace, a_is_expected } = self; + at.infcx.commit_if_ok(|_| { + let mut fields = at.infcx.combine_fields(trace, at.param_env); + fields.glb(a_is_expected) + .relate(a, b) + .map(move |t| InferOk { value: t, obligations: fields.obligations }) + }) + } +} + +impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: Types(ExpectedFound::new(a_is_expected, a, b)) + } + } +} + +impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) + } + } +} + +impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) + } + } +} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a16f7fb208175..f5869b8a20fab 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -31,7 +31,7 @@ use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::relate::{Relate, RelateResult, TypeRelation}; +use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{Cell, RefCell, Ref, RefMut}; @@ -49,6 +49,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; +pub mod at; mod combine; mod equate; pub mod error_reporting; @@ -802,62 +803,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn equate(&'a self, - a_is_expected: bool, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: &T, - b: &T) - -> InferResult<'tcx, T> - where T: Relate<'tcx> - { - let mut fields = self.combine_fields(trace, param_env); - let result = fields.equate(a_is_expected).relate(a, b); - result.map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - - pub fn sub(&'a self, - a_is_expected: bool, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: &T, - b: &T) - -> InferResult<'tcx, T> - where T: Relate<'tcx> - { - let mut fields = self.combine_fields(trace, param_env); - let result = fields.sub(a_is_expected).relate(a, b); - result.map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - - pub fn lub(&'a self, - a_is_expected: bool, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: &T, - b: &T) - -> InferResult<'tcx, T> - where T: Relate<'tcx> - { - let mut fields = self.combine_fields(trace, param_env); - let result = fields.lub(a_is_expected).relate(a, b); - result.map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - - pub fn glb(&'a self, - a_is_expected: bool, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: &T, - b: &T) - -> InferResult<'tcx, T> - where T: Relate<'tcx> - { - let mut fields = self.combine_fields(trace, param_env); - let result = fields.glb(a_is_expected).relate(a, b); - result.map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - // Clear the "currently in a snapshot" flag, invoke the closure, // then restore the flag to its original value. This flag is a // debugging measure designed to detect cases where we start a @@ -1017,102 +962,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.add_given(sub, sup); } - pub fn sub_types(&self, - a_is_expected: bool, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> InferResult<'tcx, ()> - { - debug!("sub_types({:?} <: {:?})", a, b); - self.commit_if_ok(|_| { - let trace = TypeTrace::types(cause, a_is_expected, a, b); - self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) - }) - } - - pub fn can_sub_types(&self, - param_env: ty::ParamEnv<'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> UnitResult<'tcx> + pub fn can_sub(&self, + param_env: ty::ParamEnv<'tcx>, + a: T, + b: T) + -> UnitResult<'tcx> + where T: at::ToTrace<'tcx> { + let origin = &ObligationCause::dummy(); self.probe(|_| { - let origin = &ObligationCause::dummy(); - let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, param_env, &a, &b).map(|InferOk { obligations: _, .. }| { + self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { // Ignore obligations, since we are unrolling // everything anyway. }) }) } - pub fn eq_types(&self, - a_is_expected: bool, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> InferResult<'tcx, ()> + pub fn can_eq(&self, + param_env: ty::ParamEnv<'tcx>, + a: T, + b: T) + -> UnitResult<'tcx> + where T: at::ToTrace<'tcx> { - self.commit_if_ok(|_| { - let trace = TypeTrace::types(cause, a_is_expected, a, b); - self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) - }) - } - - pub fn eq_trait_refs(&self, - a_is_expected: bool, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>) - -> InferResult<'tcx, ()> - { - debug!("eq_trait_refs({:?} = {:?})", a, b); - self.commit_if_ok(|_| { - let trace = TypeTrace { - cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) - }; - self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) - }) - } - - pub fn eq_impl_headers(&self, - a_is_expected: bool, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: &ty::ImplHeader<'tcx>, - b: &ty::ImplHeader<'tcx>) - -> InferResult<'tcx, ()> - { - debug!("eq_impl_header({:?} = {:?})", a, b); - match (a.trait_ref, b.trait_ref) { - (Some(a_ref), Some(b_ref)) => - self.eq_trait_refs(a_is_expected, cause, param_env, a_ref, b_ref), - (None, None) => - self.eq_types(a_is_expected, cause, param_env, a.self_ty, b.self_ty), - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), - } - } - - pub fn sub_poly_trait_refs(&self, - a_is_expected: bool, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - a: ty::PolyTraitRef<'tcx>, - b: ty::PolyTraitRef<'tcx>) - -> InferResult<'tcx, ()> - { - debug!("sub_poly_trait_refs({:?} <: {:?})", a, b); - self.commit_if_ok(|_| { - let trace = TypeTrace { - cause: cause, - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) - }; - self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit()) + let origin = &ObligationCause::dummy(); + self.probe(|_| { + self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. + }) }) } @@ -1134,7 +1012,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let cause_span = cause.span; - let eqty_ok = self.eq_types(false, cause, param_env, a, b)?; + let eqty_ok = self.at(cause, param_env).eq(b, a)?; self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(eqty_ok.unit()) @@ -1172,7 +1050,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.skolemize_late_bound_regions(predicate, snapshot); let cause_span = cause.span; - let ok = self.sub_types(a_is_expected, cause, param_env, a, b)?; + let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; self.leak_check(false, cause_span, &skol_map, snapshot)?; self.pop_skolemized(skol_map, snapshot); Ok(ok.unit()) @@ -1606,27 +1484,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bound); } - pub fn can_equate(&self, param_env: ty::ParamEnv<'tcx>, a: &T, b: &T) -> UnitResult<'tcx> - where T: Relate<'tcx> + fmt::Debug - { - debug!("can_equate({:?}, {:?})", a, b); - self.probe(|_| { - // Gin up a dummy trace, since this won't be committed - // anyhow. We should make this typetrace stuff more - // generic so we don't have to do anything quite this - // terrible. - let trace = TypeTrace::dummy(self.tcx); - self.equate(true, trace, param_env, a, b).map(|InferOk { obligations: _, .. }| { - // We can intentionally ignore obligations here, since - // this is part of a simple test for general - // "equatability". However, it's not entirely clear - // that we *ought* to be, perhaps a better thing would - // be to use a mini-fulfillment context or something - // like that. - }) - }) - } - pub fn node_ty(&self, id: ast::NodeId) -> McResult> { let ty = self.node_type(id); self.resolve_type_vars_or_error(&ty) diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index c7d069053e9d0..54fe3a42b6179 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -84,12 +84,9 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - let obligations = match selcx.infcx().eq_impl_headers(true, - &ObligationCause::dummy(), - param_env, - &a_impl_header, - &b_impl_header) { - Ok(InferOk { obligations, .. }) => { + let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env) + .eq_impl_headers(&a_impl_header, &b_impl_header) { + Ok(InferOk { obligations, value: () }) => { obligations } Err(_) => return None diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6635a1f1f271e..049d5e488c946 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -184,10 +184,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.cause.clone(), 0 ); - if let Err(error) = self.eq_types( - false, &obligation.cause, obligation.param_env, - data.ty, normalized.value - ) { + if let Err(error) = self.at(&obligation.cause, obligation.param_env) + .eq(normalized.value, data.ty) { values = Some(infer::ValuePairs::Types(ExpectedFound { expected: normalized.value, found: data.ty, @@ -269,7 +267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let impl_self_ty = impl_trait_ref.self_ty(); - if let Ok(..) = self.can_equate(param_env, &trait_self_ty, &impl_self_ty) { + if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { self_match_impls.push(def_id); if trait_ref.substs.types().skip(1) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index c155d1bf241b5..dbeaf46e8be0d 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -181,11 +181,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations); let infcx = selcx.infcx(); - match infcx.eq_types(true, - &obligation.cause, - obligation.param_env, - normalized_ty, - obligation.predicate.ty) { + match infcx.at(&obligation.cause, obligation.param_env) + .eq(normalized_ty, obligation.predicate.ty) { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); Ok(Some(obligations)) @@ -840,16 +837,13 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - infcx.sub_poly_trait_refs(false, - obligation.cause.clone(), - obligation.param_env, - data_poly_trait_ref, - obligation_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() + infcx.at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .map(|InferOk { obligations: _, value: () }| { + // FIXME(#32730) -- do we need to take obligations + // into account in any way? At the moment, no. + }) + .is_ok() }); debug!("assemble_candidates_from_predicates: candidate={:?} \ @@ -1110,11 +1104,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( let data_poly_trait_ref = data.to_poly_trait_ref(); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); selcx.infcx().probe(|_| { - selcx.infcx().sub_poly_trait_refs(false, - obligation.cause.clone(), - obligation.param_env, - data_poly_trait_ref, - obligation_poly_trait_ref).is_ok() + selcx.infcx().at(&obligation.cause, obligation.param_env) + .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .is_ok() }) }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 21d4df3d0990d..6ac26e413ce4a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1269,12 +1269,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> bool { assert!(!skol_trait_ref.has_escaping_regions()); - let cause = obligation.cause.clone(); - match self.infcx.sub_poly_trait_refs(false, - cause, - obligation.param_env, - trait_bound.clone(), - ty::Binder(skol_trait_ref.clone())) { + match self.infcx.at(&obligation.cause, obligation.param_env) + .sup(ty::Binder(skol_trait_ref), trait_bound) { Ok(InferOk { obligations, .. }) => { self.inferred_obligations.extend(obligations); } @@ -2436,11 +2432,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> Result<(), SelectionError<'tcx>> { let obligation_trait_ref = obligation_trait_ref.clone(); - self.infcx.sub_poly_trait_refs(false, - obligation_cause.clone(), - obligation_param_env, - expected_trait_ref.clone(), - obligation_trait_ref.clone()) + self.infcx + .at(&obligation_cause, obligation_param_env) + .sup(obligation_trait_ref, expected_trait_ref) .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } @@ -2475,12 +2469,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.eq_types(false, - &obligation.cause, - obligation.param_env, - new_trait, - target) - .map_err(|_| Unimplemented)?; + self.infcx.at(&obligation.cause, obligation.param_env) + .eq(target, new_trait) + .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); // Register one obligation for 'a: 'b. @@ -2540,8 +2531,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.eq_types(false, &obligation.cause, obligation.param_env, a, b) - .map_err(|_| Unimplemented)?; + self.infcx.at(&obligation.cause, obligation.param_env) + .eq(b, a) + .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2603,12 +2595,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.eq_types(false, - &obligation.cause, - obligation.param_env, - new_struct, - target) - .map_err(|_| Unimplemented)?; + self.infcx.at(&obligation.cause, obligation.param_env) + .eq(target, new_struct) + .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); // Construct the nested Field: Unsize> predicate. @@ -2696,15 +2685,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { skol_obligation_trait_ref); let InferOk { obligations, .. } = - self.infcx.eq_trait_refs(false, - &obligation.cause, - obligation.param_env, - impl_trait_ref.value.clone(), - skol_obligation_trait_ref) - .map_err(|e| { - debug!("match_impl: failed eq_trait_refs due to `{}`", e); - () - })?; + self.infcx.at(&obligation.cause, obligation.param_env) + .eq(skol_obligation_trait_ref, impl_trait_ref.value) + .map_err(|e| { + debug!("match_impl: failed eq_trait_refs due to `{}`", e); + () + })?; self.inferred_obligations.extend(obligations); if let Err(e) = self.infcx.leak_check(false, @@ -2770,13 +2756,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation, poly_trait_ref); - self.infcx.sub_poly_trait_refs(false, - obligation.cause.clone(), - obligation.param_env, - poly_trait_ref, - obligation.predicate.to_poly_trait_ref()) - .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) - .map_err(|_| ()) + self.infcx.at(&obligation.cause, obligation.param_env) + .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) + .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) + .map_err(|_| ()) } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0e9bf93cbd2d1..689f06a359730 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -228,11 +228,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - match infcx.eq_trait_refs(true, - &ObligationCause::dummy(), - param_env, - source_trait_ref, - target_trait_ref) { + match infcx.at(&ObligationCause::dummy(), param_env) + .eq(source_trait_ref, target_trait_ref) { Ok(InferOk { obligations: o, .. }) => { obligations.extend(o); } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index fb162f354e991..da8e3b5a42ba9 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -353,18 +353,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { infer_ok.value } - fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>) + fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.sub_types(false, &self.misc(self.last_span), self.param_env, sup, sub) - .map(|ok| self.register_infer_ok_obligations(ok)) + self.infcx.at(&self.misc(self.last_span), self.param_env) + .sup(sup, sub) + .map(|ok| self.register_infer_ok_obligations(ok)) } fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>) -> infer::UnitResult<'tcx> { - self.infcx.eq_types(false, &self.misc(span), self.param_env, a, b) - .map(|ok| self.register_infer_ok_obligations(ok)) + self.infcx.at(&self.misc(span), self.param_env) + .eq(b, a) + .map(|ok| self.register_infer_ok_obligations(ok)) } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index b1b4e099626cf..30ac7b4bfb9be 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -64,7 +64,7 @@ use check::{Diverges, FnCtxt}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; +use rustc::infer::{Coercion, InferResult, InferOk}; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; @@ -135,11 +135,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { - let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { - self.lub(false, trace, self.fcx.param_env, &a, &b) + self.at(&self.cause, self.fcx.param_env) + .lub(b, a) } else { - self.sub(false, trace, self.fcx.param_env, &a, &b) + self.at(&self.cause, self.fcx.param_env) + .sup(b, a) + .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) } }) } @@ -771,20 +773,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return Ok(prev_ty); } - let trace = TypeTrace::types(cause, true, prev_ty, new_ty); - // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. match (&prev_ty.sty, &new_ty.sty) { (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. - let fty = self.lub(true, trace.clone(), self.param_env, &a_fty, &b_fty) + let fty = self.at(cause, self.param_env) + .trace(prev_ty, new_ty) + .lub(&a_fty, &b_fty) .map(|ok| self.register_infer_ok_obligations(ok))?; if a_def_id == b_def_id { // Same function, maybe the parameters match. let substs = self.commit_if_ok(|_| { - self.lub(true, trace.clone(), self.param_env, &a_substs, &b_substs) + self.at(cause, self.param_env) + .trace(prev_ty, new_ty) + .lub(&a_substs, &b_substs) .map(|ok| self.register_infer_ok_obligations(ok)) }); @@ -853,7 +857,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !noop { return self.commit_if_ok(|_| { - self.lub(true, trace.clone(), self.param_env, &prev_ty, &new_ty) + self.at(cause, self.param_env) + .lub(prev_ty, new_ty) .map(|ok| self.register_infer_ok_obligations(ok)) }); } @@ -866,7 +871,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(e) } else { self.commit_if_ok(|_| { - self.lub(true, trace, self.param_env, &prev_ty, &new_ty) + self.at(cause, self.param_env) + .lub(prev_ty, new_ty) .map(|ok| self.register_infer_ok_obligations(ok)) }) } @@ -1109,7 +1115,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // Another example is `break` with no argument expression. assert!(expression_ty.is_nil()); assert!(expression_ty.is_nil(), "if let hack without unit type"); - fcx.eq_types(label_expression_as_expected, cause, fcx.param_env, expression_ty, self.merged_ty()) + fcx.at(cause, fcx.param_env) + .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty()) .map(|infer_ok| { fcx.register_infer_ok_obligations(infer_ok); expression_ty diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 50e7e89a5f61a..7633be24477c6 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -289,7 +289,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); - let sub_result = infcx.sub_types(false, &cause, param_env, impl_fty, trait_fty) + let sub_result = infcx.at(&cause, param_env) + .sup(trait_fty, impl_fty) .map(|InferOk { obligations, .. }| { inh.register_predicates(obligations); }); @@ -460,28 +461,23 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a impl_iter.zip(trait_iter) .zip(impl_m_iter) .zip(trait_m_iter) - .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, - &cause, - param_env, - trait_arg_ty, - impl_arg_ty) { + .filter_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| { + match infcx.at(&cause, param_env).sub(trait_arg_ty, impl_arg_ty) { Ok(_) => None, Err(_) => Some((impl_arg.span, Some(trait_arg.span))), } }) .next() .unwrap_or_else(|| { - if infcx.sub_types(false, - &cause, - param_env, - impl_sig.output(), - trait_sig.output()) - .is_err() { - (impl_m_output.span(), Some(trait_m_output.span())) - } else { - (cause.span, tcx.hir.span_if_local(trait_m.def_id)) - } + if + infcx.at(&cause, param_env) + .sup(trait_sig.output(), impl_sig.output()) + .is_err() + { + (impl_m_output.span(), Some(trait_m_output.span())) + } else { + (cause.span, tcx.hir.span_if_local(trait_m.def_id)) + } }) } else { (cause.span, tcx.hir.span_if_local(trait_m.def_id)) @@ -760,8 +756,9 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_const_impl: trait_ty={:?}", trait_ty); - let err = infcx.sub_types(false, &cause, param_env, impl_ty, trait_ty) - .map(|ok| inh.register_infer_ok_obligations(ok)); + let err = infcx.at(&cause, param_env) + .sup(trait_ty, impl_ty) + .map(|ok| inh.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 9c3dcc3f0e0eb..40d53b5e97991 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -26,8 +26,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let cause = self.misc(sp); - match self.sub_types(false, &cause, self.param_env, actual, expected) { + let cause = &self.misc(sp); + match self.at(cause, self.param_env).sup(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); }, @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> Option> { - match self.eq_types(false, cause, self.param_env, actual, expected) { + match self.at(cause, self.param_env).eq(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); None diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 024d1f09f1cf7..bff9289de5055 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -92,7 +92,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); - match infcx.eq_types(true, cause, impl_param_env, named_type, fresh_impl_self_ty) { + match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) { Ok(InferOk { obligations, .. }) => { fulfillment_cx.register_predicate_obligations(infcx, obligations); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a5cf4dd268304..c8815f3df5aa2 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { - match self.sub_types(false, &self.misc(self.span), self.param_env, self_ty, method_self_ty) { + match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 449c0f0281044..f975a83592362 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -679,7 +679,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let output = fty.output().subst(self.tcx, substs); let (output, _) = self.replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, &output); - self.can_sub_types(self.param_env, output, expected).is_ok() + self.can_sub(self.param_env, output, expected).is_ok() }) } _ => false, @@ -885,7 +885,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { substs, bound); - if self.can_equate(self.param_env, &step.self_ty, &bound.self_ty()).is_ok() { + if self.can_eq(self.param_env, step.self_ty, bound.self_ty()).is_ok() { let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs); debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}", @@ -1143,11 +1143,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. - let sub_obligations = match self.sub_types(false, - &ObligationCause::dummy(), - self.param_env, - self_ty, - probe.xform_self_ty) { + let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env) + .sup(probe.xform_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => obligations, Err(_) => { debug!("--> cannot relate self-types"); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 055ce94d20105..48afd91b23337 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2723,7 +2723,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = self.misc(call_span); - let ures = self.sub_types(false, &origin, self.param_env, formal_ret, ret_ty); + let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret); // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. @@ -4218,7 +4218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => return, }; let last_expr_ty = self.expr_ty(last_expr); - if self.can_sub_types(self.param_env, last_expr_ty, expected_ty).is_err() { + if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return; } let original_span = original_sp(last_stmt.span, blk.span); @@ -4478,7 +4478,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.sub_types(false, &self.misc(span), self.param_env, self_ty, impl_ty) { + match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { span_bug!(span, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index db817efe93d4a..d2475a2e5b2fa 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // check whether this predicate applies to our current projection let cause = self.fcx.misc(span); - match self.eq_types(false, &cause, self.fcx.param_env, ty, outlives.0) { + match self.at(&cause, self.fcx.param_env).eq(outlives.0, ty) { Ok(ok) => { self.register_infer_ok_obligations(ok); Ok(outlives.1) diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 8c2679f1bbf53..377b7b069d331 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -308,7 +308,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // we may have to evaluate constraint // expressions in the course of execution.) // See e.g. #41936. - if let Ok(ok) = infcx.eq_types(false, &cause, param_env, b, a) { + if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) { if ok.obligations.is_empty() { return None; } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ac0e360adb08a..06cb9f948c9b3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -158,7 +158,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.infer_ctxt(()).enter(|ref infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut fulfill_cx = FulfillmentContext::new(); - match infcx.eq_types(false, &cause, param_env, expected, actual) { + match infcx.at(&cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); } From af223fae27d2aa16743abadeb5635f8452a49894 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 May 2017 12:01:53 -0400 Subject: [PATCH 6/8] pacify the mercilous tidy --- src/librustc/traits/fulfill.rs | 12 ++++-- src/librustc/traits/project.rs | 5 ++- src/librustc/traits/select.rs | 4 +- src/librustc/ty/layout.rs | 48 +++++++++++++---------- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 5 ++- src/librustc_typeck/check/regionck.rs | 3 +- 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index daeb96e188d37..c2fe04534375f 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -420,7 +420,9 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(&obligation.cause, obligation.param_env, binder) { + match selcx.infcx().equality_predicate(&obligation.cause, + obligation.param_env, + binder) { Ok(InferOk { obligations, value: () }) => { Ok(Some(obligations)) }, @@ -508,7 +510,9 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(selcx.infcx(), obligation.param_env, obligation.cause.body_id, + match ty::wf::obligations(selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, ty, obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; @@ -519,7 +523,9 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::Subtype(ref subtype) => { - match selcx.infcx().subtype_predicate(&obligation.cause, obligation.param_env, subtype) { + match selcx.infcx().subtype_predicate(&obligation.cause, + obligation.param_env, + subtype) { None => { // none means that both are unresolved pending_obligation.stalled_on = vec![subtype.skip_binder().a, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index dbeaf46e8be0d..787452121d375 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -500,7 +500,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( cacheable); let result = if projected_ty.has_projection_types() { - let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth+1); + let mut normalizer = AssociatedTypeNormalizer::new(selcx, + param_env, + cause, + depth+1); let normalized_ty = normalizer.fold(&projected_ty); debug!("opt_normalize_projection_type: \ diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 6ac26e413ce4a..998201ad8d9ff 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -553,7 +553,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(self.infcx, obligation.param_env, obligation.cause.body_id, + match ty::wf::obligations(self.infcx, + obligation.param_env, + obligation.cause.body_id, ty, obligation.cause.span) { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index c37fb0f5a778d..12af56d5c3dfa 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1788,10 +1788,11 @@ impl<'a, 'tcx> Layout { Fields::WithDiscrim(s) => (s, &s.offsets[1..]), Fields::NoDiscrim(s) => (s, &s.offsets[0..]), }; - let field_info: Vec<_> = flds.iter() - .zip(field_offsets.iter()) - .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset)) - .collect(); + let field_info: Vec<_> = + flds.iter() + .zip(field_offsets.iter()) + .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset)) + .collect(); session::VariantInfo { name: n.map(|n|n.to_string()), @@ -1814,9 +1815,10 @@ impl<'a, 'tcx> Layout { debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}", ty, nndiscr, variant_layout); let variant_def = &adt_def.variants[nndiscr as usize]; - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); + let fields: Vec<_> = + variant_def.fields.iter() + .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) + .collect(); record(adt_kind.into(), None, vec![build_variant_info(Some(variant_def.name), @@ -1840,9 +1842,10 @@ impl<'a, 'tcx> Layout { "univariant with variants {:?}", variant_names()); if adt_def.variants.len() == 1 { let variant_def = &adt_def.variants[0]; - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); + let fields: Vec<_> = + variant_def.fields.iter() + .map(|f| (f.name, f.ty(tcx, substs))) + .collect(); record(adt_kind.into(), None, vec![build_variant_info(Some(variant_def.name), @@ -1858,17 +1861,20 @@ impl<'a, 'tcx> Layout { Layout::General { ref variants, discr, .. } => { debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}", ty, adt_def.variants.len(), variants.len(), variants); - let variant_infos: Vec<_> = adt_def.variants.iter() - .zip(variants.iter()) - .map(|(variant_def, variant_layout)| { - let fields: Vec<_> = variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); - build_variant_info(Some(variant_def.name), - &fields, - Fields::WithDiscrim(variant_layout)) - }) - .collect(); + let variant_infos: Vec<_> = + adt_def.variants.iter() + .zip(variants.iter()) + .map(|(variant_def, variant_layout)| { + let fields: Vec<_> = + variant_def.fields + .iter() + .map(|f| (f.name, f.ty(tcx, substs))) + .collect(); + build_variant_info(Some(variant_def.name), + &fields, + Fields::WithDiscrim(variant_layout)) + }) + .collect(); record(adt_kind.into(), Some(discr.size()), variant_infos); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f975a83592362..2518a1739f73e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1183,7 +1183,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds); // Convert the bounds into obligations. - let obligations = traits::predicates_for_generics(cause.clone(), self.param_env, &impl_bounds); + let obligations = traits::predicates_for_generics(cause.clone(), + self.param_env, + &impl_bounds); debug!("impl_obligations={:?}", obligations); // Evaluate those obligations to see if they might possibly hold. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 48afd91b23337..ccaf9b84a45ab 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1908,7 +1908,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> InferOk<'tcx, T> where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, self.param_env, value) + self.inh.normalize_associated_types_in_as_infer_ok(span, + self.body_id, + self.param_env, + value) } pub fn write_nil(&self, node_id: ast::NodeId) { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d2475a2e5b2fa..00b044a9beff7 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -386,7 +386,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { for &ty in fn_sig_tys { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={:?})", ty); - let implied_bounds = ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span); + let implied_bounds = + ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span); // Record any relations between free regions that we observe into the free-region-map. self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds); From 4c599bc198fd882331cf4721536b2ca8fe2893d2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 May 2017 16:15:04 -0400 Subject: [PATCH 7/8] fix librustc_driver tests --- src/librustc_driver/test.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 1d236a96bf62e..2b74d0a812b4a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -46,6 +46,7 @@ use rustc::hir; struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, region_maps: &'a mut RegionMaps, + param_env: ty::ParamEnv<'tcx>, } struct RH<'a> { @@ -153,9 +154,13 @@ fn test_env(source_string: &str, index, "test_crate", |tcx| { - tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { + tcx.infer_ctxt(()).enter(|infcx| { let mut region_maps = RegionMaps::new(); - body(Env { infcx: &infcx, region_maps: &mut region_maps }); + body(Env { + infcx: &infcx, + region_maps: &mut region_maps, + param_env: ty::ParamEnv::empty(Reveal::UserFacing), + }); let free_regions = FreeRegionMap::new(); let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID); infcx.resolve_regions_and_report_errors(def_id, ®ion_maps, &free_regions); @@ -250,14 +255,14 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) { + match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) { Ok(_) => true, Err(ref e) => panic!("Encountered error: {}", e), } } pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - self.infcx.can_sub_types(a, b).is_ok() + self.infcx.can_sub(self.param_env, a, b).is_ok() } pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) { @@ -354,30 +359,23 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.tcx().types.isize) } - pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> { - infer::TypeTrace::dummy(self.tcx()) - } - - pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { - let trace = self.dummy_type_trace(); - self.infcx.sub(true, trace, &t1, &t2) + pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> { + self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2) } pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { - let trace = self.dummy_type_trace(); - self.infcx.lub(true, trace, &t1, &t2) + self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2) } pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { - let trace = self.dummy_type_trace(); - self.infcx.glb(true, trace, &t1, &t2) + self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2) } /// Checks that `t1 <: t2` is true (this may register additional /// region checks). pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { match self.sub(t1, t2) { - Ok(InferOk { obligations, .. }) => { + Ok(InferOk { obligations, value: () }) => { // None of these tests should require nested obligations: assert!(obligations.is_empty()); } From 84047db2ade806b802f36d522ea82bd5d3cbb242 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 26 May 2017 19:20:54 -0400 Subject: [PATCH 8/8] fix ui reference --- src/test/ui/issue-26548.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/issue-26548.stderr b/src/test/ui/issue-26548.stderr index 8bfe4ac733b6d..c27ad7680a570 100644 --- a/src/test/ui/issue-26548.stderr +++ b/src/test/ui/issue-26548.stderr @@ -5,5 +5,5 @@ note: ...which then requires computing layout of `std::option::Option<::It`... = note: ...which then again requires computing layout of `S`, completing the cycle. -error: aborting due to previous error +error: aborting due to previous error(s)