diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 8d3403021e41..180a1312e250 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -50,7 +50,8 @@ pub use self::select::SelectionContext; pub use self::select::SelectionCache; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants -pub use self::specialize::{Overlap, SpecializationGraph, get_impl_item_or_default, ItemSource, specializes}; +pub use self::specialize::{Overlap, SpecializationGraph, specializes}; +pub use self::specialize::{ItemSource, get_impl_item_or_default, get_parent_impl_item}; pub use self::util::elaborate_predicates; pub use self::util::get_vtable_index_of_object_method; pub use self::util::trait_ref_for_builtin_bound; diff --git a/src/librustc/middle/traits/specialize.rs b/src/librustc/middle/traits/specialize.rs index b2339b3080c9..39cbd36260db 100644 --- a/src/librustc/middle/traits/specialize.rs +++ b/src/librustc/middle/traits/specialize.rs @@ -299,6 +299,26 @@ pub fn get_impl_item_or_default<'tcx, I, F>(tcx: &ty::ctxt<'tcx>, None } +/// Convenience function for locating an item defined in a specialization parent, if any. +pub fn get_parent_impl_item<'tcx, I, F>(tcx: &ty::ctxt<'tcx>, + child_impl: DefId, + f: F) + -> Option<(I, DefId)> + where F: for<'a> FnMut(&ImplOrTraitItem<'tcx>) -> Option +{ + let trait_def_id = tcx.trait_id_of_impl(child_impl).unwrap(); + let trait_def = tcx.lookup_trait_def(trait_def_id); + + trait_def.parent_of_impl(child_impl) + .and_then(|parent_impl| get_impl_item_or_default(tcx, parent_impl, f)) + .and_then(|(item, source)| { + match source { + ItemSource::Trait { .. } => None, + ItemSource::Impl { actual_impl, .. } => Some((item, actual_impl)), + } + }) +} + fn skolemizing_subst_for_impl<'a>(tcx: &ty::ctxt<'a>, impl_def_id: DefId) -> Substs<'a> { let impl_generics = tcx.lookup_item_type(impl_def_id).generics; diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 7fa20f2135ae..081196835936 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -2670,7 +2670,6 @@ impl<'tcx> TyCtxt<'tcx> { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } - pub fn visit_all_items_in_krate(&self, dep_node_fn: F, visitor: &mut V) @@ -2678,6 +2677,16 @@ impl<'tcx> TyCtxt<'tcx> { { dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor); } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` + /// with the name of the crate containing the impl. + pub fn span_of_impl(&self, impl_did: DefId) -> Result { + if impl_did.is_local() { + let node_id = self.map.as_local_node_id(impl_did).unwrap(); + Ok(self.map.span(node_id)) + } else { + Err(self.sess.cstore.crate_name(impl_did.krate)) + } + } } /// The category of explicit self. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 136e8c6569b7..b6a1337dce05 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -127,7 +127,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use rustc_front::intravisit::{self, Visitor}; use rustc_front::hir; -use rustc_front::hir::{Visibility, PatKind}; +use rustc_front::hir::{Visibility, PatKind, Defaultness}; use rustc_front::print::pprust; use rustc_back::slice; @@ -864,6 +864,33 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env); } +fn check_specialization_validity<'tcx, F>(tcx: &ty::ctxt<'tcx>, + impl_id: DefId, + impl_item: &hir::ImplItem, + f: F) + where F: FnMut(&ty::ImplOrTraitItem<'tcx>) -> Option +{ + let parent_item_opt = traits::get_parent_impl_item(tcx, impl_id, f); + if let Some((Defaultness::Final, parent_impl)) = parent_item_opt { + span_err!(tcx.sess, impl_item.span, E0520, + "item `{}` is provided by an implementation that \ + specializes another, but the item in the parent \ + implementations is not marked `default` and so it \ + cannot be specialized.", + impl_item.name); + + match tcx.span_of_impl(parent_impl) { + Ok(span) => { + span_note!(tcx.sess, span, "parent implementation is here:"); + } + Err(cname) => { + tcx.sess.note(&format!("parent implementation is in crate `{}`", + cname)); + } + } + } +} + fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, @@ -903,6 +930,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_const.name, impl_trait_ref) } + + check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| { + if let &ty::ConstTraitItem(ref trait_const) = cand { + if trait_const.name == impl_item.name { + return Some(trait_const.defaultness); + } + } + None + }); } hir::ImplItemKind::Method(ref sig, ref body) => { check_trait_fn_not_const(ccx, impl_item.span, sig.constness); @@ -926,6 +962,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_method.name, impl_trait_ref) } + + check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| { + if let &ty::MethodTraitItem(ref meth) = cand { + if meth.name == impl_method.name { + return Some(meth.defaultness); + } + } + None + }); } hir::ImplItemKind::Type(_) => { let impl_type = match ty_impl_item { @@ -944,6 +989,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_type.name, impl_trait_ref) } + + check_specialization_validity(ccx.tcx, impl_id, impl_item, |cand| { + if let &ty::TypeTraitItem(ref at) = cand { + if at.name == impl_item.name { + return Some(at.defaultness); + } + } + None + }); } } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 47288e33ad61..97cdcd4ba34e 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -13,12 +13,10 @@ //! constructor provide a method with the same name. use middle::cstore::CrateStore; -use middle::def_id::DefId; use middle::traits; use middle::ty::{self, TyCtxt}; use middle::infer; use syntax::ast; -use syntax::codemap::Span; use rustc::dep_graph::DepNode; use rustc_front::hir; use rustc_front::intravisit; @@ -169,13 +167,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { overlap.on_trait_ref, self_type); - if overlap.with_impl.is_local() { - span_note!(self.tcx.sess, self.span_of_def_id(overlap.with_impl), - "conflicting implementation is here:"); - } else { - let cname = self.tcx.sess.cstore.crate_name(overlap.with_impl.krate); - self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", - cname)); + match self.tcx.span_of_impl(overlap.with_impl) { + Ok(span) => { + span_note!(self.tcx.sess, span, "conflicting implementation is here:"); + } + Err(cname) => { + self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", + cname)); + } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1a33a5a562a9..79508c2ca9f8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3696,5 +3696,6 @@ register_diagnostics! { // type `{}` was overridden E0436, // functional record update requires a struct E0513, // no type for local variable .. - E0519 // redundant default implementations of trait + E0519, // redundant default implementations of trait + E0520 // cannot specialize non-default item } diff --git a/src/test/compile-fail/specialization-no-default.rs b/src/test/compile-fail/specialization-no-default.rs new file mode 100644 index 000000000000..3e23c6e06eaf --- /dev/null +++ b/src/test/compile-fail/specialization-no-default.rs @@ -0,0 +1,41 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn foo(&self); + fn bar(&self); +} + +impl Foo for T { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Foo for u8 {} +impl Foo for u16 { + fn foo(&self) {} //~ ERROR E0520 +} +impl Foo for u32 { + fn bar(&self) {} //~ ERROR E0520 +} + +trait Bar { + type T; +} + +impl Bar for T { + type T = u8; +} + +impl Bar for u8 { + type T = (); //~ ERROR E0520 +} + +fn main() {}