Resolve,
EntryPoint,
CheckEntryFn,
+ CoherenceCheckTrait(D),
CoherenceCheckImpl(D),
CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D),
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),
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,
+ trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+ trait_default_impl: BTreeMap<DefId, NodeId>,
+
loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
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(),
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,
}
}
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),
}
}
+ 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
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub bodies: FxHashMap<BodyId, Body>,
+
+ pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+ pub trait_default_impl: BTreeMap<DefId, NodeId>,
}
impl Crate {
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),
// 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;
// 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 }
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,
/// 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<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
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
/// 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,
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
{
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 {
}
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()
.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 =
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);
res = res - TC::OwnsDtor;
}
- if def.has_dtor() {
+ if def.has_dtor(tcx) {
res = res | TC::OwnsDtor;
}
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
}
}
+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;
}
}
}
+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])*
}
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)
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<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
+}
const IS_FUNDAMENTAL = 1 << 4,
const IS_UNION = 1 << 5,
const IS_BOX = 1 << 6,
+ const IS_DTOR_VALID = 1 << 7,
}
}
}
/// 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
}
}
- pub fn destructor(&self) -> Option<DefId> {
- self.destructor.get()
+ pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+ 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<DefId> {
+ 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 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
}
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();
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 {
// 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;
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,
/// Various flags
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
/// recomputed all the time.
pub def_path_hash: u64,
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,
}
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.
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) {
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);
}
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);
}
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,
}
}
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)
}
}
- if adt.has_dtor() {
+ if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
/// (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
};
}
}
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)
});
}
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
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)
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",
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 {:?}",
// 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() =>
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
///
/// 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,
};
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());
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();
trait_items: _,
impl_items: _,
bodies: _,
+
+ trait_impls: _,
+ trait_default_impl: _,
} = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
}
_ => return,
};
- if def.has_dtor() {
+ if def.has_dtor(cx.tcx) {
return;
}
let parameter_environment = cx.tcx.empty_parameter_environment();
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.
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)
_ => 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,
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,
};
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
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();
}
// 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,
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);
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);
/// 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;
}
_ => {}
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
// 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
};
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();
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;
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;
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
// 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();
// 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();
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() {
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)
}
}
}
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<DefId>,
- 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<F>(&self, trait_def_id: Option<DefId>, 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) {
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>,
--- /dev/null
+// 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 });
+}
// 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<maps::queries::inherent_impls<'tcx>>>,
-}
-
-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<DefId> {
- 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"
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);
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);
}
//! 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;
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> {
/// Checks exactly one impl for orphan rules and other such
/// restrictions. In this fn, it can happen that multiple errors
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 {}",
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),
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,
//! 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<ast::NodeId>,
-}
+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
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,
}
}
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));
- }
- }
- }
}
_ => {}
}
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);
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);
}
_ => {}
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);
}
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>,
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
pub fn provide(providers: &mut Providers) {
collect::provide(providers);
+ coherence::provide(providers);
check::provide(providers);
}
use std::iter::once;
use syntax::ast;
+use syntax_pos::DUMMY_SP;
use rustc::hir;
use rustc::hir::def::{Def, CtorKind};
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
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) {
//~^ 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() {
}
impl<A> 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() {
trait MyTrait {}
impl MyTrait for .. {}
+//~^ ERROR redundant default implementations of trait `MyTrait`
impl MyTrait for .. {}
-//~^ ERROR redundant default implementations of trait `MyTrait`
trait MySafeTrait {}
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() {
}
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
--> $DIR/E0204.rs:17:10
|
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<u32> },
+ | ----------- 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
|