From c832e6f3272fd01e22a6370e7745e305fe13a4c9 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 19 Feb 2017 14:46:29 +0200 Subject: [PATCH] rustc_typeck: rework coherence to be almost completely on-demand. --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/hir/lowering.rs | 22 +- src/librustc/hir/map/mod.rs | 20 + src/librustc/hir/mod.rs | 3 + src/librustc/infer/mod.rs | 2 +- src/librustc/middle/cstore.rs | 2 - src/librustc/traits/mod.rs | 2 +- src/librustc/traits/project.rs | 37 +- src/librustc/traits/specialize/mod.rs | 2 +- .../traits/specialize/specialization_graph.rs | 2 +- src/librustc/ty/contents.rs | 2 +- src/librustc/ty/maps.rs | 49 +++ src/librustc/ty/mod.rs | 56 ++- src/librustc/ty/trait_def.rs | 75 +++- src/librustc/ty/util.rs | 8 +- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 2 +- .../borrowck/mir/elaborate_drops.rs | 2 +- .../borrowck/mir/gather_moves.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_const_eval/eval.rs | 2 +- src/librustc_driver/test.rs | 2 +- .../calculate_svh/svh_visitor.rs | 3 + src/librustc_lint/builtin.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 6 - src/librustc_metadata/decoder.rs | 21 +- src/librustc_mir/mir_map.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_mir/transform/type_check.rs | 2 +- src/librustc_passes/consts.rs | 4 +- src/librustc_passes/rvalues.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/glue.rs | 4 +- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 57 ++- src/librustc_typeck/coherence/inherent.rs | 356 ++++++++++++++++++ src/librustc_typeck/coherence/mod.rs | 203 ++++------ src/librustc_typeck/coherence/orphan.rs | 227 +---------- src/librustc_typeck/coherence/overlap.rs | 213 ++++------- src/librustc_typeck/coherence/unsafety.rs | 17 +- src/librustc_typeck/collect.rs | 12 +- src/librustc_typeck/lib.rs | 3 +- src/librustdoc/clean/inline.rs | 3 +- src/test/compile-fail/E0117.rs | 2 + .../coherence-cross-crate-conflict.rs | 1 + .../coherence-default-trait-impl.rs | 2 +- .../compile-fail/coherence-impls-sized.rs | 12 +- src/test/ui/span/E0204.stderr | 18 +- 53 files changed, 824 insertions(+), 670 deletions(-) create mode 100644 src/librustc_typeck/coherence/inherent.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 769c08a81efa6..e0233d6f8b98c 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -70,6 +70,7 @@ pub enum DepNode { Resolve, EntryPoint, CheckEntryFn, + CoherenceCheckTrait(D), CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), @@ -241,6 +242,7 @@ impl DepNode { MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), CollectItemSig(ref d) => op(d).map(CollectItemSig), + CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index bfcaf1e00f06e..468421a68b54c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -80,6 +80,9 @@ pub struct LoweringContext<'a> { impl_items: BTreeMap, bodies: FxHashMap, + trait_impls: BTreeMap>, + trait_default_impl: BTreeMap, + loop_scopes: Vec, is_in_loop_condition: bool, @@ -116,6 +119,8 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + trait_impls: BTreeMap::new(), + trait_default_impl: BTreeMap::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -201,6 +206,8 @@ impl<'a> LoweringContext<'a> { trait_items: self.trait_items, impl_items: self.impl_items, bodies: self.bodies, + trait_impls: self.trait_impls, + trait_default_impl: self.trait_default_impl, } } @@ -1089,14 +1096,27 @@ impl<'a> LoweringContext<'a> { hir::ItemUnion(vdata, self.lower_generics(generics)) } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + let trait_ref = self.lower_trait_ref(trait_ref); + + if let Def::Trait(def_id) = trait_ref.path.def { + self.trait_default_impl.insert(def_id, id); + } + hir::ItemDefaultImpl(self.lower_unsafety(unsafety), - self.lower_trait_ref(trait_ref)) + trait_ref) } ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); + + if let Some(ref trait_ref) = ifce { + if let Def::Trait(def_id) = trait_ref.path.def { + self.trait_impls.entry(def_id).or_insert(vec![]).push(id); + } + } + hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), self.lower_generics(generics), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 13b786541c502..20b4d8d8a8f03 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -461,6 +461,26 @@ impl<'hir> Map<'hir> { } } + pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] { + self.dep_graph.read(DepNode::TraitImpls(trait_did)); + + // NB: intentionally bypass `self.forest.krate()` so that we + // do not trigger a read of the whole krate here + self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..]) + } + + pub fn trait_default_impl(&self, trait_did: DefId) -> Option { + self.dep_graph.read(DepNode::TraitImpls(trait_did)); + + // NB: intentionally bypass `self.forest.krate()` so that we + // do not trigger a read of the whole krate here + self.forest.krate.trait_default_impl.get(&trait_did).cloned() + } + + pub fn trait_is_auto(&self, trait_did: DefId) -> bool { + self.trait_default_impl(trait_did).is_some() + } + /// Get the attributes on the krate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e8c5f2447cd6f..8b6c75886baa8 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -410,6 +410,9 @@ pub struct Crate { pub trait_items: BTreeMap, pub impl_items: BTreeMap, pub bodies: FxHashMap, + + pub trait_impls: BTreeMap>, + pub trait_default_impl: BTreeMap, } impl Crate { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index d7f254df7538a..a929060cf9890 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), reported_trait_errors: RefCell::new(FxHashSet()), - projection_mode: Reveal::NotSpecializable, + projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), obligations_in_snapshot: Cell::new(false), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index cb5ced57bd8b9..4a7027b8997a5 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -191,7 +191,6 @@ pub trait CrateStore { // flags fn is_const_fn(&self, did: DefId) -> bool; - fn is_defaulted_trait(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool; fn is_dllimport_foreign_item(&self, def: DefId) -> bool; @@ -327,7 +326,6 @@ impl CrateStore for DummyCrateStore { // flags fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } - fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") } fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 117e16da26c3f..7e7d06e4b814e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -473,7 +473,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let elaborated_env = unnormalized_env.with_caller_bounds(predicates); - tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| { let predicates = match fully_normalize(&infcx, cause, &infcx.parameter_environment.caller_bounds) { Ok(predicates) => predicates, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 448a3166bd860..3d8f9e41c675b 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -38,36 +38,6 @@ use util::common::FN_OUTPUT_NAME; /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Reveal { - /// FIXME (#32205) - /// At coherence-checking time, we're still constructing the - /// specialization graph, and thus we only project - /// non-`default` associated types that are defined directly in - /// the applicable impl. (This behavior should be improved over - /// time, to allow for successful projections modulo cycles - /// between different impls). - /// - /// Here's an example that will fail due to the restriction: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// type Output = bool; - /// } - /// - /// impl Assoc for u8 {} // <- inherits the non-default type from above - /// - /// trait Foo {} - /// impl Foo for u32 {} - /// impl Foo for ::Output {} // <- this projection will fail - /// ``` - /// - /// The projection would succeed if `Output` had been defined - /// directly in the impl for `u8`. - ExactMatch, - /// At type-checking time, we refuse to project any associated /// type that is marked `default`. Non-`default` ("final") types /// are always projected. This is necessary in general for @@ -90,7 +60,7 @@ pub enum Reveal { /// fn main() { /// let <() as Assoc>::Output = true; /// } - NotSpecializable, + UserFacing, /// At trans time, all monomorphic projections will succeed. /// Also, `impl Trait` is normalized to the concrete type, @@ -1347,8 +1317,9 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; + let trait_def = selcx.tcx().lookup_trait_def(trait_def_id); - if selcx.projection_mode() == Reveal::ExactMatch { + if !trait_def.is_complete(selcx.tcx()) { let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(selcx.tcx()) { if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { @@ -1360,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( } None } else { - selcx.tcx().lookup_trait_def(trait_def_id) + trait_def .ancestors(impl_def_id) .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type) .next() diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0fe054b30ba31..79df7de04f540 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .subst(tcx, &penv.free_substs); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| { + let result = tcx.infer_ctxt(penv, Reveal::UserFacing).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 368b1fb4bcbd3..40eb69395678f 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children { let possible_sibling = *slot; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).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/ty/contents.rs b/src/librustc/ty/contents.rs index 56621c57eb8f7..e14295982916f 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { res = res - TC::OwnsDtor; } - if def.has_dtor() { + if def.has_dtor(tcx) { res = res | TC::OwnsDtor; } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 26c92e3e7ecf7..358d69ff8dba9 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -24,6 +24,15 @@ trait Key { fn default_span(&self, tcx: TyCtxt) -> Span; } +impl Key for CrateNum { + fn map_crate(&self) -> CrateNum { + *self + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + impl Key for DefId { fn map_crate(&self) -> CrateNum { self.krate @@ -42,6 +51,15 @@ impl Key for (DefId, DefId) { } } +impl Key for (CrateNum, DefId) { + fn map_crate(&self) -> CrateNum { + self.0 + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.1.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -141,6 +159,19 @@ impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> { } } +impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> { + fn describe(tcx: TyCtxt, (_, def_id): (CrateNum, DefId)) -> String { + format!("coherence checking all impls of trait `{}`", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("coherence checking all inherent impls") + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -238,6 +269,12 @@ macro_rules! define_maps { } pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { + // FIXME(eddyb) Move away from using `DepTrackingMap` + // so we don't have to explicitly ignore a false edge: + // we can't observe a value dependency, only side-effects, + // through `force`, and once everything has been updated, + // perhaps only diagnostics, if those, will remain. + let _ignore = tcx.dep_graph.in_ignore(); match Self::try_get_with(tcx, span, key, |_| ()) { Ok(()) => {} Err(e) => tcx.report_cycle(e) @@ -338,7 +375,19 @@ define_maps! { <'tcx> pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), + + pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (), + /// Results of evaluating monomorphic constants embedded in /// other items, such as enum variant explicit discriminants. pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result } + +fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { + DepNode::CoherenceCheckTrait(def_id) +} + +fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode { + DepNode::Coherence +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5ab0c9e565519..55b6f61148d77 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1301,6 +1301,7 @@ bitflags! { const IS_FUNDAMENTAL = 1 << 4, const IS_UNION = 1 << 5, const IS_BOX = 1 << 6, + const IS_DTOR_VALID = 1 << 7, } } @@ -1522,8 +1523,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { } /// Returns whether this type has a destructor. - pub fn has_dtor(&self) -> bool { - self.destructor.get().is_some() + pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + self.destructor(tcx).is_some() } /// Asserts this is a struct and returns the struct's unique @@ -1578,12 +1579,36 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - pub fn destructor(&self) -> Option { - self.destructor.get() + pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) { + return self.destructor.get(); + } + + let dtor = self.destructor_uncached(tcx); + self.destructor.set(dtor); + self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID); + + dtor } - pub fn set_destructor(&self, dtor: DefId) { - self.destructor.set(Some(dtor)); + fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() { + def_id + } else { + return None; + }; + + queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait)); + + let mut dtor = None; + let ty = tcx.item_type(self.did); + tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| { + if let Some(item) = tcx.associated_items(def_id).next() { + dtor = Some(item.def_id); + } + }); + + dtor } pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) @@ -2367,23 +2392,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { - self.populate_implementations_for_trait_if_necessary(trait_def_id); - let def = self.lookup_trait_def(trait_def_id); def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } - /// Records a trait-to-implementation mapping. - pub fn record_trait_has_default_impl(self, trait_def_id: DefId) { - let def = self.lookup_trait_def(trait_def_id); - def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) - } - /// Populates the type context with all the inherent implementations for /// the given type if necessary. pub fn populate_inherent_implementations_for_type_if_necessary(self, + span: Span, type_id: DefId) { if type_id.is_local() { + // Make sure coherence of inherent impls ran already. + ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE); return } @@ -2416,16 +2436,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let _ignore = self.dep_graph.in_ignore(); let def = self.lookup_trait_def(trait_id); - if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { + if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) { return; } debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); - if self.sess.cstore.is_defaulted_trait(trait_id) { - self.record_trait_has_default_impl(trait_id); - } - for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) { let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); @@ -2434,7 +2450,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.record_remote_impl(self, impl_def_id, trait_ref, parent); } - def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); + def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS); } pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 1dc494ca277b3..097b596c5ebb6 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::DepNode; -use hir::def_id::DefId; +use hir::def_id::{DefId, LOCAL_CRATE}; use traits::{self, specialization_graph}; use ty; use ty::fast_reject; @@ -18,6 +18,9 @@ use std::cell::{Cell, RefCell}; use hir; use util::nodemap::FxHashMap; +use syntax::ast; +use syntax_pos::DUMMY_SP; + /// A trait's definition with type information. pub struct TraitDef { pub def_id: DefId, @@ -60,6 +63,11 @@ pub struct TraitDef { /// Various flags pub flags: Cell, + /// The number of impls we've added from the local crate. + /// When this number matches up the list in the HIR map, + /// we're done, and the specialization graph is correct. + local_impl_count: Cell, + /// The ICH of this trait's DefPath, cached here so it doesn't have to be /// recomputed all the time. pub def_path_hash: u64, @@ -78,6 +86,7 @@ impl<'a, 'gcx, 'tcx> TraitDef { nonblanket_impls: RefCell::new(FxHashMap()), blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), + local_impl_count: Cell::new(0), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), def_path_hash: def_path_hash, } @@ -155,6 +164,13 @@ impl<'a, 'gcx, 'tcx> TraitDef { assert!(impl_def_id.is_local()); let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref); assert!(was_new); + + self.local_impl_count.set(self.local_impl_count.get() + 1); + } + + /// Records a trait-to-implementation mapping. + pub fn record_has_default_impl(&self) { + self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL); } /// Records a trait-to-implementation mapping for a non-local impl. @@ -194,10 +210,51 @@ impl<'a, 'gcx, 'tcx> TraitDef { specialization_graph::ancestors(self, of_impl) } + /// Whether the impl set and specialization graphs are complete. + pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + tcx.populate_implementations_for_trait_if_necessary(self.def_id); + ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok() + } + + /// If any local impls haven't been added yet, returns + /// Some(list of local impls for this trait). + fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> Option<&'gcx [ast::NodeId]> { + if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) { + return None; + } + + if self.is_complete(tcx) { + self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS); + return None; + } + + let impls = tcx.hir.trait_impls(self.def_id); + assert!(self.local_impl_count.get() <= impls.len()); + if self.local_impl_count.get() == impls.len() { + self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS); + return None; + } + + Some(impls) + } + pub fn for_each_impl(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) { self.read_trait_impls(tcx); tcx.populate_implementations_for_trait_if_necessary(self.def_id); + let local_impls = self.missing_local_impls(tcx); + if let Some(impls) = local_impls { + for &id in impls { + f(tcx.hir.local_def_id(id)); + } + } + let mut f = |def_id: DefId| { + if !(local_impls.is_some() && def_id.is_local()) { + f(def_id); + } + }; + for &impl_def_id in self.blanket_impls.borrow().iter() { f(impl_def_id); } @@ -217,9 +274,20 @@ impl<'a, 'gcx, 'tcx> TraitDef { mut f: F) { self.read_trait_impls(tcx); - tcx.populate_implementations_for_trait_if_necessary(self.def_id); + let local_impls = self.missing_local_impls(tcx); + if let Some(impls) = local_impls { + for &id in impls { + f(tcx.hir.local_def_id(id)); + } + } + let mut f = |def_id: DefId| { + if !(local_impls.is_some() && def_id.is_local()) { + f(def_id); + } + }; + for &impl_def_id in self.blanket_impls.borrow().iter() { f(impl_def_id); } @@ -258,6 +326,7 @@ bitflags! { const HAS_DEFAULT_IMPL = 1 << 0, const IS_OBJECT_SAFE = 1 << 1, const OBJECT_SAFETY_VALID = 1 << 2, - const IMPLS_VALID = 1 << 3, + const HAS_REMOTE_IMPLS = 1 << 3, + const HAS_LOCAL_IMPLS = 1 << 4, } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d1c22651a9e00..64480e510229e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -149,7 +149,7 @@ impl<'tcx> ParameterEnvironment<'tcx> { self_type: Ty<'tcx>, span: Span) -> Result<(), CopyImplementationError> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt) @@ -171,7 +171,7 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } - if adt.has_dtor() { + if adt.has_dtor(tcx) { return Err(CopyImplementationError::HasDestructor); } @@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// (This allows programs to make cyclic structures without /// resorting to unasfe means; see RFCs 769 and 1238). pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool { - let dtor_method = match adt.destructor() { + let dtor_method = match adt.destructor(self) { Some(dtor) => dtor, None => return false }; @@ -524,7 +524,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } } let result = - tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch) + tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing) .enter(|infcx| { traits::type_known_to_meet_bound(&infcx, self, def_id, span) }); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index e3dec97472a48..3ce31882b86c4 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -783,7 +783,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyAdt(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor(self.tcx()) => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index c33ced52e2bd6..0577ba7f45a93 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -177,7 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { ty::TyAdt(def, _) => { - if def.has_dtor() { + if def.has_dtor(bccx.tcx) { Some(cmt.clone()) } else { check_and_get_illegal_move_origin(bccx, b) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 47f8d978704f4..3678c2e55c1fd 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -150,7 +150,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { - ty::TyAdt(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ which implements the `Drop` trait", diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index f8c0044774a01..13f898219bc12 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -898,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match ty.sty { ty::TyAdt(def, _) => { - if def.has_dtor() && !def.is_box() { + if def.has_dtor(self.tcx) && !def.is_box() { self.tcx.sess.span_warn( c.source_info.span, &format!("dataflow bug??? moving out of type with dtor {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 35ace6628cfed..8d866676dbd18 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { // error: can't move out of borrowed content ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() => + ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() => return Err(MovePathError::IllegalMove), // move out of union - always move the entire union ty::TyAdt(adt, _) if adt.is_union() => diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index d9283e7037f50..1c9ee335699ae 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => { + ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 9b30946c0bebb..db5df72267df7 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -516,7 +516,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::NotSpecializable).enter(|infcx| { + cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).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 eadb49a0731a4..0ab2255aab0ff 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -922,7 +922,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( trait_ref); tcx.populate_implementations_for_trait_if_necessary(trait_id); - tcx.infer_ctxt((), Reveal::NotSpecializable).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_driver/test.rs b/src/librustc_driver/test.rs index 36ba1e7f95bd8..9568cc3d6de0e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -151,7 +151,7 @@ fn test_env(source_string: &str, index, "test_crate", |tcx| { - tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { body(Env { infcx: &infcx }); let free_regions = FreeRegionMap::new(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 486900fc2fed5..150a2c39db7a8 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -1167,6 +1167,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { trait_items: _, impl_items: _, bodies: _, + + trait_impls: _, + trait_default_impl: _, } = *krate; visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 75269f58ed62d..b3f09c28277ad 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { } _ => return, }; - if def.has_dtor() { + if def.has_dtor(cx.tcx) { return; } let parameter_environment = cx.tcx.empty_parameter_environment(); @@ -882,7 +882,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap(); let param_env = ty::ParameterEnvironment::for_item(tcx, node_id); - tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(param_env, Reveal::UserFacing).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_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 1b19e79d489d6..443e75e63d3dd 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -203,12 +203,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(did.krate).is_const_fn(did.index) } - fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool - { - self.dep_graph.read(DepNode::MetaData(trait_def_id)); - self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index) - } - fn is_default_impl(&self, impl_did: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(impl_did)); self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e81d752fde047..1627b22cd5fa1 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -501,10 +501,16 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - ty::TraitDef::new(self.local_def_id(item_id), - data.unsafety, - data.paren_sugar, - self.def_path(item_id).deterministic_hash(tcx)) + let def = ty::TraitDef::new(self.local_def_id(item_id), + data.unsafety, + data.paren_sugar, + self.def_path(item_id).deterministic_hash(tcx)); + + if data.has_default_impl { + def.record_has_default_impl(); + } + + def } fn get_variant(&self, @@ -1027,13 +1033,6 @@ impl<'a, 'tcx> CrateMetadata { self.dllimport_foreign_items.contains(&id) } - pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { - match self.entry(trait_id).kind { - EntryKind::Trait(data) => data.decode(self).has_default_impl, - _ => bug!(), - } - } - pub fn is_default_impl(&self, impl_id: DefIndex) -> bool { match self.entry(impl_id).kind { EntryKind::DefaultImpl(_) => true, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 34b701a3a9dd5..0d7be189f883a 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -96,7 +96,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) }; let src = MirSource::from_node(tcx, id); - tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { let cx = Cx::new(&infcx, src); let mut mir = if let MirSource::Fn(id) = src { // fetch the fully liberated fn signature (that is, all bound diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4f80e21af64e4..9f38564d1e2f3 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -758,7 +758,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Aggregate(ref kind, _) => { if let AggregateKind::Adt(def, ..) = *kind { - if def.has_dtor() { + if def.has_dtor(self.tcx) { self.add(Qualif::NEEDS_DROP); self.deny_drop(); } @@ -1042,7 +1042,7 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty; - tcx.infer_ctxt((), Reveal::NotSpecializable).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 40485e4b66d77..af4a4a53905eb 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -699,7 +699,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir { return; } let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); - tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| { let mut checker = TypeChecker::new(&infcx, src.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 e3772a09968ec..e3a77a9359980 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::NotSpecializable).enter(|infcx| { + let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { let param_env = infcx.parameter_environment.clone(); let outer_penv = mem::replace(&mut self.param_env, param_env); euv::ExprUseVisitor::new(self, &infcx).consume_body(body); @@ -274,7 +274,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { /// instead of producing errors. fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { - ty::TyAdt(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor(v.tcx) => { v.promotable = false; } _ => {} diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 9de5ff541a52c..c367e71fcd246 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'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::NotSpecializable).enter(|infcx| { + self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| { let mut delegate = RvalueContextDelegate { tcx: infcx.tcx, param_env: &infcx.parameter_environment diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 14ef48a902703..b12c1220b2b4d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -754,7 +754,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { - ty::TyAdt(def, _) => def.destructor(), + ty::TyAdt(def, _) => def.destructor(scx.tcx()), _ => None }; diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 58e0a9e589f33..32fc3d5af2445 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -237,7 +237,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi bcx.call(dtor, &[ptr.llval], None); bcx } - ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => { + ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => { let shallow_drop = def.is_union(); let tcx = bcx.tcx(); @@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi traits::VtableImpl(data) => data, _ => bug!("dtor for {:?} is not an impl???", t) }; - let dtor_did = def.destructor().unwrap(); + let dtor_did = def.destructor(tcx).unwrap(); let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let llret; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 06cf653e29368..0e9abaf1cf955 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -224,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_param_env, normalize_cause.clone()); - tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { let inh = Inherited::new(infcx); let infcx = &inh.infcx; let fulfillment_cx = &inh.fulfillment_cx; @@ -730,7 +730,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::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { let mut fulfillment_cx = traits::FulfillmentContext::new(); // The below is for the most part highly similar to the procedure diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 385ea7d52e1ce..07cc35ed67bbb 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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 = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); - tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| { let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); @@ -554,7 +554,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Find the `impl<..> Drop for _` to inspect any // attributes attached to the impl's generics. - let dtor_method = adt_def.destructor() + let dtor_method = adt_def.destructor(tcx) .expect("dtorck type without destructor impossible"); let method = tcx.associated_item(dtor_method); let impl_def_id = method.container.id(); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b6071d01ff1cf..dfa7ababca0bb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { // Read the inherent implementation candidates for this type from the // metadata if necessary. - self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id); + self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id); if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) { for &impl_def_id in impl_infos.iter() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 68d8280d397d7..aa1fc0f8579da 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -477,7 +477,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { let tables = ty::TypeckTables::empty(); let param_env = ParameterEnvironment::for_item(tcx, id); InheritedBuilder { - infcx: tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable) + infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing) } } } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index bfe8abb201cae..3cdf9fc93ae60 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -26,47 +26,38 @@ use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use rustc::hir::{self, ItemImpl}; -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop); - check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy); - check_trait( - tcx, - tcx.lang_items.coerce_unsized_trait(), - visit_implementation_of_coerce_unsized); +pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) { + Checker { tcx, trait_def_id } + .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop) + .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy) + .check(tcx.lang_items.coerce_unsized_trait(), + visit_implementation_of_coerce_unsized); } -fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: Option, - mut f: F) - where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId) -{ - if let Some(trait_def_id) = trait_def_id { - let mut impls = vec![]; - tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| { - impls.push(did); - }); - impls.sort(); - for impl_def_id in impls { - f(tcx, trait_def_id, impl_def_id); +struct Checker<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_def_id: DefId +} + +impl<'a, 'tcx> Checker<'a, 'tcx> { + fn check(&self, trait_def_id: Option, mut f: F) -> &Self + where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId) + { + if Some(self.trait_def_id) == trait_def_id { + for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) { + let impl_def_id = self.tcx.hir.local_def_id(impl_id); + f(self.tcx, self.trait_def_id, impl_def_id); + } } + self } } fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _drop_did: DefId, impl_did: DefId) { - let items = tcx.associated_item_def_ids(impl_did); - if items.is_empty() { - // We'll error out later. For now, just don't ICE. - return; - } - let method_def_id = items[0]; - - let self_type = tcx.item_type(impl_did); - match self_type.sty { - ty::TyAdt(type_def, _) => { - type_def.set_destructor(method_def_id); - } + match tcx.item_type(impl_did).sty { + ty::TyAdt(..) => {} _ => { // Destructors only work on nominal types. if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) { @@ -205,7 +196,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| { + tcx.infer_ctxt(param_env, Reveal::UserFacing).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.rs b/src/librustc_typeck/coherence/inherent.rs new file mode 100644 index 0000000000000..e3b4ba9eb1b9e --- /dev/null +++ b/src/librustc_typeck/coherence/inherent.rs @@ -0,0 +1,356 @@ +// Copyright 2017 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. + +use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefId; +use rustc::hir; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::lint; +use rustc::traits::{self, Reveal}; +use rustc::ty::{self, TyCtxt}; + +use syntax::ast; +use syntax_pos::Span; + +struct InherentCollect<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx> +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + let (unsafety, ty) = match item.node { + hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty), + _ => return + }; + + match unsafety { + hir::Unsafety::Normal => { + // OK + } + hir::Unsafety::Unsafe => { + span_err!(self.tcx.sess, + item.span, + E0197, + "inherent impls cannot be declared as unsafe"); + } + } + + let def_id = self.tcx.hir.local_def_id(item.id); + let self_ty = self.tcx.item_type(def_id); + match self_ty.sty { + ty::TyAdt(def, _) => { + self.check_def_id(item, def.did); + } + ty::TyDynamic(ref data, ..) if data.principal().is_some() => { + self.check_def_id(item, data.principal().unwrap().def_id()); + } + ty::TyChar => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.char_impl(), + "char", + "char", + item.span); + } + ty::TyStr => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.str_impl(), + "str", + "str", + item.span); + } + ty::TySlice(_) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.slice_impl(), + "slice", + "[T]", + item.span); + } + ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.const_ptr_impl(), + "const_ptr", + "*const T", + item.span); + } + ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.mut_ptr_impl(), + "mut_ptr", + "*mut T", + item.span); + } + ty::TyInt(ast::IntTy::I8) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i8_impl(), + "i8", + "i8", + item.span); + } + ty::TyInt(ast::IntTy::I16) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i16_impl(), + "i16", + "i16", + item.span); + } + ty::TyInt(ast::IntTy::I32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i32_impl(), + "i32", + "i32", + item.span); + } + ty::TyInt(ast::IntTy::I64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i64_impl(), + "i64", + "i64", + item.span); + } + ty::TyInt(ast::IntTy::I128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i128_impl(), + "i128", + "i128", + item.span); + } + ty::TyInt(ast::IntTy::Is) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.isize_impl(), + "isize", + "isize", + item.span); + } + ty::TyUint(ast::UintTy::U8) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u8_impl(), + "u8", + "u8", + item.span); + } + ty::TyUint(ast::UintTy::U16) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u16_impl(), + "u16", + "u16", + item.span); + } + ty::TyUint(ast::UintTy::U32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u32_impl(), + "u32", + "u32", + item.span); + } + ty::TyUint(ast::UintTy::U64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u64_impl(), + "u64", + "u64", + item.span); + } + ty::TyUint(ast::UintTy::U128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u128_impl(), + "u128", + "u128", + item.span); + } + ty::TyUint(ast::UintTy::Us) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.usize_impl(), + "usize", + "usize", + item.span); + } + ty::TyFloat(ast::FloatTy::F32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.f32_impl(), + "f32", + "f32", + item.span); + } + ty::TyFloat(ast::FloatTy::F64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.f64_impl(), + "f64", + "f64", + item.span); + } + ty::TyError => { + return; + } + _ => { + struct_span_err!(self.tcx.sess, + ty.span, + E0118, + "no base type found for inherent implementation") + .span_label(ty.span, &format!("impl requires a base type")) + .note(&format!("either implement a trait on it or create a newtype \ + to wrap it instead")) + .emit(); + return; + } + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } +} + +impl<'a, 'tcx> InherentCollect<'a, 'tcx> { + fn check_def_id(&self, item: &hir::Item, def_id: DefId) { + if def_id.is_local() { + // Add the implementation to the mapping from implementation to base + // type def ID, if there is a base type for this implementation and + // the implementation does not have any associated traits. + let impl_def_id = self.tcx.hir.local_def_id(item.id); + + // Subtle: it'd be better to collect these into a local map + // and then write the vector only once all items are known, + // but that leads to degenerate dep-graphs. The problem is + // that the write of that big vector winds up having reads + // from *all* impls in the krate, since we've lost the + // precision basically. This would be ok in the firewall + // model so once we've made progess towards that we can modify + // the strategy here. In the meantime, using `push` is ok + // because we are doing this as a pre-pass before anyone + // actually reads from `inherent_impls` -- and we know this is + // true beacuse we hold the refcell lock. + self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id); + } else { + struct_span_err!(self.tcx.sess, + item.span, + E0116, + "cannot define inherent `impl` for a type outside of the crate \ + where the type is defined") + .span_label(item.span, + &format!("impl for type defined outside of crate.")) + .note("define and implement a trait or new type instead") + .emit(); + } + } + + fn check_primitive_impl(&self, + impl_def_id: DefId, + lang_def_id: Option, + lang: &str, + ty: &str, + span: Span) { + match lang_def_id { + Some(lang_def_id) if lang_def_id == impl_def_id => { + // OK + } + _ => { + struct_span_err!(self.tcx.sess, + span, + E0390, + "only a single inherent implementation marked with `#[lang = \ + \"{}\"]` is allowed for the `{}` primitive", + lang, + ty) + .span_help(span, "consider using a trait to implement these methods") + .emit(); + } + } + } +} + +struct InherentOverlapChecker<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx> +} + +impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { + fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { + #[derive(Copy, Clone, PartialEq)] + enum Namespace { + Type, + Value, + } + + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; + + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); + + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); + + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { + let msg = format!("duplicate definitions with name `{}`", name); + let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); + self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, + node_id, + self.tcx.span_of_impl(item1).unwrap(), + msg); + } + } + } + } + + fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { + let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); + + let inherent_impls = self.tcx.maps.inherent_impls.borrow(); + let impls = match inherent_impls.get(&ty_def_id) { + Some(impls) => impls, + None => return, + }; + + 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| { + 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) + } + }); + } + } + } +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> { + fn visit_item(&mut self, item: &'v hir::Item) { + match item.node { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemTrait(..) | + hir::ItemUnion(..) => { + let type_def_id = self.tcx.hir.local_def_id(item.id); + self.check_for_overlapping_inherent_impls(type_def_id); + } + _ => {} + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } +} + +pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, + &mut InherentCollect { tcx }); + tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, + &mut InherentOverlapChecker { tcx }); +} diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ed5ca79a70661..9ecf42daeaae5 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -15,146 +15,72 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. -use dep_graph::DepTrackingMap; -use hir::def_id::DefId; -use rustc::ty::{self, maps, TyCtxt, TypeFoldable}; -use rustc::ty::{Ty, TyBool, TyChar, TyError}; -use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple}; -use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr}; -use rustc::ty::{TyProjection, TyAnon}; -use syntax_pos::Span; +use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc::ty::maps::Providers; use rustc::dep_graph::DepNode; -use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::hir::{Item, ItemImpl}; -use rustc::hir; -use std::cell::RefMut; + +use syntax::ast; +use syntax_pos::DUMMY_SP; mod builtin; +mod inherent; mod orphan; mod overlap; mod unsafety; -struct CoherenceCollect<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - inherent_impls: RefMut<'a, DepTrackingMap>>, -} - -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> { - fn visit_item(&mut self, item: &Item) { - if let ItemImpl(..) = item.node { - self.check_implementation(item) - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { - } - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { - } -} - -impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> { - fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let inherent_impls = tcx.maps.inherent_impls.borrow_mut(); - let mut this = &mut CoherenceCollect { tcx, inherent_impls }; - - // Check implementations and traits. This populates the tables - // containing the inherent methods and extension methods. It also - // builds up the trait inheritance table. - tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this); - } +fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { + let impl_def_id = tcx.hir.local_def_id(node_id); - // Returns the def ID of the base type, if there is one. - fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { - match ty.sty { - TyAdt(def, _) => Some(def.did), + // If there are no traits, then this implementation must have a + // base type. - TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()), + if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { + debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", + trait_ref, + tcx.item_path_str(impl_def_id)); - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) | - TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError | - TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None, - - TyInfer(..) | TyClosure(..) | TyAnon(..) => { - // `ty` comes from a user declaration so we should only expect types - // that the user can type - span_bug!(span, - "coherence encountered unexpected type searching for base type: {}", - ty); - } + // Skip impls where one of the self type is an error type. + // This occurs with e.g. resolve failures (#30589). + if trait_ref.references_error() { + return; } - } - fn check_implementation(&mut self, item: &Item) { - let tcx = self.tcx; - let impl_did = tcx.hir.local_def_id(item.id); - let self_type = tcx.item_type(impl_did); - - // If there are no traits, then this implementation must have a - // base type. - - if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { - debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", - trait_ref, - item.name); - - // Skip impls where one of the self type is an error type. - // This occurs with e.g. resolve failures (#30589). - if trait_ref.references_error() { - return; - } - - enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id); - self.add_trait_impl(trait_ref, impl_did); - } else { - // Skip inherent impls where the self type is an error - // type. This occurs with e.g. resolve failures (#30589). - if self_type.references_error() { - return; - } - - // Add the implementation to the mapping from implementation to base - // type def ID, if there is a base type for this implementation and - // the implementation does not have any associated traits. - if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) { - self.add_inherent_impl(base_def_id, impl_did); - } - } + enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); + let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + trait_def.record_local_impl(tcx, impl_def_id, trait_ref); } +} + +fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) { + let did = Some(trait_def_id); + let li = &tcx.lang_items; - fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) { - // Subtle: it'd be better to collect these into a local map - // and then write the vector only once all items are known, - // but that leads to degenerate dep-graphs. The problem is - // that the write of that big vector winds up having reads - // from *all* impls in the krate, since we've lost the - // precision basically. This would be ok in the firewall - // model so once we've made progess towards that we can modify - // the strategy here. In the meantime, using `push` is ok - // because we are doing this as a pre-pass before anyone - // actually reads from `inherent_impls` -- and we know this is - // true beacuse we hold the refcell lock. - self.inherent_impls.push(base_def_id, impl_def_id); + // Disallow *all* explicit impls of `Sized` and `Unsize` for now. + if did == li.sized_trait() { + let span = tcx.span_of_impl(impl_def_id).unwrap(); + struct_span_err!(tcx.sess, + span, + E0322, + "explicit impls for the `Sized` trait are not permitted") + .span_label(span, &format!("impl of 'Sized' not allowed")) + .emit(); + return; } - fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) { - debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}", - impl_trait_ref, - impl_def_id); - let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id); - trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref); + if did == li.unsize_trait() { + let span = tcx.span_of_impl(impl_def_id).unwrap(); + span_err!(tcx.sess, + span, + E0328, + "explicit impls for the `Unsize` trait are not permitted"); + return; } -} -fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) { if tcx.sess.features.borrow().unboxed_closures { - // the feature gate allows all of them + // the feature gate allows all Fn traits return; } - let did = Some(trait_def_id); - let li = &tcx.lang_items; let trait_name = if did == li.fn_trait() { "Fn" @@ -166,7 +92,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def return; // everything OK }; let mut err = struct_span_err!(tcx.sess, - sp, + tcx.span_of_impl(impl_def_id).unwrap(), E0183, "manual implementations of `{}` are experimental", trait_name); @@ -175,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def err.emit(); } -pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - CoherenceCollect::check(tcx); +pub fn provide(providers: &mut Providers) { + *providers = Providers { + coherent_trait, + coherent_inherent_impls, + ..*providers + }; +} +fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (_, def_id): (CrateNum, DefId)) { + tcx.populate_implementations_for_trait_if_necessary(def_id); + + let impls = tcx.hir.trait_impls(def_id); + for &impl_id in impls { + check_impl(tcx, impl_id); + } + for &impl_id in impls { + overlap::check_impl(tcx, impl_id); + } + builtin::check_trait(tcx, def_id); +} + +fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) { + inherent::check(tcx); +} + +pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::Coherence); + for &trait_def_id in tcx.hir.krate().trait_impls.keys() { + ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); + } + unsafety::check(tcx); orphan::check(tcx); - overlap::check(tcx); - builtin::check(tcx); + overlap::check_default_impls(tcx); + + ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 9ef231499df51..ee361ab6073d4 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -11,11 +11,8 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; use rustc::ty::{self, TyCtxt}; -use syntax::ast; -use syntax_pos::Span; use rustc::dep_graph::DepNode; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; @@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'tcx, 'tcx>, } -impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { - fn check_def_id(&self, item: &hir::Item, def_id: DefId) { - if def_id.krate != LOCAL_CRATE { - struct_span_err!(self.tcx.sess, - item.span, - E0116, - "cannot define inherent `impl` for a type outside of the crate \ - where the type is defined") - .span_label(item.span, - &format!("impl for type defined outside of crate.")) - .note("define and implement a trait or new type instead") - .emit(); - } - } - - fn check_primitive_impl(&self, - impl_def_id: DefId, - lang_def_id: Option, - lang: &str, - ty: &str, - span: Span) { - match lang_def_id { - Some(lang_def_id) if lang_def_id == impl_def_id => { - // OK - } - _ => { - struct_span_err!(self.tcx.sess, - span, - E0390, - "only a single inherent implementation marked with `#[lang = \ - \"{}\"]` is allowed for the `{}` primitive", - lang, - ty) - .span_help(span, "consider using a trait to implement these methods") - .emit(); - } - } - } -} - impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { /// Checks exactly one impl for orphan rules and other such /// restrictions. In this fn, it can happen that multiple errors @@ -78,168 +35,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let def_id = self.tcx.hir.local_def_id(item.id); match item.node { - hir::ItemImpl(.., None, ref ty, _) => { - // For inherent impls, self type must be a nominal type - // defined in this crate. - debug!("coherence2::orphan check: inherent impl {}", - self.tcx.hir.node_to_string(item.id)); - let self_ty = self.tcx.item_type(def_id); - match self_ty.sty { - ty::TyAdt(def, _) => { - self.check_def_id(item, def.did); - } - ty::TyDynamic(ref data, ..) if data.principal().is_some() => { - self.check_def_id(item, data.principal().unwrap().def_id()); - } - ty::TyChar => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.char_impl(), - "char", - "char", - item.span); - } - ty::TyStr => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.str_impl(), - "str", - "str", - item.span); - } - ty::TySlice(_) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.slice_impl(), - "slice", - "[T]", - item.span); - } - ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.const_ptr_impl(), - "const_ptr", - "*const T", - item.span); - } - ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.mut_ptr_impl(), - "mut_ptr", - "*mut T", - item.span); - } - ty::TyInt(ast::IntTy::I8) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.i8_impl(), - "i8", - "i8", - item.span); - } - ty::TyInt(ast::IntTy::I16) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.i16_impl(), - "i16", - "i16", - item.span); - } - ty::TyInt(ast::IntTy::I32) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.i32_impl(), - "i32", - "i32", - item.span); - } - ty::TyInt(ast::IntTy::I64) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.i64_impl(), - "i64", - "i64", - item.span); - } - ty::TyInt(ast::IntTy::I128) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.i128_impl(), - "i128", - "i128", - item.span); - } - ty::TyInt(ast::IntTy::Is) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.isize_impl(), - "isize", - "isize", - item.span); - } - ty::TyUint(ast::UintTy::U8) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.u8_impl(), - "u8", - "u8", - item.span); - } - ty::TyUint(ast::UintTy::U16) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.u16_impl(), - "u16", - "u16", - item.span); - } - ty::TyUint(ast::UintTy::U32) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.u32_impl(), - "u32", - "u32", - item.span); - } - ty::TyUint(ast::UintTy::U64) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.u64_impl(), - "u64", - "u64", - item.span); - } - ty::TyUint(ast::UintTy::U128) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.u128_impl(), - "u128", - "u128", - item.span); - } - ty::TyUint(ast::UintTy::Us) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.usize_impl(), - "usize", - "usize", - item.span); - } - ty::TyFloat(ast::FloatTy::F32) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.f32_impl(), - "f32", - "f32", - item.span); - } - ty::TyFloat(ast::FloatTy::F64) => { - self.check_primitive_impl(def_id, - self.tcx.lang_items.f64_impl(), - "f64", - "f64", - item.span); - } - ty::TyError => { - return; - } - _ => { - struct_span_err!(self.tcx.sess, - ty.span, - E0118, - "no base type found for inherent implementation") - .span_label(ty.span, &format!("impl requires a base type")) - .note(&format!("either implement a trait on it or create a newtype \ - to wrap it instead")) - .emit(); - return; - } - } - } hir::ItemImpl(.., Some(_), _, _) => { // "Trait" impl debug!("coherence2::orphan check: trait impl {}", @@ -311,7 +106,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { trait_def_id, self.tcx.trait_has_default_impl(trait_def_id)); if self.tcx.trait_has_default_impl(trait_def_id) && - trait_def_id.krate != LOCAL_CRATE { + !trait_def_id.is_local() { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { ty::TyAdt(self_def, _) => Some(self_def.did), @@ -346,31 +141,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { return; } } - - // Disallow *all* explicit impls of `Sized` and `Unsize` for now. - if Some(trait_def_id) == self.tcx.lang_items.sized_trait() { - struct_span_err!(self.tcx.sess, - item.span, - E0322, - "explicit impls for the `Sized` trait are not permitted") - .span_label(item.span, &format!("impl of 'Sized' not allowed")) - .emit(); - return; - } - if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { - span_err!(self.tcx.sess, - item.span, - E0328, - "explicit impls for the `Unsize` trait are not permitted"); - return; - } } hir::ItemDefaultImpl(_, ref item_trait_ref) => { // "Trait" impl debug!("coherence2::orphan check: default trait impl {}", self.tcx.hir.node_to_string(item.id)); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); - if trait_ref.def_id.krate != LOCAL_CRATE { + if !trait_ref.def_id.is_local() { struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318, diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 45493d40eb802..d334d0c4338f9 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -12,102 +12,101 @@ //! same type. Likewise, no two inherent impls for a given type //! constructor provide a method with the same name. -use hir::def_id::DefId; -use rustc::traits::{self, Reveal}; +use rustc::traits; use rustc::ty::{self, TyCtxt, TypeFoldable}; use syntax::ast; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use util::nodemap::DefIdMap; -use lint; -pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut overlap = OverlapChecker { - tcx: tcx, - default_impls: DefIdMap(), - }; +pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let mut overlap = OverlapChecker { tcx }; // this secondary walk specifically checks for some other cases, // like defaulted traits, for which additional overlap rules exist tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); } -struct OverlapChecker<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, - - // maps from a trait def-id to an impl id - default_impls: DefIdMap, -} +pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { + let impl_def_id = tcx.hir.local_def_id(node_id); + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_def_id = trait_ref.def_id; -impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { - fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { - #[derive(Copy, Clone, PartialEq)] - enum Namespace { - Type, - Value, - } + if trait_ref.references_error() { + debug!("coherence: skipping impl {:?} with error {:?}", + impl_def_id, trait_ref); + return + } - let name_and_namespace = |def_id| { - let item = self.tcx.associated_item(def_id); - (item.name, match item.kind { - ty::AssociatedKind::Type => Namespace::Type, - ty::AssociatedKind::Const | - ty::AssociatedKind::Method => Namespace::Value, - }) - }; - - let impl_items1 = self.tcx.associated_item_def_ids(impl1); - let impl_items2 = self.tcx.associated_item_def_ids(impl2); - - for &item1 in &impl_items1[..] { - let (name, namespace) = name_and_namespace(item1); - - for &item2 in &impl_items2[..] { - if (name, namespace) == name_and_namespace(item2) { - let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); - } + let _task = + tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); + + let def = tcx.lookup_trait_def(trait_def_id); + + // attempt to insert into the specialization graph + let insert_result = def.add_impl_for_specialization(tcx, impl_def_id); + + // insertion failed due to overlap + if let Err(overlap) = insert_result { + let mut err = struct_span_err!(tcx.sess, + tcx.span_of_impl(impl_def_id).unwrap(), + E0119, + "conflicting implementations of trait `{}`{}:", + overlap.trait_desc, + overlap.self_desc.clone().map_or(String::new(), + |ty| { + format!(" for type `{}`", ty) + })); + + match tcx.span_of_impl(overlap.with_impl) { + Ok(span) => { + err.span_label(span, &format!("first implementation here")); + err.span_label(tcx.span_of_impl(impl_def_id).unwrap(), + &format!("conflicting implementation{}", + overlap.self_desc + .map_or(String::new(), + |ty| format!(" for `{}`", ty)))); + } + Err(cname) => { + err.note(&format!("conflicting implementation in crate `{}`", cname)); } } + + err.emit(); } - fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id)); - - let inherent_impls = self.tcx.maps.inherent_impls.borrow(); - let impls = match inherent_impls.get(&ty_def_id) { - Some(impls) => impls, - None => return, - }; - - for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt((), Reveal::ExactMatch).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) - } - }); + // check for overlap with the automatic `impl Trait for Trait` + if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty { + // This is something like impl Trait1 for Trait2. Illegal + // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. + + if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) { + // This is an error, but it will be reported by wfcheck. Ignore it here. + // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. + } else { + let mut supertrait_def_ids = + traits::supertrait_def_ids(tcx, + data.principal().unwrap().def_id()); + if supertrait_def_ids.any(|d| d == trait_def_id) { + span_err!(tcx.sess, + tcx.span_of_impl(impl_def_id).unwrap(), + E0371, + "the object type `{}` automatically \ + implements the trait `{}`", + trait_ref.self_ty(), + tcx.item_path_str(trait_def_id)); } } } } +struct OverlapChecker<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, +} + impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemTrait(..) | - hir::ItemUnion(..) => { - let type_def_id = self.tcx.hir.local_def_id(item.id); - self.check_for_overlapping_inherent_impls(type_def_id); - } - hir::ItemDefaultImpl(..) => { // look for another default impl; note that due to the // general orphan/coherence rules, it must always be @@ -115,8 +114,8 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { let impl_def_id = self.tcx.hir.local_def_id(item.id); let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); - let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); - if let Some(prev_id) = prev_default_impl { + let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap(); + if prev_id != item.id { let mut err = struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0521, @@ -131,76 +130,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { } } hir::ItemImpl(.., Some(_), _, _) => { - let impl_def_id = self.tcx.hir.local_def_id(item.id); - let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); - let trait_def_id = trait_ref.def_id; - - if trait_ref.references_error() { - debug!("coherence: skipping impl {:?} with error {:?}", - impl_def_id, trait_ref); - return - } - - let _task = - self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); - - let def = self.tcx.lookup_trait_def(trait_def_id); - - // attempt to insert into the specialization graph - let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id); - - // insertion failed due to overlap - if let Err(overlap) = insert_result { - let mut err = struct_span_err!(self.tcx.sess, - self.tcx.span_of_impl(impl_def_id).unwrap(), - E0119, - "conflicting implementations of trait `{}`{}:", - overlap.trait_desc, - overlap.self_desc.clone().map_or(String::new(), - |ty| { - format!(" for type `{}`", ty) - })); - - match self.tcx.span_of_impl(overlap.with_impl) { - Ok(span) => { - err.span_label(span, &format!("first implementation here")); - err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(), - &format!("conflicting implementation{}", - overlap.self_desc - .map_or(String::new(), - |ty| format!(" for `{}`", ty)))); - } - Err(cname) => { - err.note(&format!("conflicting implementation in crate `{}`", cname)); - } - } - - err.emit(); - } - - // check for overlap with the automatic `impl Trait for Trait` - if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty { - // This is something like impl Trait1 for Trait2. Illegal - // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. - - if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) { - // This is an error, but it will be reported by wfcheck. Ignore it here. - // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. - } else { - let mut supertrait_def_ids = - traits::supertrait_def_ids(self.tcx, - data.principal().unwrap().def_id()); - if supertrait_def_ids.any(|d| d == trait_def_id) { - span_err!(self.tcx.sess, - item.span, - E0371, - "the object type `{}` automatically \ - implements the trait `{}`", - trait_ref.self_ty(), - self.tcx.item_path_str(trait_def_id)); - } - } - } } _ => {} } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 8c98e2952ebe9..22247d2531aec 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -31,20 +31,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { unsafety: hir::Unsafety, polarity: hir::ImplPolarity) { match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) { - None => { - // Inherent impl. - match unsafety { - hir::Unsafety::Normal => { - // OK - } - hir::Unsafety::Unsafe => { - span_err!(self.tcx.sess, - item.span, - E0197, - "inherent impls cannot be declared as unsafe"); - } - } - } + None => {} Some(trait_ref) => { let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); @@ -100,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { hir::ItemDefaultImpl(unsafety, _) => { self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ref generics, ..) => { + hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } _ => {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 83adbdaf0307d..ecdbf170702aa 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -519,9 +519,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { convert_enum_variant_types(tcx, def_id, &enum_definition.variants); }, hir::ItemDefaultImpl(..) => { - if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { - tcx.record_trait_has_default_impl(trait_ref.def_id); - } + tcx.impl_trait_ref(def_id); } hir::ItemImpl(..) => { tcx.item_generics(def_id); @@ -869,7 +867,13 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); - tcx.alloc_trait_def(ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash)) + let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash); + + if tcx.hir.trait_is_auto(def_id) { + def.record_has_default_impl(); + } + + tcx.alloc_trait_def(def) } fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0f425baec10bb..2c325d46c0bc0 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::NotSpecializable).enter(|infcx| { + tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { match infcx.eq_types(false, &cause, expected, actual) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations @@ -287,6 +287,7 @@ fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { collect::provide(providers); + coherence::provide(providers); check::provide(providers); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 61c2a3c9e9512..c4476483186c7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -15,6 +15,7 @@ use std::io; use std::iter::once; use syntax::ast; +use syntax_pos::DUMMY_SP; use rustc::hir; use rustc::hir::def::{Def, CtorKind}; @@ -231,7 +232,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; - tcx.populate_inherent_implementations_for_type_if_necessary(did); + tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did); let mut impls = Vec::new(); if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) { diff --git a/src/test/compile-fail/E0117.rs b/src/test/compile-fail/E0117.rs index 4ba9c3382f35d..3da00da205fec 100644 --- a/src/test/compile-fail/E0117.rs +++ b/src/test/compile-fail/E0117.rs @@ -12,6 +12,8 @@ impl Drop for u32 {} //~ ERROR E0117 //~^ NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate //~| NOTE define and implement a trait or new type instead +//~| ERROR the Drop trait may only be implemented on structures +//~| implementing Drop requires a struct fn main() { } diff --git a/src/test/compile-fail/coherence-cross-crate-conflict.rs b/src/test/compile-fail/coherence-cross-crate-conflict.rs index 9f74afbb2b3b5..aac870293fd55 100644 --- a/src/test/compile-fail/coherence-cross-crate-conflict.rs +++ b/src/test/compile-fail/coherence-cross-crate-conflict.rs @@ -17,6 +17,7 @@ use trait_impl_conflict::Foo; impl Foo for A { //~^ ERROR type parameter `A` must be used as the type parameter for some local type + //~| ERROR conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize` } fn main() { diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index 3d109de76ccd1..15a80c64f8b06 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -13,9 +13,9 @@ trait MyTrait {} impl MyTrait for .. {} +//~^ ERROR redundant default implementations of trait `MyTrait` impl MyTrait for .. {} -//~^ ERROR redundant default implementations of trait `MyTrait` trait MySafeTrait {} diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index 79767e5157b14..60b5d14d1587a 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322 impl Sized for MyType {} //~ ERROR E0322 //~^ impl of 'Sized' not allowed -impl Sized for (MyType, MyType) {} //~ ERROR E0117 +impl Sized for (MyType, MyType) {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed +//~| ERROR E0117 impl Sized for &'static NotSync {} //~ ERROR E0322 //~^ impl of 'Sized' not allowed -impl Sized for [MyType] {} //~ ERROR E0117 +impl Sized for [MyType] {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed +//~| ERROR E0117 -impl Sized for &'static [NotSync] {} //~ ERROR E0117 +impl Sized for &'static [NotSync] {} //~ ERROR E0322 +//~^ impl of 'Sized' not allowed +//~| ERROR E0117 fn main() { } diff --git a/src/test/ui/span/E0204.stderr b/src/test/ui/span/E0204.stderr index 81a60a9dd3099..4fe6afaca8ec6 100644 --- a/src/test/ui/span/E0204.stderr +++ b/src/test/ui/span/E0204.stderr @@ -7,15 +7,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type 15 | impl Copy for Foo { } | ^^^^ -error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/E0204.rs:27:6 - | -23 | Bar { x: Vec }, - | ----------- this field does not implement `Copy` -... -27 | impl Copy for EFoo { } - | ^^^^ - error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/E0204.rs:17:10 | @@ -25,6 +16,15 @@ error[E0204]: the trait `Copy` may not be implemented for this type 19 | ty: &'a mut bool, | ---------------- this field does not implement `Copy` +error[E0204]: the trait `Copy` may not be implemented for this type + --> $DIR/E0204.rs:27:6 + | +23 | Bar { x: Vec }, + | ----------- this field does not implement `Copy` +... +27 | impl Copy for EFoo { } + | ^^^^ + error[E0204]: the trait `Copy` may not be implemented for this type --> $DIR/E0204.rs:29:10 |