diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 15c4469b74694..291d0d7c937ed 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -108,6 +108,10 @@ pub enum DepNode { SymbolName(D), SpecializationGraph(D), ObjectSafety(D), + IsCopy(D), + IsSized(D), + IsFreeze(D), + NeedsDrop(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 @@ -159,6 +163,7 @@ pub enum DepNode { // not a hotspot. ProjectionCache { def_ids: Vec }, + ParamEnv(D), DescribeDef(D), DefSpan(D), Stability(D), @@ -233,6 +238,10 @@ impl DepNode { // they are always absolute. WorkProduct(ref id) => Some(WorkProduct(id.clone())), + IsCopy(ref d) => op(d).map(IsCopy), + IsSized(ref d) => op(d).map(IsSized), + IsFreeze(ref d) => op(d).map(IsFreeze), + NeedsDrop(ref d) => op(d).map(NeedsDrop), Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), @@ -284,6 +293,7 @@ impl DepNode { let def_ids: Option> = def_ids.iter().map(op).collect(); def_ids.map(|d| ProjectionCache { def_ids: d }) } + ParamEnv(ref d) => op(d).map(ParamEnv), DescribeDef(ref d) => op(d).map(DescribeDef), DefSpan(ref d) => op(d).map(DefSpan), Stability(ref d) => op(d).map(Stability), diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1ecc277c7ca4d..270430f40df02 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -161,7 +161,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // For region variables. region_vars: RegionVarBindings<'a, 'gcx, 'tcx>, - pub parameter_environment: ty::ParameterEnvironment<'gcx>, + 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. @@ -406,41 +406,41 @@ pub trait InferEnv<'a, 'tcx> { fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>); + Option>); } impl<'a, 'tcx> InferEnv<'a, 'tcx> for () { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { + Option>) { (None, None, None) } } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParameterEnvironment<'tcx> { +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>) { + Option>) { (None, None, Some(self)) } } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParameterEnvironment<'tcx>) { +impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) { fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) -> (Option<&'a ty::TypeckTables<'tcx>>, Option>, - Option>) { + Option>) { (Some(self.0), None, Some(self.1)) } } -impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParameterEnvironment<'tcx>) { +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>) { + Option>) { (None, Some(self.0), Some(self.1)) } } @@ -449,11 +449,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>) { + Option>) { let def_id = tcx.hir.body_owner_def_id(self); (Some(tcx.typeck_tables_of(def_id)), None, - Some(tcx.parameter_environment(def_id))) + Some(tcx.param_env(def_id))) } } @@ -465,7 +465,7 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { arena: DroplessArena, fresh_tables: Option>>, tables: Option<&'a ty::TypeckTables<'gcx>>, - param_env: Option>, + param_env: Option>, projection_mode: Reveal, } @@ -498,7 +498,7 @@ 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), - parameter_environment: param_env.unwrap(), + param_env: param_env.unwrap(), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), @@ -526,9 +526,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { 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(|| { - global_tcx.empty_parameter_environment() - }); + let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty()); global_tcx.enter_local(arena, |tcx| f(InferCtxt { tcx: tcx, tables: tables, @@ -537,7 +535,7 @@ 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), - parameter_environment: param_env, + param_env: param_env, selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), reported_trait_errors: RefCell::new(FxHashSet()), @@ -650,7 +648,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } pub fn normalize_associated_type_in_env( - self, value: &T, env: &'a ty::ParameterEnvironment<'tcx> + self, value: &T, env: ty::ParamEnv<'tcx> ) -> T where T: TransNormalize<'tcx> { @@ -662,7 +660,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(env.clone(), Reveal::All).enter(|infcx| { + self.infer_ctxt(env, Reveal::All).enter(|infcx| { value.trans_normalize(&infcx) }) } @@ -1674,8 +1672,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } - pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> { - &self.parameter_environment + pub fn param_env(&self) -> ty::ParamEnv<'gcx> { + self.param_env } pub fn closure_kind(&self, diff --git a/src/librustc/traits/README.md b/src/librustc/traits/README.md index ff72f9dd07e36..c49df4b1ad9ea 100644 --- a/src/librustc/traits/README.md +++ b/src/librustc/traits/README.md @@ -418,16 +418,16 @@ before, and hence the cache lookup would succeed, yielding One subtle interaction is that the results of trait lookup will vary depending on what where clauses are in scope. Therefore, we actually have *two* caches, a local and a global cache. The local cache is -attached to the `ParameterEnvironment` and the global cache attached -to the `tcx`. We use the local cache whenever the result might depend -on the where clauses that are in scope. The determination of which -cache to use is done by the method `pick_candidate_cache` in -`select.rs`. At the moment, we use a very simple, conservative rule: -if there are any where-clauses in scope, then we use the local cache. -We used to try and draw finer-grained distinctions, but that led to a -serious of 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). +attached to the `ParamEnv` and the global cache attached to the +`tcx`. We use the local cache whenever the result might depend on the +where clauses that are in scope. The determination of which cache to +use is done by the method `pick_candidate_cache` in `select.rs`. At +the moment, we use a very simple, conservative rule: if there are any +where-clauses in scope, then we use the local cache. We used to try +and draw finer-grained distinctions, but that led to a serious of +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). # Specialization diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 1823373348bad..e358f39bd9a3a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -437,9 +437,9 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx /// Normalizes the parameter environment, reporting errors if they occur. pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, region_context: DefId, - unnormalized_env: ty::ParameterEnvironment<'tcx>, + unnormalized_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>) - -> ty::ParameterEnvironment<'tcx> + -> ty::ParamEnv<'tcx> { // I'm not wild about reporting errors here; I'd prefer to // have the errors get reported at a defined place (e.g., @@ -477,15 +477,15 @@ 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 = unnormalized_env.with_caller_bounds(tcx.intern_predicates(&predicates)); + let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates)); tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| { let predicates = match fully_normalize( &infcx, cause, - // You would really want to pass infcx.parameter_environment.caller_bounds here, + // 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 ParameterEnvironment in infcx, so we + // 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, @@ -494,7 +494,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Err(errors) => { infcx.report_fulfillment_errors(&errors); // An unnormalized env is better than nothing. - return infcx.parameter_environment; + return infcx.param_env; } }; @@ -516,19 +516,19 @@ 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.parameter_environment; + return infcx.param_env; } }; let predicates = match tcx.lift_to_global(&predicates) { Some(predicates) => predicates, - None => return infcx.parameter_environment + None => return infcx.param_env }; debug!("normalize_param_env_or_error: resolved predicates={:?}", predicates); - infcx.parameter_environment.with_caller_bounds(tcx.intern_predicates(&predicates)) + ty::ParamEnv::new(tcx.intern_predicates(&predicates)) }) } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index cccc20e5b296b..7366ed45f31bd 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -315,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'gcx> { + pub fn param_env(&self) -> ty::ParamEnv<'gcx> { self.infcx.param_env() } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0e5779f9d1793..e0f28e3b49e91 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -180,7 +180,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // create a parameter environment corresponding to a (skolemized) instantiation of impl1 - let penv = tcx.parameter_environment(impl1_def_id); + let penv = tcx.param_env(impl1_def_id); let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create a infcx, taking the predicates of impl1 as assumptions: @@ -250,7 +250,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, source_trait_ref, target_trait_ref, errors, - infcx.parameter_environment.caller_bounds); + infcx.param_env.caller_bounds); Err(()) } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b9355c264b3ef..5ee0b1c9e5ea4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -138,7 +138,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { let flags = super::flags::FlagComputation::for_sty(&st); let ty_struct = TyS { sty: st, - flags: Cell::new(flags.flags), + flags: flags.flags, region_depth: flags.depth, }; @@ -978,8 +978,8 @@ macro_rules! sty_debug_print { ty::TyError => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; - let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER); + let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); + let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); variant.total += 1; total.total += 1; diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 686b99ba68094..46afa6ee7d011 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -167,7 +167,7 @@ impl FlagComputation { } fn add_ty(&mut self, ty: Ty) { - self.add_flags(ty.flags.get()); + self.add_flags(ty.flags); self.add_depth(ty.region_depth); } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 6de3c018bda0e..c17a54f4f69bb 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -625,9 +625,8 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_ty(&mut self, t: Ty) -> bool { - let flags = t.flags.get(); - debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, flags, self.flags); - flags.intersects(self.flags) + debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags, self.flags); + t.flags.intersects(self.flags) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bd38a6c3fd39a..1a8c74ff1f943 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1079,7 +1079,7 @@ impl<'a, 'gcx, 'tcx> Layout { let ptr_layout = |pointee: Ty<'gcx>| { let non_zero = !ty.is_unsafe_ptr(); let pointee = infcx.normalize_projections(pointee); - if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { + if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { let unsized_part = tcx.struct_tail(pointee); @@ -1268,11 +1268,11 @@ impl<'a, 'gcx, 'tcx> Layout { let kind = if def.is_enum() || def.variants[0].fields.len() == 0{ StructKind::AlwaysSizedUnivariant } else { - let param_env = tcx.parameter_environment(def.did); + let param_env = tcx.param_env(def.did); let fields = &def.variants[0].fields; let last_field = &fields[fields.len()-1]; let always_sized = tcx.type_of(last_field.did) - .is_sized(tcx, ¶m_env, DUMMY_SP); + .is_sized(tcx, param_env, DUMMY_SP); if !always_sized { StructKind::MaybeUnsizedUnivariant } else { StructKind::AlwaysSizedUnivariant } }; diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 85462bd9b1273..fb352e5be8938 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; -use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use hir::def::Def; use hir; use middle::const_val; @@ -136,6 +136,15 @@ impl Key for (MirSuite, MirPassIndex, DefId) { } } +impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -244,6 +253,30 @@ impl> QueryDescription for M { } } +impl<'tcx> QueryDescription for queries::is_copy_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `Copy`", env.value) + } +} + +impl<'tcx> QueryDescription for queries::is_sized_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `Sized`", env.value) + } +} + +impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is freeze", env.value) + } +} + +impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` needs drop", env.value) + } +} + impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", @@ -856,6 +889,15 @@ define_maps! { <'tcx> -> ty::trait_def::TraitImpls, [] specialization_graph_of: SpecializationGraph(DefId) -> Rc, [] is_object_safe: ObjectSafety(DefId) -> bool, + + [] param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, + + // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, + // `ty.is_copy()`, etc, since that will prune the environment where possible. + [] is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] 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, } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -899,3 +941,27 @@ fn crate_variances(_: CrateNum) -> DepNode { fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode { DepNode::TraitImpls(def_id) } + +fn is_copy_dep_node<'tcx>(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::IsCopy(def_id) +} + +fn is_sized_dep_node<'tcx>(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::IsSized(def_id) +} + +fn is_freeze_dep_node<'tcx>(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::IsFreeze(def_id) +} + +fn needs_drop_dep_node<'tcx>(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::NeedsDrop(def_id) +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 359722ce96ec9..fa731f6dde638 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -35,7 +35,6 @@ use util::common::ErrorReported; use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; -use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; use std::cmp; use std::fmt; @@ -503,22 +502,12 @@ bitflags! { TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits, - - // Caches for type_is_sized, type_moves_by_default - const SIZEDNESS_CACHED = 1 << 16, - const IS_SIZED = 1 << 17, - const MOVENESS_CACHED = 1 << 18, - const MOVES_BY_DEFAULT = 1 << 19, - const FREEZENESS_CACHED = 1 << 20, - const IS_FREEZE = 1 << 21, - const NEEDS_DROP_CACHED = 1 << 22, - const NEEDS_DROP = 1 << 23, } } pub struct TyS<'tcx> { pub sty: TypeVariants<'tcx>, - pub flags: Cell, + pub flags: TypeFlags, // the maximal depth of any bound regions appearing in this type. region_depth: u32, @@ -1249,46 +1238,58 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -/// When type checking, we use the `ParameterEnvironment` to track -/// details about the type/lifetime parameters that are in scope. -/// It primarily stores the bounds information. -/// -/// Note: This information might seem to be redundant with the data in -/// `tcx.ty_param_defs`, but it is not. That table contains the -/// parameter definitions from an "outside" perspective, but this -/// struct will contain the bounds for a parameter as seen from inside -/// the function body. Currently the only real distinction is that -/// bound lifetime parameters are replaced with free ones, but in the -/// future I hope to refine the representation of types so as to make -/// more distinctions clearer. -#[derive(Clone)] -pub struct ParameterEnvironment<'tcx> { +/// When type checking, we use the `ParamEnv` to track +/// details about the set of where-clauses that are in scope at this +/// particular point. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ParamEnv<'tcx> { /// Obligations that the caller must satisfy. This is basically /// the set of bounds on the in-scope type parameters, translated /// into Obligations, and elaborated and normalized. - pub caller_bounds: &'tcx [ty::Predicate<'tcx>], - - /// A cache for `moves_by_default`. - pub is_copy_cache: RefCell, bool>>, + pub caller_bounds: &'tcx Slice>, +} - /// A cache for `type_is_sized` - pub is_sized_cache: RefCell, bool>>, +impl<'tcx> ParamEnv<'tcx> { + /// Creates a suitable environment in which to perform trait + /// queries on the given value. This will either be `self` *or* + /// the empty environment, depending on whether `value` references + /// type parameters that are in scope. (If it doesn't, then any + /// judgements should be completely independent of the context, + /// and hence we can safely use the empty environment so as to + /// enable more sharing across functions.) + /// + /// NB: This is a mildly dubious thing to do, in that a function + /// (or other environment) might have wacky where-clauses like + /// `where Box: Copy`, which are clearly never + /// satisfiable. The code will at present ignore these, + /// effectively, when type-checking the body of said + /// function. This preserves existing behavior in any + /// case. --nmatsakis + pub fn and>(self, value: T) -> ParamEnvAnd<'tcx, T> { + assert!(!value.needs_infer()); + if value.has_param_types() || value.has_self_ty() { + ParamEnvAnd { + param_env: self, + value: value, + } + } else { + ParamEnvAnd { + param_env: ParamEnv::empty(), + value: value, + } + } + } +} - /// A cache for `type_is_freeze` - pub is_freeze_cache: RefCell, bool>>, +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ParamEnvAnd<'tcx, T> { + pub param_env: ParamEnv<'tcx>, + pub value: T, } -impl<'a, 'tcx> ParameterEnvironment<'tcx> { - pub fn with_caller_bounds(&self, - caller_bounds: &'tcx [ty::Predicate<'tcx>]) - -> ParameterEnvironment<'tcx> - { - ParameterEnvironment { - caller_bounds: caller_bounds, - is_copy_cache: RefCell::new(FxHashMap()), - is_sized_cache: RefCell::new(FxHashMap()), - is_freeze_cache: RefCell::new(FxHashMap()), - } +impl<'tcx, T> ParamEnvAnd<'tcx, T> { + pub fn into_parts(self) -> (ParamEnv<'tcx>, T) { + (self.param_env, self.value) } } @@ -2357,54 +2358,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Construct a parameter environment suitable for static contexts or other contexts where there - /// are no free type/lifetime parameters in scope. - pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { - ty::ParameterEnvironment { - caller_bounds: Slice::empty(), - is_copy_cache: RefCell::new(FxHashMap()), - is_sized_cache: RefCell::new(FxHashMap()), - is_freeze_cache: RefCell::new(FxHashMap()), - } - } - - /// See `ParameterEnvironment` struct def'n for details. - pub fn parameter_environment(self, def_id: DefId) -> ParameterEnvironment<'gcx> { - // - // Compute the bounds on Self and the type parameters. - // - - let tcx = self.global_tcx(); - let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); - let predicates = bounds.predicates; - - // Finally, we have to normalize the bounds in the environment, in - // case they contain any associated type projections. This process - // can yield errors if the put in illegal associated types, like - // `::Bar` where `i32` does not implement `Foo`. We - // report these errors right here; this doesn't actually feel - // right to me, because constructing the environment feels like a - // kind of a "idempotent" action, but I'm not sure where would be - // a better place. In practice, we construct environments for - // every fn once during type checking, and we'll abort if there - // 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::ParameterEnvironment { - caller_bounds: tcx.intern_predicates(&predicates), - is_copy_cache: RefCell::new(FxHashMap()), - is_sized_cache: RefCell::new(FxHashMap()), - is_freeze_cache: RefCell::new(FxHashMap()), - }; - - let body_id = self.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| { - self.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id) - }); - let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); - traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) - } - pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> { self.mk_region(ty::ReScope(CodeExtent::Misc(id))) } @@ -2564,14 +2517,45 @@ 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> { + // Compute the bounds on Self and the type parameters. + + let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); + let predicates = bounds.predicates; + + // Finally, we have to normalize the bounds in the environment, in + // case they contain any associated type projections. This process + // can yield errors if the put in illegal associated types, like + // `::Bar` where `i32` does not implement `Foo`. We + // report these errors right here; this doesn't actually feel + // right to me, because constructing the environment feels like a + // kind of a "idempotent" action, but I'm not sure where would be + // a better place. In practice, we construct environments for + // every fn once during type checking, and we'll abort if there + // 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 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) + }); + let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); + traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) +} pub fn provide(providers: &mut ty::maps::Providers) { + util::provide(providers); *providers = ty::maps::Providers { associated_item, associated_item_def_ids, adt_sized_constraint, adt_dtorck_constraint, def_span, + param_env, trait_of_item, trait_impls_of: trait_def::trait_impls_of_provider, relevant_trait_impls_for: trait_def::relevant_trait_impls_provider, @@ -2585,6 +2569,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { adt_dtorck_constraint, trait_impls_of: trait_def::trait_impls_of_provider, relevant_trait_impls_for: trait_def::relevant_trait_impls_provider, + param_env, ..*providers }; } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c6c6a0e47003d..01fed11fc97af 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -15,20 +15,17 @@ use hir::map::DefPathData; use infer::InferCtxt; use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; -use ty::ParameterEnvironment; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; -use util::nodemap::{FxHashMap, FxHashSet}; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; -use std::cell::RefCell; use std::cmp; use std::hash::Hash; use std::intrinsics; @@ -36,8 +33,6 @@ use syntax::ast::{self, Name}; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; -use hir; - type Disr = ConstInt; pub trait IntTypeExt { @@ -152,7 +147,18 @@ pub enum Representability { SelfRecursive(Vec), } -impl<'tcx> ParameterEnvironment<'tcx> { +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()) + } + + /// 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 can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type: Ty<'tcx>, span: Span) -> Result<(), CopyImplementationError> { @@ -711,152 +717,28 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> } impl<'a, 'tcx> ty::TyS<'tcx> { - fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - def_id: DefId, - cache: &RefCell, bool>>, - span: Span) -> bool - { - if self.has_param_types() || self.has_self_ty() { - if let Some(result) = cache.borrow().get(self) { - return *result; - } - } - let result = - tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing) - .enter(|infcx| { - traits::type_known_to_meet_bound(&infcx, self, def_id, span) - }); - if self.has_param_types() || self.has_self_ty() { - cache.borrow_mut().insert(self, result); - } - return result; - } - - // FIXME (@jroesch): I made this public to use it, not sure if should be private - pub fn moves_by_default(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - span: Span) -> bool { - if self.flags.get().intersects(TypeFlags::MOVENESS_CACHED) { - return self.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT); - } - - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyNever | - TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { - mutbl: hir::MutImmutable, .. - }) => Some(false), - - TyStr | TyRef(_, TypeAndMut { - mutbl: hir::MutMutable, .. - }) => Some(true), - - TyArray(..) | TySlice(..) | TyDynamic(..) | TyTuple(..) | - TyClosure(..) | TyAdt(..) | TyAnon(..) | - TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None - }.unwrap_or_else(|| { - !self.impls_bound(tcx, param_env, - tcx.require_lang_item(lang_items::CopyTraitLangItem), - ¶m_env.is_copy_cache, span) }); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT - } else { - TypeFlags::MOVENESS_CACHED - }); - } - - result + pub fn moves_by_default(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span) + -> bool { + !tcx.at(span).is_copy_raw(param_env.and(self)) } - #[inline] - pub fn is_sized(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - span: Span) -> bool + pub fn is_sized(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span)-> bool { - if self.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) { - return self.flags.get().intersects(TypeFlags::IS_SIZED); - } - - self.is_sized_uncached(tcx, param_env, span) - } - - fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - span: Span) -> bool { - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true), - - TyStr | TyDynamic(..) | TySlice(_) => Some(false), - - TyAdt(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyAnon(..) | TyError => None - }.unwrap_or_else(|| { - self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::SizedTraitLangItem), - ¶m_env.is_sized_cache, span) }); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED - } else { - TypeFlags::SIZEDNESS_CACHED - }); - } - - result + tcx.at(span).is_sized_raw(param_env.and(self)) } - /// Returns `true` if and only if there are no `UnsafeCell`s - /// nested within the type (ignoring `PhantomData` or pointers). - #[inline] - pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - span: Span) -> bool + pub fn is_freeze(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span)-> bool { - if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) { - return self.flags.get().intersects(TypeFlags::IS_FREEZE); - } - - self.is_freeze_uncached(tcx, param_env, span) - } - - fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>, - span: Span) -> bool { - assert!(!self.needs_infer()); - - // Fast-path for primitive types - let result = match self.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyStr | TyNever => Some(true), - - TyArray(..) | TySlice(_) | - TyTuple(..) | TyClosure(..) | TyAdt(..) | - TyDynamic(..) | TyProjection(..) | TyParam(..) | - TyInfer(..) | TyAnon(..) | TyError => None - }.unwrap_or_else(|| { - self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem), - ¶m_env.is_freeze_cache, span) }); - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE - } else { - TypeFlags::FREEZENESS_CACHED - }); - } - - result + tcx.at(span).is_freeze_raw(param_env.and(self)) } /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely @@ -866,112 +748,11 @@ impl<'a, 'tcx> ty::TyS<'tcx> { /// (Note that this implies that if `ty` has a destructor attached, /// then `needs_drop` will definitely return `true` for `ty`.) #[inline] - pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>) -> bool { - if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::NEEDS_DROP); - } - - self.needs_drop_uncached(tcx, param_env, &mut FxHashSet()) - } - - fn needs_drop_inner(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>, - stack: &mut FxHashSet>) - -> bool { - if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::NEEDS_DROP); - } - - // This should be reported as an error by `check_representable`. - // - // Consider the type as not needing drop in the meanwhile to avoid - // further errors. - if let Some(_) = stack.replace(self) { - return false; - } - - let needs_drop = self.needs_drop_uncached(tcx, param_env, stack); - - // "Pop" the cycle detection "stack". - stack.remove(self); - - needs_drop - } - - fn needs_drop_uncached(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>, - stack: &mut FxHashSet>) - -> bool { - assert!(!self.needs_infer()); - - let result = match self.sty { - // Fast-path for primitive types - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | - ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, - - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false, - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking for the structural "may drop". - - // FIXME(#22815): Note that this is a conservative heuristic; - // it may report that the type "may drop" when actual type does - // not actually have a destructor associated with it. But since - // the type absolutely did not have the `Copy` bound attached - // (see above), it is sound to treat it as having a destructor. - - // User destructors are the only way to have concrete drop types. - ty::TyAdt(def, _) if def.has_dtor(tcx) => true, - - // Can refer to a type which may drop. - // FIXME(eddyb) check this against a ParameterEnvironment. - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | - ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, - - // Structural recursion. - ty::TyArray(ty, _) | ty::TySlice(ty) => { - ty.needs_drop_inner(tcx, param_env, stack) - } - - ty::TyClosure(def_id, ref substs) => { - substs.upvar_tys(def_id, tcx) - .any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) - } - - ty::TyTuple(ref tys, _) => { - tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) - } - - // unions don't have destructors regardless of the child types - ty::TyAdt(def, _) if def.is_union() => false, - - ty::TyAdt(def, substs) => { - def.variants.iter().any(|v| { - v.fields.iter().any(|f| { - f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack) - }) - }) - } - }; - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP - } else { - TypeFlags::NEEDS_DROP_CACHED - }); - } - - result + pub fn needs_drop(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> bool { + tcx.needs_drop_raw(param_env.and(self)) } #[inline] @@ -1158,3 +939,112 @@ impl<'a, 'tcx> ty::TyS<'tcx> { r } } + +fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + 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) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) +} + +fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + 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) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) +} + +fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + 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) + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) +} + +fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + let (param_env, ty) = query.into_parts(); + + let needs_drop = |ty: Ty<'tcx>| -> bool { + match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) { + Ok(v) => v, + Err(_) => { + // Cycles should be reported as an error by `check_representable`. + // + // Consider the type as not needing drop in the meanwhile to avoid + // further errors. + false + } + } + }; + + assert!(!ty.needs_infer()); + + match ty.sty { + // Fast-path for primitive types + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + + // User destructors are the only way to have concrete drop types. + ty::TyAdt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParamEnv. + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | + ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, + + // Structural recursion. + ty::TyArray(ty, _) | ty::TySlice(ty) => needs_drop(ty), + + ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), + + ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop), + + // unions don't have destructors regardless of the child types + ty::TyAdt(def, _) if def.is_union() => false, + + ty::TyAdt(def, substs) => + def.variants.iter().any( + |variant| variant.fields.iter().any( + |field| needs_drop(field.ty(tcx, substs)))), + } +} + + +pub fn provide(providers: &mut ty::maps::Providers) { + *providers = ty::maps::Providers { + is_copy_raw, + is_sized_raw, + is_freeze_raw, + needs_drop_raw, + ..*providers + }; +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8ca699339d36e..340e4f2cfccbc 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -504,13 +504,7 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ParameterEnvironment({:?})", self.caller_bounds) - } -} - -impl<'tcx> fmt::Display for ty::RegionKind { +impl fmt::Display for ty::RegionKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if verbose() { return write!(f, "{:?}", *self); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index eeb5a3fb957fa..722ec6424fece 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::ParameterEnvironment<'tcx>, + param_env: &'a ty::ParamEnv<'tcx>, } impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { @@ -197,7 +197,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, dfcx_loans: dfcx_loans, move_data: move_data, all_loans: all_loans, - param_env: &infcx.parameter_environment + param_env: &infcx.param_env }; euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body); } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 520a90d940b39..e0d86ff23f862 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -44,8 +44,8 @@ impl MirPass for ElaborateDrops { _ => return } let id = src.item_id(); - let param_env = tcx.parameter_environment(tcx.hir.local_def_id(id)); - let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); + let param_env = tcx.param_env(tcx.hir.local_def_id(id)); + let move_data = MoveData::gather_moves(mir, tcx, param_env); let elaborate_patch = { let mir = &*mir; let env = MoveDataParamEnv { @@ -196,7 +196,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { self.ctxt.tcx } - fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.ctxt.param_env() } @@ -289,8 +289,9 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn move_data(&self) -> &'b MoveData<'tcx> { &self.env.move_data } - fn param_env(&self) -> &'b ty::ParameterEnvironment<'tcx> { - &self.env.param_env + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.env.param_env } fn initialization_data_at(&self, loc: Location) -> InitializationData { diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index ed5e539f245f1..931cdf4f68612 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,7 +9,7 @@ // except according to those terms. -use rustc::ty::{self, TyCtxt, ParameterEnvironment}; +use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec}; @@ -191,7 +191,7 @@ pub struct MovePathLookup<'tcx> { struct MoveDataBuilder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &'a ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, data: MoveData<'tcx>, } @@ -203,7 +203,7 @@ pub enum MovePathError { impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &'a ParameterEnvironment<'tcx>) + param_env: ty::ParamEnv<'tcx>) -> Self { let mut move_paths = IndexVec::new(); let mut path_map = IndexVec::new(); @@ -370,7 +370,7 @@ impl<'tcx> MovePathLookup<'tcx> { impl<'a, 'tcx> MoveData<'tcx> { pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>) + param_env: ty::ParamEnv<'tcx>) -> Self { gather_moves(mir, tcx, param_env) } @@ -378,7 +378,7 @@ impl<'a, 'tcx> MoveData<'tcx> { fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ParameterEnvironment<'tcx>) + param_env: ty::ParamEnv<'tcx>) -> MoveData<'tcx> { let mut builder = MoveDataBuilder::new(mir, tcx, param_env); diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index fbaa60f84450b..2eb064305e87c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -51,7 +51,7 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option pub struct MoveDataParamEnv<'tcx> { move_data: MoveData<'tcx>, - param_env: ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, } pub fn borrowck_mir(bcx: &mut BorrowckCtxt, @@ -65,8 +65,8 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt, // steals it, but it forces the `borrowck` query. let mir = &tcx.mir_validated(def_id).borrow(); - let param_env = tcx.parameter_environment(def_id); - let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); + let param_env = tcx.param_env(def_id); + let move_data = MoveData::gather_moves(mir, tcx, param_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let flow_inits = @@ -325,7 +325,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>( let ty = lvalue.ty(mir, tcx).to_ty(tcx); debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); - if ty.needs_drop(tcx, &ctxt.param_env) { + if ty.needs_drop(tcx, ctxt.param_env) { each_child(child); } else { debug!("on_all_drop_children_bits - skipping") @@ -359,7 +359,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( where F: FnMut(MovePathIndex, DropFlagState) { let move_data = &ctxt.move_data; - let param_env = &ctxt.param_env; + let param_env = ctxt.param_env; debug!("drop_flag_effects_for_location({:?})", loc); // first, move out of the RHS diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index c28d45be18d9e..f7c20542cbf2e 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -535,7 +535,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { lp: &LoanPath<'tcx>, the_move: &move_data::Move, moved_lp: &LoanPath<'tcx>, - _param_env: &ty::ParameterEnvironment<'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 a18f91a9ee391..7ed5f620816e1 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> { tcx: self.tcx, tables: self.tcx.body_tables(b), region_maps: &self.tcx.region_maps(def_id), - param_env: &self.tcx.parameter_environment(def_id) + param_env: self.tcx.param_env(def_id) }.visit_body(self.tcx.hir.body(b)); } } @@ -69,7 +69,7 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn struct MatchVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, - param_env: &'a ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, region_maps: &'a RegionMaps, } @@ -518,7 +518,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.clone()), Reveal::UserFacing).enter(|infcx| { + cx.tcx.infer_ctxt((cx.tables, cx.param_env), Reveal::UserFacing).enter(|infcx| { let mut checker = MutationChecker { cx: cx, }; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6423d65a4c23f..39b8e568ab48d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -527,13 +527,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if def.has_dtor(cx.tcx) { return; } - let parameter_environment = cx.tcx.empty_parameter_environment(); - // FIXME (@jroesch) should probably inver this so that the parameter env still impls this - // method - if !ty.moves_by_default(cx.tcx, ¶meter_environment, item.span) { + let param_env = ty::ParamEnv::empty(); + if !ty.moves_by_default(cx.tcx, param_env, item.span) { return; } - if parameter_environment.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() { + if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() { cx.span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, "type could implement `Copy`; consider adding `impl \ @@ -990,7 +988,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), trait_ref.to_poly_trait_predicate()); - let param_env = tcx.parameter_environment(method.def_id); + let param_env = tcx.param_env(method.def_id); tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { @@ -1258,7 +1256,8 @@ impl LintPass for UnionsWithDropFields { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { - let param_env = &ctx.tcx.parameter_environment(ctx.tcx.hir.local_def_id(item.id)); + let item_def_id = ctx.tcx.hir.local_def_id(item.id); + let param_env = ctx.tcx.param_env(item_def_id); for field in vdata.fields() { let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); if field_ty.needs_drop(ctx.tcx, param_env) { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index fb173e2487bff..9e151596a1ab5 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -172,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.parameter_environment(tcx.hir.local_def_id(ctor_id)); + let pe = tcx.param_env(tcx.hir.local_def_id(ctor_id)); tcx.infer_ctxt(pe, Reveal::UserFacing).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 9ffce18fe150e..f61e2545f71fe 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -168,7 +168,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { type with inference types/regions", ty); }); - ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment) + ty.needs_drop(self.tcx.global_tcx(), self.infcx.param_env) } pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 6f4480bf6dd16..428685d7f5058 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -40,8 +40,6 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, -> &'tcx Mir<'tcx> { debug!("make_shim({:?})", instance); - let did = instance.def_id(); - let param_env = tcx.parameter_environment(did); let mut result = match instance { ty::InstanceDef::Item(..) => @@ -98,7 +96,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ) } ty::InstanceDef::DropGlue(def_id, ty) => { - build_drop_shim(tcx, ¶m_env, def_id, ty) + build_drop_shim(tcx, def_id, ty) } ty::InstanceDef::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) @@ -144,7 +142,6 @@ fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>, span: Span) } fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>, def_id: DefId, ty: Option>) -> Mir<'tcx> @@ -189,10 +186,12 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, if let Some(..) = ty { let patch = { + let param_env = tcx.param_env(def_id); let mut elaborator = DropShimElaborator { mir: &mir, patch: MirPatch::new(&mir), - tcx, param_env + tcx, + param_env }; let dropee = Lvalue::Local(Local::new(1+0)).deref(); let resume_block = elaborator.patch.resume_block(); @@ -218,7 +217,7 @@ pub struct DropShimElaborator<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, patch: MirPatch<'tcx>, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - param_env: &'a ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { @@ -233,7 +232,7 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch } fn mir(&self) -> &'a Mir<'tcx> { self.mir } fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx } - fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx> { self.param_env } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle { if let DropFlagMode::Shallow = mode { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index e6d62dc646072..edb2f44d18e35 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -220,7 +220,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // FIXME: Give a bonus to functions with only a single caller let def_id = tcx.hir.local_def_id(self.source.item_id()); - let param_env = tcx.parameter_environment(def_id); + let param_env = tcx.param_env(def_id); let mut first_block = true; let mut cost = 0; @@ -253,7 +253,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { // a regular goto. let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); let ty = ty.to_ty(tcx); - if ty.needs_drop(tcx, ¶m_env) { + if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { work_list.push(unwind); @@ -545,7 +545,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } -fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'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| { ty.layout(&infcx).ok().map(|layout| { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 72edf68f4034c..4e84cbe6fecb1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> Qualif { /// Remove flags which are impossible for the given type. fn restrict(&mut self, ty: Ty<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: &ty::ParameterEnvironment<'tcx>) { + param_env: ty::ParamEnv<'tcx>) { if ty.is_freeze(tcx, param_env, DUMMY_SP) { *self = *self - Qualif::MUTABLE_INTERIOR; } @@ -128,7 +128,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { mir: &'a Mir<'tcx>, rpo: ReversePostorder<'a, 'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, temp_qualif: IndexVec>, return_qualif: Option, qualif: Qualif, @@ -139,7 +139,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, def_id: DefId, mir: &'a Mir<'tcx>, mode: Mode) @@ -193,7 +193,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// Add the given type's qualification to self.qualif. fn add_type(&mut self, ty: Ty<'tcx>) { self.add(Qualif::MUTABLE_INTERIOR | Qualif::NEEDS_DROP); - self.qualif.restrict(ty, self.tcx, &self.param_env); + self.qualif.restrict(ty, self.tcx, self.param_env); } /// Within the provided closure, self.qualif will start @@ -544,7 +544,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { static, use a constant instead"); } let ty = lvalue.ty(this.mir, this.tcx).to_ty(this.tcx); - this.qualif.restrict(ty, this.tcx, &this.param_env); + this.qualif.restrict(ty, this.tcx, this.param_env); } ProjectionElem::ConstantIndex {..} | @@ -937,7 +937,7 @@ fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return Qualif::NOT_CONST.bits(); } - let param_env = tcx.parameter_environment(def_id); + let param_env = tcx.param_env(def_id); let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const); qualifier.qualify_const().bits() @@ -965,7 +965,7 @@ impl MirPass for QualifyAndPromoteConstants { MirSource::Const(_) | MirSource::Promoted(..) => return }; - let param_env = tcx.parameter_environment(def_id); + let param_env = tcx.param_env(def_id); if mode == Mode::Fn || mode == Mode::ConstFn { // This is ugly because Qualifier holds onto mir, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 82c0d2c1b01c6..6d9603ea459d4 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -751,7 +751,7 @@ impl MirPass for TypeckMir { // broken MIR, so try not to report duplicate errors. return; } - let param_env = tcx.parameter_environment(def_id); + let param_env = tcx.param_env(def_id); tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { let mut checker = TypeChecker::new(&infcx, item_id); { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 9d7c7ec63cfc5..585840ce1e509 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -56,7 +56,7 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug { fn patch(&mut self) -> &mut MirPatch<'tcx>; fn mir(&self) -> &'a Mir<'tcx>; fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx>; - fn param_env(&self) -> &'a ty::ParameterEnvironment<'tcx>; + fn param_env(&self) -> ty::ParamEnv<'tcx>; fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle; fn get_drop_flag(&mut self, path: Self::Path) -> Option>; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index a0998b1bd1bfb..25845c5768e8c 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -58,7 +58,7 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> { in_fn: bool, promotable: bool, mut_rvalue_borrows: NodeSet, - param_env: ty::ParameterEnvironment<'tcx>, + param_env: ty::ParamEnv<'tcx>, tables: &'a ty::TypeckTables<'tcx>, } @@ -85,11 +85,11 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { // Adds the worst effect out of all the values of one type. fn add_type(&mut self, ty: Ty<'gcx>) { - if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) { + if !ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) { self.promotable = false; } - if ty.needs_drop(self.tcx, &self.param_env) { + if ty.needs_drop(self.tcx, self.param_env) { self.promotable = false; } } @@ -139,7 +139,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { - let param_env = infcx.parameter_environment.clone(); + 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);; euv::ExprUseVisitor::new(self, region_maps, &infcx).consume_body(body); @@ -466,7 +466,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { in_fn: false, promotable: false, mut_rvalue_borrows: NodeSet(), - param_env: tcx.empty_parameter_environment(), + param_env: ty::ParamEnv::empty(), }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c2f2c63790a4c..0dece586c930d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -79,7 +79,6 @@ impl Stats { pub struct SharedCrateContext<'a, 'tcx: 'a> { exported_symbols: NodeSet, tcx: TyCtxt<'a, 'tcx, 'tcx>, - empty_param_env: ty::ParameterEnvironment<'tcx>, check_overflow: bool, use_dll_storage_attrs: bool, @@ -315,7 +314,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { SharedCrateContext { exported_symbols: exported_symbols, - empty_param_env: tcx.empty_parameter_environment(), tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, @@ -323,15 +321,15 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx, &self.empty_param_env) + ty.needs_drop(self.tcx, ty::ParamEnv::empty()) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP) + ty.is_sized(self.tcx, ty::ParamEnv::empty(), DUMMY_SP) } pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP) + ty.is_freeze(self.tcx, ty::ParamEnv::empty(), DUMMY_SP) } pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index d9f77e8f04f1c..767cf8f48cfea 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -165,10 +165,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Finally we register each of these predicates as an obligation in // a fresh FulfillmentCtxt, and invoke select_all_or_error. - // Create a parameter environment that represents the implementation's - // method. - let impl_param_env = tcx.parameter_environment(impl_m.def_id); - // Create mapping from impl to skolemized. let impl_to_skol_substs = Substs::identity_for_item(tcx, impl_m.def_id); @@ -216,19 +212,18 @@ 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 trait_param_env = impl_param_env.with_caller_bounds( - tcx.intern_predicates(&hybrid_preds.predicates)); - let trait_param_env = traits::normalize_param_env_or_error(tcx, - impl_m.def_id, - trait_param_env, - normalize_cause.clone()); - - tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { + let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates)); + 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| { let inh = Inherited::new(infcx, impl_m.def_id); let infcx = &inh.infcx; debug!("compare_impl_method: caller_bounds={:?}", - infcx.parameter_environment.caller_bounds); + infcx.param_env.caller_bounds); let mut selcx = traits::SelectionContext::new(&infcx); @@ -350,7 +345,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let region_maps = RegionMaps::new(); let mut free_regions = FreeRegionMap::new(); free_regions.relate_free_regions_from_predicates( - &infcx.parameter_environment.caller_bounds); + &infcx.param_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); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index e029332559635..3ed0da05dc2c2 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -79,7 +79,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.parameter_environment(self_type_did); + let impl_param_env = tcx.param_env(self_type_did); tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| { let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c1cf5192877c0..9ad72b2a137ea 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -566,7 +566,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { param_ty: ty::ParamTy) { // FIXME -- Do we want to commit to this behavior for param bounds? - let bounds: Vec<_> = self.parameter_environment + let bounds: Vec<_> = self.param_env .caller_bounds .iter() .filter_map(|predicate| { @@ -893,7 +893,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); - let caller_predicates = self.parameter_environment.caller_bounds.to_vec(); + let caller_predicates = self.param_env.caller_bounds.to_vec(); for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates) .filter_map(|p| p.to_opt_poly_trait_ref()) .filter(|b| b.def_id() == trait_def_id) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d304d79bc52c8..24a88140cf041 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -539,7 +539,7 @@ 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.parameter_environment(def_id); + let param_env = tcx.param_env(def_id); InheritedBuilder { infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing), def_id, @@ -1561,7 +1561,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { let index = generics.type_param_to_index[&def_id.index]; ty::GenericPredicates { parent: None, - predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| { + predicates: self.param_env.caller_bounds.iter().filter(|predicate| { match **predicate { ty::Predicate::Trait(ref data) => { data.0.self_ty().is_param(index) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 754bd288bfaa7..b29bf01ba1996 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let subject = self.tcx.hir.local_def_id(item_id); let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(subject)); rcx.free_region_map.relate_free_regions_from_predicates( - &self.parameter_environment.caller_bounds); + &self.param_env.caller_bounds); rcx.relate_free_regions(wf_tys, item_id, span); rcx.visit_region_obligations(item_id); rcx.resolve_regions_and_report_errors(); @@ -158,7 +158,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } rcx.free_region_map.relate_free_regions_from_predicates( - &self.parameter_environment.caller_bounds); + &self.param_env.caller_bounds); rcx.resolve_regions_and_report_errors(); @@ -1682,7 +1682,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>) -> Vec> { - let param_env = &self.parameter_environment; + let param_env = &self.param_env; // To start, collect bounds from user: let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx), diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 556bd618c78cb..ff5599fb1bdbf 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -105,7 +105,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, self_type); let span = tcx.hir.span(impl_node_id); - let param_env = tcx.parameter_environment(impl_did); + let param_env = tcx.param_env(impl_did); assert!(!self_type.has_escaping_regions()); debug!("visit_implementation_of_copy: self_type={:?} (free)", @@ -199,7 +199,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, target); let span = tcx.hir.span(impl_node_id); - let param_env = tcx.parameter_environment(impl_did); + let param_env = tcx.param_env(impl_did); assert!(!source.has_escaping_regions()); let err_info = CoerceUnsizedInfo { custom_kind: None }; @@ -387,7 +387,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.parameter_environment + free_regions.relate_free_regions_from_predicates(&infcx.param_env .caller_bounds); infcx.resolve_regions_and_report_errors(impl_did, ®ion_maps, &free_regions); diff --git a/src/test/run-make/atomic-lock-free/atomic_lock_free.rs b/src/test/run-make/atomic-lock-free/atomic_lock_free.rs index 023f2218b87ae..b41e8e9226b32 100644 --- a/src/test/run-make/atomic-lock-free/atomic_lock_free.rs +++ b/src/test/run-make/atomic-lock-free/atomic_lock_free.rs @@ -20,6 +20,8 @@ extern "rust-intrinsic" { trait Sized {} #[lang = "copy"] trait Copy {} +#[lang = "freeze"] +trait Freeze {} #[cfg(target_has_atomic = "8")] pub unsafe fn atomic_u8(x: *mut u8) {