about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/traits/mod.rs3
-rw-r--r--src/librustc/middle/traits/specialize.rs20
-rw-r--r--src/librustc/middle/ty/mod.rs11
-rw-r--r--src/librustc_typeck/check/mod.rs56
-rw-r--r--src/librustc_typeck/coherence/overlap.rs17
-rw-r--r--src/librustc_typeck/diagnostics.rs3
-rw-r--r--src/test/compile-fail/specialization-no-default.rs41
7 files changed, 138 insertions, 13 deletions
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 8d3403021e4..180a1312e25 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 b2339b3080c..39cbd36260d 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<I>
+{
+    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 7fa20f2135a..08119683593 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<V,F>(&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<Span, String> {
+        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 136e8c6569b..b6a1337dce0 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<hir::Defaultness>
+{
+    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 47288e33ad6..97cdcd4ba34 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 1a33a5a562a..79508c2ca9f 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 00000000000..3e23c6e06ea
--- /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 <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.
+
+trait Foo {
+    fn foo(&self);
+    fn bar(&self);
+}
+
+impl<T> 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<T> Bar for T {
+    type T = u8;
+}
+
+impl Bar for u8 {
+    type T = (); //~ ERROR E0520
+}
+
+fn main() {}