1
Fork 0

rustc_typeck: rework coherence to be almost completely on-demand.

This commit is contained in:
Eduard-Mihai Burtescu 2017-02-19 14:46:29 +02:00
parent 9890e0466d
commit c832e6f327
53 changed files with 836 additions and 682 deletions

View file

@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
Resolve, Resolve,
EntryPoint, EntryPoint,
CheckEntryFn, CheckEntryFn,
CoherenceCheckTrait(D),
CoherenceCheckImpl(D), CoherenceCheckImpl(D),
CoherenceOverlapCheck(D), CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D), CoherenceOverlapCheckSpecial(D),
@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
MetaData(ref d) => op(d).map(MetaData), MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem), CollectItem(ref d) => op(d).map(CollectItem),
CollectItemSig(ref d) => op(d).map(CollectItemSig), CollectItemSig(ref d) => op(d).map(CollectItemSig),
CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),

View file

@ -80,6 +80,9 @@ pub struct LoweringContext<'a> {
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>, impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>, bodies: FxHashMap<hir::BodyId, hir::Body>,
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
trait_default_impl: BTreeMap<DefId, NodeId>,
loop_scopes: Vec<NodeId>, loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool, is_in_loop_condition: bool,
@ -116,6 +119,8 @@ pub fn lower_crate(sess: &Session,
trait_items: BTreeMap::new(), trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(), impl_items: BTreeMap::new(),
bodies: FxHashMap(), bodies: FxHashMap(),
trait_impls: BTreeMap::new(),
trait_default_impl: BTreeMap::new(),
loop_scopes: Vec::new(), loop_scopes: Vec::new(),
is_in_loop_condition: false, is_in_loop_condition: false,
type_def_lifetime_params: DefIdMap(), type_def_lifetime_params: DefIdMap(),
@ -201,6 +206,8 @@ impl<'a> LoweringContext<'a> {
trait_items: self.trait_items, trait_items: self.trait_items,
impl_items: self.impl_items, impl_items: self.impl_items,
bodies: self.bodies, 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)) hir::ItemUnion(vdata, self.lower_generics(generics))
} }
ItemKind::DefaultImpl(unsafety, ref trait_ref) => { 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), 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) => { ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
let new_impl_items = impl_items.iter() let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item)) .map(|item| self.lower_impl_item_ref(item))
.collect(); .collect();
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); 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), hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity), self.lower_impl_polarity(polarity),
self.lower_generics(generics), self.lower_generics(generics),

View file

@ -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<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_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 /// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter /// invoking `krate.attrs` because it registers a tighter
/// dep-graph access. /// dep-graph access.

View file

@ -410,6 +410,9 @@ pub struct Crate {
pub trait_items: BTreeMap<TraitItemId, TraitItem>, pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>, pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub bodies: FxHashMap<BodyId, Body>, pub bodies: FxHashMap<BodyId, Body>,
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
pub trait_default_impl: BTreeMap<DefId, NodeId>,
} }
impl Crate { impl Crate {

View file

@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
evaluation_cache: traits::EvaluationCache::new(), evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()), projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FxHashSet()), reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: Reveal::NotSpecializable, projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false), tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(), err_count_on_creation: self.sess.err_count(),
obligations_in_snapshot: Cell::new(false), obligations_in_snapshot: Cell::new(false),

View file

@ -191,7 +191,6 @@ pub trait CrateStore {
// flags // flags
fn is_const_fn(&self, did: DefId) -> bool; 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_default_impl(&self, impl_did: DefId) -> bool;
fn is_foreign_item(&self, did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool;
fn is_dllimport_foreign_item(&self, def: DefId) -> bool; fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
@ -327,7 +326,6 @@ impl CrateStore for DummyCrateStore {
// flags // flags
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } 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_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_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false } fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }

View file

@ -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); 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, let predicates = match fully_normalize(&infcx, cause,
&infcx.parameter_environment.caller_bounds) { &infcx.parameter_environment.caller_bounds) {
Ok(predicates) => predicates, Ok(predicates) => predicates,

View file

@ -38,36 +38,6 @@ use util::common::FN_OUTPUT_NAME;
/// more or less conservative. /// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Reveal { 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<T> 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 <u8 as Assoc>::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 /// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types /// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for /// are always projected. This is necessary in general for
@ -90,7 +60,7 @@ pub enum Reveal {
/// fn main() { /// fn main() {
/// let <() as Assoc>::Output = true; /// let <() as Assoc>::Output = true;
/// } /// }
NotSpecializable, UserFacing,
/// At trans time, all monomorphic projections will succeed. /// At trans time, all monomorphic projections will succeed.
/// Also, `impl Trait` is normalized to the concrete type, /// Also, `impl Trait` is normalized to the concrete type,
@ -1347,8 +1317,9 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>> -> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
{ {
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; 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); let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(selcx.tcx()) { for item in impl_node.items(selcx.tcx()) {
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
@ -1360,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
} }
None None
} else { } else {
selcx.tcx().lookup_trait_def(trait_def_id) trait_def
.ancestors(impl_def_id) .ancestors(impl_def_id)
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type) .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
.next() .next()

View file

@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.subst(tcx, &penv.free_substs); .subst(tcx, &penv.free_substs);
// Create a infcx, taking the predicates of impl1 as assumptions: // 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 // Normalize the trait reference. The WF rules ought to ensure
// that this always succeeds. // that this always succeeds.
let impl1_trait_ref = let impl1_trait_ref =

View file

@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
let possible_sibling = *slot; let possible_sibling = *slot;
let tcx = tcx.global_tcx(); 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, let overlap = traits::overlapping_impls(&infcx,
possible_sibling, possible_sibling,
impl_def_id); impl_def_id);

View file

@ -219,7 +219,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
res = res - TC::OwnsDtor; res = res - TC::OwnsDtor;
} }
if def.has_dtor() { if def.has_dtor(tcx) {
res = res | TC::OwnsDtor; res = res | TC::OwnsDtor;
} }

View file

@ -24,6 +24,15 @@ trait Key {
fn default_span(&self, tcx: TyCtxt) -> Span; 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 { impl Key for DefId {
fn map_crate(&self) -> CrateNum { fn map_crate(&self) -> CrateNum {
self.krate 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 { trait Value<'tcx>: Sized {
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; 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 { macro_rules! define_maps {
(<$tcx:tt> (<$tcx:tt>
$($(#[$attr:meta])* $($(#[$attr:meta])*
@ -238,6 +269,12 @@ macro_rules! define_maps {
} }
pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { 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, |_| ()) { match Self::try_get_with(tcx, span, key, |_| ()) {
Ok(()) => {} Ok(()) => {}
Err(e) => tcx.report_cycle(e) Err(e) => tcx.report_cycle(e)
@ -338,7 +375,19 @@ define_maps! { <'tcx>
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'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 /// Results of evaluating monomorphic constants embedded in
/// other items, such as enum variant explicit discriminants. /// other items, such as enum variant explicit discriminants.
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()> pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
} }
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
DepNode::CoherenceCheckTrait(def_id)
}
fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Coherence
}

View file

@ -1301,6 +1301,7 @@ bitflags! {
const IS_FUNDAMENTAL = 1 << 4, const IS_FUNDAMENTAL = 1 << 4,
const IS_UNION = 1 << 5, const IS_UNION = 1 << 5,
const IS_BOX = 1 << 6, 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. /// Returns whether this type has a destructor.
pub fn has_dtor(&self) -> bool { pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
self.destructor.get().is_some() self.destructor(tcx).is_some()
} }
/// Asserts this is a struct and returns the struct's unique /// 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<DefId> { pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
self.destructor.get() 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) { fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
self.destructor.set(Some(dtor)); 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>) 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 { 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); let def = self.lookup_trait_def(trait_def_id);
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) 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 /// Populates the type context with all the inherent implementations for
/// the given type if necessary. /// the given type if necessary.
pub fn populate_inherent_implementations_for_type_if_necessary(self, pub fn populate_inherent_implementations_for_type_if_necessary(self,
span: Span,
type_id: DefId) { type_id: DefId) {
if type_id.is_local() { if type_id.is_local() {
// Make sure coherence of inherent impls ran already.
ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
return return
} }
@ -2416,16 +2436,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let _ignore = self.dep_graph.in_ignore(); let _ignore = self.dep_graph.in_ignore();
let def = self.lookup_trait_def(trait_id); 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; return;
} }
debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def); 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)) { 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(); 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.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 { pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
use dep_graph::DepNode; use dep_graph::DepNode;
use hir::def_id::DefId; use hir::def_id::{DefId, LOCAL_CRATE};
use traits::{self, specialization_graph}; use traits::{self, specialization_graph};
use ty; use ty;
use ty::fast_reject; use ty::fast_reject;
@ -18,6 +18,9 @@ use std::cell::{Cell, RefCell};
use hir; use hir;
use util::nodemap::FxHashMap; use util::nodemap::FxHashMap;
use syntax::ast;
use syntax_pos::DUMMY_SP;
/// A trait's definition with type information. /// A trait's definition with type information.
pub struct TraitDef { pub struct TraitDef {
pub def_id: DefId, pub def_id: DefId,
@ -60,6 +63,11 @@ pub struct TraitDef {
/// Various flags /// Various flags
pub flags: Cell<TraitFlags>, pub flags: Cell<TraitFlags>,
/// 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<usize>,
/// The ICH of this trait's DefPath, cached here so it doesn't have to be /// The ICH of this trait's DefPath, cached here so it doesn't have to be
/// recomputed all the time. /// recomputed all the time.
pub def_path_hash: u64, pub def_path_hash: u64,
@ -78,6 +86,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
nonblanket_impls: RefCell::new(FxHashMap()), nonblanket_impls: RefCell::new(FxHashMap()),
blanket_impls: RefCell::new(vec![]), blanket_impls: RefCell::new(vec![]),
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
local_impl_count: Cell::new(0),
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
def_path_hash: def_path_hash, def_path_hash: def_path_hash,
} }
@ -155,6 +164,13 @@ impl<'a, 'gcx, 'tcx> TraitDef {
assert!(impl_def_id.is_local()); assert!(impl_def_id.is_local());
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref); let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
assert!(was_new); 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. /// 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) 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<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) { pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
self.read_trait_impls(tcx); self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.def_id); 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() { for &impl_def_id in self.blanket_impls.borrow().iter() {
f(impl_def_id); f(impl_def_id);
} }
@ -217,9 +274,20 @@ impl<'a, 'gcx, 'tcx> TraitDef {
mut f: F) mut f: F)
{ {
self.read_trait_impls(tcx); self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.def_id); 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() { for &impl_def_id in self.blanket_impls.borrow().iter() {
f(impl_def_id); f(impl_def_id);
} }
@ -258,6 +326,7 @@ bitflags! {
const HAS_DEFAULT_IMPL = 1 << 0, const HAS_DEFAULT_IMPL = 1 << 0,
const IS_OBJECT_SAFE = 1 << 1, const IS_OBJECT_SAFE = 1 << 1,
const OBJECT_SAFETY_VALID = 1 << 2, const OBJECT_SAFETY_VALID = 1 << 2,
const IMPLS_VALID = 1 << 3, const HAS_REMOTE_IMPLS = 1 << 3,
const HAS_LOCAL_IMPLS = 1 << 4,
} }
} }

View file

@ -149,7 +149,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
self_type: Ty<'tcx>, span: Span) self_type: Ty<'tcx>, span: Span)
-> Result<(), CopyImplementationError> { -> Result<(), CopyImplementationError> {
// FIXME: (@jroesch) float this code up // 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 { let (adt, substs) = match self_type.sty {
ty::TyAdt(adt, substs) => (adt, substs), ty::TyAdt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt) _ => 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); return Err(CopyImplementationError::HasDestructor);
} }
@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// (This allows programs to make cyclic structures without /// (This allows programs to make cyclic structures without
/// resorting to unasfe means; see RFCs 769 and 1238). /// resorting to unasfe means; see RFCs 769 and 1238).
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool { 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, Some(dtor) => dtor,
None => return false None => return false
}; };
@ -524,7 +524,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
} }
} }
let result = let result =
tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch) tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
.enter(|infcx| { .enter(|infcx| {
traits::type_known_to_meet_bound(&infcx, self, def_id, span) traits::type_known_to_meet_bound(&infcx, self, def_id, span)
}); });

View file

@ -783,7 +783,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
match lp_base.to_type().sty { 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 // In the case where the owner implements drop, then
// the path must be initialized to prevent a case of // the path must be initialized to prevent a case of
// partial reinitialization // partial reinitialization

View file

@ -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, _)) => { Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
match b.ty.sty { match b.ty.sty {
ty::TyAdt(def, _) => { ty::TyAdt(def, _) => {
if def.has_dtor() { if def.has_dtor(bccx.tcx) {
Some(cmt.clone()) Some(cmt.clone())
} else { } else {
check_and_get_illegal_move_origin(bccx, b) check_and_get_illegal_move_origin(bccx, b)

View file

@ -150,7 +150,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
Categorization::Downcast(ref b, _) | Categorization::Downcast(ref b, _) |
Categorization::Interior(ref b, mc::InteriorField(_)) => { Categorization::Interior(ref b, mc::InteriorField(_)) => {
match b.ty.sty { 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, let mut err = struct_span_err!(bccx, move_from.span, E0509,
"cannot move out of type `{}`, \ "cannot move out of type `{}`, \
which implements the `Drop` trait", which implements the `Drop` trait",

View file

@ -898,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
match ty.sty { match ty.sty {
ty::TyAdt(def, _) => { ty::TyAdt(def, _) => {
if def.has_dtor() && !def.is_box() { if def.has_dtor(self.tcx) && !def.is_box() {
self.tcx.sess.span_warn( self.tcx.sess.span_warn(
c.source_info.span, c.source_info.span,
&format!("dataflow bug??? moving out of type with dtor {:?}", &format!("dataflow bug??? moving out of type with dtor {:?}",

View file

@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
// error: can't move out of borrowed content // error: can't move out of borrowed content
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
// error: can't move out of struct with destructor // 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), return Err(MovePathError::IllegalMove),
// move out of union - always move the entire union // move out of union - always move the entire union
ty::TyAdt(adt, _) if adt.is_union() => ty::TyAdt(adt, _) if adt.is_union() =>

View file

@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
lv, ty); lv, ty);
true 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", debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
lv, ty); lv, ty);
true true

View file

@ -516,7 +516,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
/// ///
/// FIXME: this should be done by borrowck. /// FIXME: this should be done by borrowck.
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { 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 { let mut checker = MutationChecker {
cx: cx, cx: cx,
}; };

View file

@ -922,7 +922,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
trait_ref); trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_id); 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 mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate()); trait_ref.to_poly_trait_predicate());

View file

@ -151,7 +151,7 @@ fn test_env<F>(source_string: &str,
index, index,
"test_crate", "test_crate",
|tcx| { |tcx| {
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| { tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
body(Env { infcx: &infcx }); body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new(); let free_regions = FreeRegionMap::new();

View file

@ -1167,6 +1167,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
trait_items: _, trait_items: _,
impl_items: _, impl_items: _,
bodies: _, bodies: _,
trait_impls: _,
trait_default_impl: _,
} = *krate; } = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);

View file

@ -523,7 +523,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
} }
_ => return, _ => return,
}; };
if def.has_dtor() { if def.has_dtor(cx.tcx) {
return; return;
} }
let parameter_environment = cx.tcx.empty_parameter_environment(); 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 node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id); 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); let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) { match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound. // The method comes from a `T: Trait` bound.

View file

@ -203,12 +203,6 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(did.krate).is_const_fn(did.index) 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 { fn is_default_impl(&self, impl_did: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(impl_did)); self.dep_graph.read(DepNode::MetaData(impl_did));
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index) self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)

View file

@ -501,10 +501,16 @@ impl<'a, 'tcx> CrateMetadata {
_ => bug!(), _ => bug!(),
}; };
ty::TraitDef::new(self.local_def_id(item_id), let def = ty::TraitDef::new(self.local_def_id(item_id),
data.unsafety, data.unsafety,
data.paren_sugar, data.paren_sugar,
self.def_path(item_id).deterministic_hash(tcx)) self.def_path(item_id).deterministic_hash(tcx));
if data.has_default_impl {
def.record_has_default_impl();
}
def
} }
fn get_variant(&self, fn get_variant(&self,
@ -1027,13 +1033,6 @@ impl<'a, 'tcx> CrateMetadata {
self.dllimport_foreign_items.contains(&id) 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 { pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
match self.entry(impl_id).kind { match self.entry(impl_id).kind {
EntryKind::DefaultImpl(_) => true, EntryKind::DefaultImpl(_) => true,

View file

@ -96,7 +96,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
}; };
let src = MirSource::from_node(tcx, id); 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 cx = Cx::new(&infcx, src);
let mut mir = if let MirSource::Fn(id) = src { let mut mir = if let MirSource::Fn(id) = src {
// fetch the fully liberated fn signature (that is, all bound // fetch the fully liberated fn signature (that is, all bound

View file

@ -758,7 +758,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
Rvalue::Aggregate(ref kind, _) => { Rvalue::Aggregate(ref kind, _) => {
if let AggregateKind::Adt(def, ..) = *kind { if let AggregateKind::Adt(def, ..) = *kind {
if def.has_dtor() { if def.has_dtor(self.tcx) {
self.add(Qualif::NEEDS_DROP); self.add(Qualif::NEEDS_DROP);
self.deny_drop(); self.deny_drop();
} }
@ -1042,7 +1042,7 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
// Statics must be Sync. // Statics must be Sync.
if mode == Mode::Static { if mode == Mode::Static {
let ty = mir.return_ty; 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 cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new(); let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, ty, fulfillment_cx.register_bound(&infcx, ty,

View file

@ -699,7 +699,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
return; return;
} }
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id()); 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 checker = TypeChecker::new(&infcx, src.item_id());
{ {
let mut verifier = TypeVerifier::new(&mut checker, mir); let mut verifier = TypeVerifier::new(&mut checker, mir);

View file

@ -138,7 +138,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
self.check_const_eval(&body.value); 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 param_env = infcx.parameter_environment.clone();
let outer_penv = mem::replace(&mut self.param_env, param_env); let outer_penv = mem::replace(&mut self.param_env, param_env);
euv::ExprUseVisitor::new(self, &infcx).consume_body(body); 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. /// instead of producing errors.
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty { match node_ty.sty {
ty::TyAdt(def, _) if def.has_dtor() => { ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
v.promotable = false; v.promotable = false;
} }
_ => {} _ => {}

View file

@ -38,7 +38,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
fn visit_nested_body(&mut self, body_id: hir::BodyId) { fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let body = self.tcx.hir.body(body_id); 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 { let mut delegate = RvalueContextDelegate {
tcx: infcx.tcx, tcx: infcx.tcx,
param_env: &infcx.parameter_environment param_env: &infcx.parameter_environment

View file

@ -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 // If the type implements Drop, also add a translation item for the
// monomorphized Drop::drop() implementation. // monomorphized Drop::drop() implementation.
let destructor_did = match ty.sty { let destructor_did = match ty.sty {
ty::TyAdt(def, _) => def.destructor(), ty::TyAdt(def, _) => def.destructor(scx.tcx()),
_ => None _ => None
}; };

View file

@ -237,7 +237,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
bcx.call(dtor, &[ptr.llval], None); bcx.call(dtor, &[ptr.llval], None);
bcx 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 shallow_drop = def.is_union();
let tcx = bcx.tcx(); 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, traits::VtableImpl(data) => data,
_ => bug!("dtor for {:?} is not an impl???", t) _ => 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 callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let llret; let llret;

View file

@ -224,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_param_env, trait_param_env,
normalize_cause.clone()); 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 inh = Inherited::new(infcx);
let infcx = &inh.infcx; let infcx = &inh.infcx;
let fulfillment_cx = &inh.fulfillment_cx; 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>) { impl_trait_ref: ty::TraitRef<'tcx>) {
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); 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(); let mut fulfillment_cx = traits::FulfillmentContext::new();
// The below is for the most part highly similar to the procedure // The below is for the most part highly similar to the procedure

View file

@ -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. // 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); 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 tcx = infcx.tcx;
let mut fulfillment_cx = traits::FulfillmentContext::new(); 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 // Find the `impl<..> Drop for _` to inspect any
// attributes attached to the impl's generics. // 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"); .expect("dtorck type without destructor impossible");
let method = tcx.associated_item(dtor_method); let method = tcx.associated_item(dtor_method);
let impl_def_id = method.container.id(); let impl_def_id = method.container.id();

View file

@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
// Read the inherent implementation candidates for this type from the // Read the inherent implementation candidates for this type from the
// metadata if necessary. // 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) { if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
for &impl_def_id in impl_infos.iter() { for &impl_def_id in impl_infos.iter() {

View file

@ -477,7 +477,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
let tables = ty::TypeckTables::empty(); let tables = ty::TypeckTables::empty();
let param_env = ParameterEnvironment::for_item(tcx, id); let param_env = ParameterEnvironment::for_item(tcx, id);
InheritedBuilder { InheritedBuilder {
infcx: tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable) infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
} }
} }
} }

View file

@ -26,47 +26,38 @@ use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map; use rustc::hir::map as hir_map;
use rustc::hir::{self, ItemImpl}; use rustc::hir::{self, ItemImpl};
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop); Checker { tcx, trait_def_id }
check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy); .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
check_trait( .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
tcx, .check(tcx.lang_items.coerce_unsized_trait(),
tcx.lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized);
visit_implementation_of_coerce_unsized);
} }
fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, struct Checker<'a, 'tcx: 'a> {
trait_def_id: Option<DefId>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut f: F) trait_def_id: DefId
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId) }
{
if let Some(trait_def_id) = trait_def_id { impl<'a, 'tcx> Checker<'a, 'tcx> {
let mut impls = vec![]; fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| { where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
impls.push(did); {
}); if Some(self.trait_def_id) == trait_def_id {
impls.sort(); for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
for impl_def_id in impls { let impl_def_id = self.tcx.hir.local_def_id(impl_id);
f(tcx, trait_def_id, impl_def_id); f(self.tcx, self.trait_def_id, impl_def_id);
}
} }
self
} }
} }
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_drop_did: DefId, _drop_did: DefId,
impl_did: DefId) { impl_did: DefId) {
let items = tcx.associated_item_def_ids(impl_did); match tcx.item_type(impl_did).sty {
if items.is_empty() { ty::TyAdt(..) => {}
// 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);
}
_ => { _ => {
// Destructors only work on nominal types. // Destructors only work on nominal types.
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) { 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, source,
target); 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 cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>,

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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<DefId>,
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 });
}

View file

@ -15,147 +15,73 @@
// done by the orphan and overlap modules. Then we build up various // done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here. // mappings. That mapping code resides here.
use dep_graph::DepTrackingMap; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::def_id::DefId; use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc::ty::{self, maps, TyCtxt, TypeFoldable}; use rustc::ty::maps::Providers;
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 rustc::dep_graph::DepNode; use rustc::dep_graph::DepNode;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{Item, ItemImpl}; use syntax::ast;
use rustc::hir; use syntax_pos::DUMMY_SP;
use std::cell::RefMut;
mod builtin; mod builtin;
mod inherent;
mod orphan; mod orphan;
mod overlap; mod overlap;
mod unsafety; mod unsafety;
struct CoherenceCollect<'a, 'tcx: 'a> { fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_def_id = tcx.hir.local_def_id(node_id);
inherent_impls: RefMut<'a, DepTrackingMap<maps::queries::inherent_impls<'tcx>>>,
}
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> { // If there are no traits, then this implementation must have a
fn visit_item(&mut self, item: &Item) { // base type.
if let ItemImpl(..) = item.node {
self.check_implementation(item) 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));
// 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 visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { 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 visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
} }
} }
impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> { fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
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);
}
// 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<DefId> {
match ty.sty {
TyAdt(def, _) => Some(def.did),
TyDynamic(ref t, ..) => t.principal().map(|p| p.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);
}
}
}
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);
}
}
}
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);
}
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);
}
}
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
return;
}
let did = Some(trait_def_id); let did = Some(trait_def_id);
let li = &tcx.lang_items; let li = &tcx.lang_items;
// 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;
}
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;
}
if tcx.sess.features.borrow().unboxed_closures {
// the feature gate allows all Fn traits
return;
}
let trait_name = if did == li.fn_trait() { let trait_name = if did == li.fn_trait() {
"Fn" "Fn"
} else if did == li.fn_mut_trait() { } else if did == li.fn_mut_trait() {
@ -166,7 +92,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
return; // everything OK return; // everything OK
}; };
let mut err = struct_span_err!(tcx.sess, let mut err = struct_span_err!(tcx.sess,
sp, tcx.span_of_impl(impl_def_id).unwrap(),
E0183, E0183,
"manual implementations of `{}` are experimental", "manual implementations of `{}` are experimental",
trait_name); trait_name);
@ -175,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
err.emit(); err.emit();
} }
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) {
CoherenceCollect::check(tcx); *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); 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); unsafety::check(tcx);
orphan::check(tcx); orphan::check(tcx);
overlap::check(tcx); overlap::check_default_impls(tcx);
builtin::check(tcx);
ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
} }

View file

@ -11,11 +11,8 @@
//! Orphan checker: every impl either implements a trait defined in this //! Orphan checker: every impl either implements a trait defined in this
//! crate or pertains to a type defined in this crate. //! crate or pertains to a type defined in this crate.
use hir::def_id::{DefId, LOCAL_CRATE};
use rustc::traits; use rustc::traits;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use syntax::ast;
use syntax_pos::Span;
use rustc::dep_graph::DepNode; use rustc::dep_graph::DepNode;
use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir; use rustc::hir;
@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>, 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<DefId>,
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> { impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
/// Checks exactly one impl for orphan rules and other such /// Checks exactly one impl for orphan rules and other such
/// restrictions. In this fn, it can happen that multiple errors /// 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) { fn visit_item(&mut self, item: &hir::Item) {
let def_id = self.tcx.hir.local_def_id(item.id); let def_id = self.tcx.hir.local_def_id(item.id);
match item.node { 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(_), _, _) => { hir::ItemImpl(.., Some(_), _, _) => {
// "Trait" impl // "Trait" impl
debug!("coherence2::orphan check: 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, trait_def_id,
self.tcx.trait_has_default_impl(trait_def_id)); self.tcx.trait_has_default_impl(trait_def_id));
if 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 self_ty = trait_ref.self_ty();
let opt_self_def_id = match self_ty.sty { let opt_self_def_id = match self_ty.sty {
ty::TyAdt(self_def, _) => Some(self_def.did), ty::TyAdt(self_def, _) => Some(self_def.did),
@ -346,31 +141,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
return; 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) => { hir::ItemDefaultImpl(_, ref item_trait_ref) => {
// "Trait" impl // "Trait" impl
debug!("coherence2::orphan check: default trait impl {}", debug!("coherence2::orphan check: default trait impl {}",
self.tcx.hir.node_to_string(item.id)); self.tcx.hir.node_to_string(item.id));
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); 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, struct_span_err!(self.tcx.sess,
item_trait_ref.path.span, item_trait_ref.path.span,
E0318, E0318,

View file

@ -12,102 +12,101 @@
//! same type. Likewise, no two inherent impls for a given type //! same type. Likewise, no two inherent impls for a given type
//! constructor provide a method with the same name. //! constructor provide a method with the same name.
use hir::def_id::DefId; use rustc::traits;
use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::ty::{self, TyCtxt, TypeFoldable};
use syntax::ast; use syntax::ast;
use rustc::dep_graph::DepNode; use rustc::dep_graph::DepNode;
use rustc::hir; use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::itemlikevisit::ItemLikeVisitor;
use util::nodemap::DefIdMap;
use lint;
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut overlap = OverlapChecker { let mut overlap = OverlapChecker { tcx };
tcx: tcx,
default_impls: DefIdMap(),
};
// this secondary walk specifically checks for some other cases, // this secondary walk specifically checks for some other cases,
// like defaulted traits, for which additional overlap rules exist // like defaulted traits, for which additional overlap rules exist
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
} }
struct OverlapChecker<'cx, 'tcx: 'cx> { pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
tcx: TyCtxt<'cx, 'tcx, 'tcx>, 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;
// maps from a trait def-id to an impl id if trait_ref.references_error() {
default_impls: DefIdMap<ast::NodeId>, debug!("coherence: skipping impl {:?} with error {:?}",
impl_def_id, trait_ref);
return
}
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();
}
// 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));
}
}
}
} }
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { struct OverlapChecker<'cx, 'tcx: 'cx> {
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { tcx: TyCtxt<'cx, 'tcx, 'tcx>,
#[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::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)
}
});
}
}
}
} }
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) { fn visit_item(&mut self, item: &'v hir::Item) {
match item.node { 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(..) => { hir::ItemDefaultImpl(..) => {
// look for another default impl; note that due to the // look for another default impl; note that due to the
// general orphan/coherence rules, it must always be // 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 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_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
if let Some(prev_id) = prev_default_impl { if prev_id != item.id {
let mut err = struct_span_err!(self.tcx.sess, let mut err = struct_span_err!(self.tcx.sess,
self.tcx.span_of_impl(impl_def_id).unwrap(), self.tcx.span_of_impl(impl_def_id).unwrap(),
E0521, E0521,
@ -131,76 +130,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
} }
} }
hir::ItemImpl(.., Some(_), _, _) => { 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));
}
}
}
} }
_ => {} _ => {}
} }

View file

@ -31,20 +31,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
unsafety: hir::Unsafety, unsafety: hir::Unsafety,
polarity: hir::ImplPolarity) { polarity: hir::ImplPolarity) {
match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) { match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
None => { 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");
}
}
}
Some(trait_ref) => { Some(trait_ref) => {
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); 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, _) => { hir::ItemDefaultImpl(unsafety, _) => {
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); 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); self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
} }
_ => {} _ => {}

View file

@ -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); convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
}, },
hir::ItemDefaultImpl(..) => { hir::ItemDefaultImpl(..) => {
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { tcx.impl_trait_ref(def_id);
tcx.record_trait_has_default_impl(trait_ref.def_id);
}
} }
hir::ItemImpl(..) => { hir::ItemImpl(..) => {
tcx.item_generics(def_id); 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); 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>, fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

View file

@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
actual: Ty<'tcx>) actual: Ty<'tcx>)
-> bool { -> bool {
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| { tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
match infcx.eq_types(false, &cause, expected, actual) { match infcx.eq_types(false, &cause, expected, actual) {
Ok(InferOk { obligations, .. }) => { Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate 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) { pub fn provide(providers: &mut Providers) {
collect::provide(providers); collect::provide(providers);
coherence::provide(providers);
check::provide(providers); check::provide(providers);
} }

View file

@ -15,6 +15,7 @@ use std::io;
use std::iter::once; use std::iter::once;
use syntax::ast; use syntax::ast;
use syntax_pos::DUMMY_SP;
use rustc::hir; use rustc::hir;
use rustc::hir::def::{Def, CtorKind}; 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<clean::Item> { pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
let tcx = cx.tcx; 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(); let mut impls = Vec::new();
if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) { if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {

View file

@ -12,6 +12,8 @@ impl Drop for u32 {} //~ ERROR E0117
//~^ NOTE impl doesn't use types inside crate //~^ NOTE impl doesn't use types inside crate
//~| NOTE the impl does not reference any types defined in this crate //~| NOTE the impl does not reference any types defined in this crate
//~| NOTE define and implement a trait or new type instead //~| 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() { fn main() {
} }

View file

@ -17,6 +17,7 @@ use trait_impl_conflict::Foo;
impl<A> Foo for A { impl<A> Foo for A {
//~^ ERROR type parameter `A` must be used as the type parameter for some local type //~^ 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() { fn main() {

View file

@ -13,9 +13,9 @@
trait MyTrait {} trait MyTrait {}
impl MyTrait for .. {} impl MyTrait for .. {}
//~^ ERROR redundant default implementations of trait `MyTrait`
impl MyTrait for .. {} impl MyTrait for .. {}
//~^ ERROR redundant default implementations of trait `MyTrait`
trait MySafeTrait {} trait MySafeTrait {}

View file

@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322
impl Sized for MyType {} //~ ERROR E0322 impl Sized for MyType {} //~ ERROR E0322
//~^ impl of 'Sized' not allowed //~^ 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 Sized for &'static NotSync {} //~ ERROR E0322
//~^ impl of 'Sized' not allowed //~^ 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() { fn main() {
} }

View file

@ -7,15 +7,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type
15 | impl Copy for Foo { } 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<u32> },
| ----------- this field does not implement `Copy`
...
27 | impl Copy for EFoo { }
| ^^^^
error[E0204]: the trait `Copy` may not be implemented for this type error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:17:10 --> $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, 19 | ty: &'a mut bool,
| ---------------- this field does not implement `Copy` | ---------------- 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<u32> },
| ----------- this field does not implement `Copy`
...
27 | impl Copy for EFoo { }
| ^^^^
error[E0204]: the trait `Copy` may not be implemented for this type error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:29:10 --> $DIR/E0204.rs:29:10
| |