about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/slice.rs17
-rw-r--r--src/librustc/traits/error_reporting.rs98
-rw-r--r--src/librustc_metadata/common.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs34
-rw-r--r--src/test/compile-fail/on-unimplemented/bad-annotation.rs (renamed from src/test/compile-fail/on-unimplemented-bad-anno.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/multiple-impls.rs55
-rw-r--r--src/test/compile-fail/on-unimplemented/on-impl.rs (renamed from src/test/compile-fail/check_on_unimplemented.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/on-trait.rs (renamed from src/test/compile-fail/on-unimplemented.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/slice-index.rs (renamed from src/test/compile-fail/check_on_unimplemented_on_slice.rs)4
9 files changed, 165 insertions, 46 deletions
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index e4b98ed6445..542dfcbe628 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -523,8 +523,7 @@ impl<T> SliceExt for [T] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(unused_attributes)]
-#[rustc_on_unimplemented = "a usize is required to index into a slice"]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<usize> for [T] {
     type Output = T;
 
@@ -535,8 +534,7 @@ impl<T> ops::Index<usize> for [T] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(unused_attributes)]
-#[rustc_on_unimplemented = "a usize is required to index into a slice"]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<usize> for [T] {
     #[inline]
     fn index_mut(&mut self, index: usize) -> &mut T {
@@ -570,6 +568,7 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
 /// Requires that `begin <= end` and `end <= self.len()`,
 /// otherwise slicing will panic.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::Range<usize>> for [T] {
     type Output = [T];
 
@@ -596,6 +595,7 @@ impl<T> ops::Index<ops::Range<usize>> for [T] {
 ///
 /// Equivalent to `&self[0 .. end]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
     type Output = [T];
 
@@ -611,6 +611,7 @@ impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
 ///
 /// Equivalent to `&self[begin .. self.len()]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeFrom<usize>> for [T] {
     type Output = [T];
 
@@ -636,6 +637,7 @@ impl<T> ops::Index<RangeFull> for [T] {
 }
 
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] {
     type Output = [T];
 
@@ -651,6 +653,7 @@ impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] {
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] {
     type Output = [T];
 
@@ -671,6 +674,7 @@ impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] {
 /// Requires that `begin <= end` and `end <= self.len()`,
 /// otherwise slicing will panic.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
@@ -695,6 +699,7 @@ impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
 ///
 /// Equivalent to `&mut self[0 .. end]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
@@ -708,6 +713,7 @@ impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
 ///
 /// Equivalent to `&mut self[begin .. self.len()]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
@@ -730,6 +736,7 @@ impl<T> ops::IndexMut<RangeFull> for [T] {
 }
 
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
@@ -743,6 +750,7 @@ impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] {
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
@@ -1933,4 +1941,3 @@ macro_rules! impl_marker_for {
 
 impl_marker_for!(BytewiseEquality,
                  u8 i8 u16 i16 u32 i32 u64 i64 usize isize char bool);
-
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 847aade630f..9a69958fea0 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -30,7 +30,7 @@ use infer::{InferCtxt};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::fast_reject;
 use ty::fold::TypeFolder;
-use ty::subst::{self, Subst};
+use ty::subst::{self, Subst, TypeSpace};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
 use std::cmp;
@@ -135,8 +135,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         let ity = tcx.lookup_item_type(did);
         let (tps, rps, _) =
-            (ity.generics.types.get_slice(subst::TypeSpace),
-             ity.generics.regions.get_slice(subst::TypeSpace),
+            (ity.generics.types.get_slice(TypeSpace),
+             ity.generics.regions.get_slice(TypeSpace),
              ity.ty);
 
         let rps = self.region_vars_for_defs(obligation.cause.span, rps);
@@ -144,56 +144,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             subst::VecPerParamSpace::empty(),
             subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
         self.type_vars_for_defs(obligation.cause.span,
-                                subst::ParamSpace::TypeSpace,
+                                TypeSpace,
                                 &mut substs,
                                 tps);
         substs
     }
 
-    fn impl_with_self_type_of(&self,
-                              trait_ref: ty::PolyTraitRef<'tcx>,
-                              obligation: &PredicateObligation<'tcx>)
-                              -> Option<DefId>
+    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+        /// returns the fuzzy category of a given type, or None
+        /// if the type can be equated to any type.
+        fn type_category<'tcx>(t: Ty<'tcx>) -> Option<u32> {
+            match t.sty {
+                ty::TyBool => Some(0),
+                ty::TyChar => Some(1),
+                ty::TyStr => Some(2),
+                ty::TyInt(..) | ty::TyUint(..) |
+                ty::TyInfer(ty::IntVar(..)) => Some(3),
+                ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4),
+                ty::TyEnum(..) => Some(5),
+                ty::TyStruct(..) => Some(6),
+                ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7),
+                ty::TyArray(..) | ty::TySlice(..) => Some(8),
+                ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9),
+                ty::TyTrait(..) => Some(10),
+                ty::TyClosure(..) => Some(11),
+                ty::TyTuple(..) => Some(12),
+                ty::TyProjection(..) => Some(13),
+                ty::TyParam(..) => Some(14),
+                ty::TyInfer(..) | ty::TyError => None
+            }
+        }
+
+        match (type_category(a), type_category(b)) {
+            (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) {
+                (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) |
+                (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) =>
+                    def_a == def_b,
+                _ => cat_a == cat_b
+            },
+            // infer and error can be equated to all types
+            _ => true
+        }
+    }
+
+    fn impl_similar_to(&self,
+                       trait_ref: ty::PolyTraitRef<'tcx>,
+                       obligation: &PredicateObligation<'tcx>)
+                       -> Option<DefId>
     {
         let tcx = self.tcx;
-        let mut result = None;
-        let mut ambiguous = false;
 
-        let trait_self_ty = tcx.erase_late_bound_regions(&trait_ref).self_ty();
+        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
+        let trait_self_ty = trait_ref.self_ty();
 
-        if trait_self_ty.is_ty_var() {
-            return None;
-        }
+        let mut self_match_impls = vec![];
+        let mut fuzzy_match_impls = vec![];
 
-        self.tcx.lookup_trait_def(trait_ref.def_id())
+        self.tcx.lookup_trait_def(trait_ref.def_id)
             .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| {
-                let impl_self_ty = tcx
+                let impl_trait_ref = tcx
                     .impl_trait_ref(def_id)
                     .unwrap()
-                    .self_ty()
                     .subst(tcx, &self.impl_substs(def_id, obligation.clone()));
 
-                if !tcx.has_attr(def_id, "rustc_on_unimplemented") {
-                    return;
-                }
+                let impl_self_ty = impl_trait_ref.self_ty();
 
                 if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
-                    ambiguous = result.is_some();
-                    result = Some(def_id);
+                    self_match_impls.push(def_id);
+
+                    if trait_ref.substs.types.get_slice(TypeSpace).iter()
+                        .zip(impl_trait_ref.substs.types.get_slice(TypeSpace))
+                        .all(|(u,v)| self.fuzzy_match_tys(u, v))
+                    {
+                        fuzzy_match_impls.push(def_id);
+                    }
                 }
             });
 
-        if ambiguous {
-            None
+        let impl_def_id = if self_match_impls.len() == 1 {
+            self_match_impls[0]
+        } else if fuzzy_match_impls.len() == 1 {
+            fuzzy_match_impls[0]
         } else {
-            result
+            return None
+        };
+
+        if tcx.has_attr(impl_def_id, "rustc_on_unimplemented") {
+            Some(impl_def_id)
+        } else {
+            None
         }
     }
 
     fn on_unimplemented_note(&self,
                              trait_ref: ty::PolyTraitRef<'tcx>,
                              obligation: &PredicateObligation<'tcx>) -> Option<String> {
-        let def_id = self.impl_with_self_type_of(trait_ref, obligation)
+        let def_id = self.impl_similar_to(trait_ref, obligation)
             .unwrap_or(trait_ref.def_id());
         let trait_ref = trait_ref.skip_binder();
 
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index 4bf428ef46d..2b972af07ff 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -247,8 +247,7 @@ pub const tag_rustc_version: usize = 0x10f;
 pub fn rustc_version() -> String {
     format!(
         "rustc {}",
-//        option_env!("CFG_VERSION").unwrap_or("unknown version")
-        "nightly edition"
+        option_env!("CFG_VERSION").unwrap_or("unknown version")
     )
 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3ea617d310b..264003bb62b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -732,17 +732,26 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           match ccx.tcx.impl_trait_ref(impl_def_id) {
               Some(impl_trait_ref) => {
-                check_impl_items_against_trait(ccx,
-                                               it.span,
-                                               impl_def_id,
-                                               &impl_trait_ref,
-                                               impl_items);
+                  let trait_def_id = impl_trait_ref.def_id;
+
+                  check_impl_items_against_trait(ccx,
+                                                 it.span,
+                                                 impl_def_id,
+                                                 &impl_trait_ref,
+                                                 impl_items);
+                  check_on_unimplemented(
+                      ccx,
+                      &ccx.tcx.lookup_trait_def(trait_def_id).generics,
+                      it,
+                      ccx.tcx.item_name(trait_def_id));
               }
               None => { }
           }
       }
-      hir::ItemTrait(_, ref generics, _, _) => {
-        check_trait_on_unimplemented(ccx, generics, it);
+      hir::ItemTrait(..) => {
+        let def_id = ccx.tcx.map.local_def_id(it.id);
+        let generics = &ccx.tcx.lookup_trait_def(def_id).generics;
+        check_on_unimplemented(ccx, generics, it, it.name);
       }
       hir::ItemStruct(..) => {
         check_struct(ccx, it.id, it.span);
@@ -854,15 +863,16 @@ fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                               generics: &hir::Generics,
-                               item: &hir::Item) {
+fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                    generics: &ty::Generics,
+                                    item: &hir::Item,
+                                    name: ast::Name) {
     if let Some(ref attr) = item.attrs.iter().find(|a| {
         a.check_name("rustc_on_unimplemented")
     }) {
         if let Some(ref istring) = attr.value_str() {
             let parser = Parser::new(&istring);
-            let types = &generics.ty_params;
+            let types = &generics.types;
             for token in parser {
                 match token {
                     Piece::String(_) => (), // Normal string, no need to check it
@@ -878,7 +888,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 span_err!(ccx.tcx.sess, attr.span, E0230,
                                                  "there is no type parameter \
                                                           {} on trait {}",
-                                                           s, item.name);
+                                                           s, name);
                             }
                         },
                         // `{:1}` and `{}` are not to be used
diff --git a/src/test/compile-fail/on-unimplemented-bad-anno.rs b/src/test/compile-fail/on-unimplemented/bad-annotation.rs
index 8580749084d..8580749084d 100644
--- a/src/test/compile-fail/on-unimplemented-bad-anno.rs
+++ b/src/test/compile-fail/on-unimplemented/bad-annotation.rs
diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs
new file mode 100644
index 00000000000..0df8c41ffe1
--- /dev/null
+++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs
@@ -0,0 +1,55 @@
+// Copyright 2016 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.
+
+// Test if the on_unimplemented message override works
+
+#![feature(on_unimplemented)]
+#![feature(rustc_attrs)]
+
+struct Foo<T>(T);
+struct Bar<T>(T);
+
+#[rustc_on_unimplemented = "trait message"]
+trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+#[rustc_on_unimplemented = "on impl for Foo"]
+impl Index<Foo<usize>> for [i32] {
+    type Output = i32;
+    fn index(&self, _index: Foo<usize>) -> &i32 {
+        loop {}
+    }
+}
+
+#[rustc_on_unimplemented = "on impl for Bar"]
+impl Index<Bar<usize>> for [i32] {
+    type Output = i32;
+    fn index(&self, _index: Bar<usize>) -> &i32 {
+        loop {}
+    }
+}
+
+#[rustc_error]
+fn main() {
+    Index::index(&[] as &[i32], 2u32);
+    //~^ ERROR E0277
+    //~| NOTE trait message
+    //~| NOTE required by
+    Index::index(&[] as &[i32], Foo(2u32));
+    //~^ ERROR E0277
+    //~| NOTE on impl for Foo
+    //~| NOTE required by
+    Index::index(&[] as &[i32], Bar(2u32));
+    //~^ ERROR E0277
+    //~| NOTE on impl for Bar
+    //~| NOTE required by
+}
diff --git a/src/test/compile-fail/check_on_unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs
index 4471b625d79..4471b625d79 100644
--- a/src/test/compile-fail/check_on_unimplemented.rs
+++ b/src/test/compile-fail/on-unimplemented/on-impl.rs
diff --git a/src/test/compile-fail/on-unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs
index 39ce1b33ca1..39ce1b33ca1 100644
--- a/src/test/compile-fail/on-unimplemented.rs
+++ b/src/test/compile-fail/on-unimplemented/on-trait.rs
diff --git a/src/test/compile-fail/check_on_unimplemented_on_slice.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs
index 6f4b211452c..6a8f9d471e1 100644
--- a/src/test/compile-fail/check_on_unimplemented_on_slice.rs
+++ b/src/test/compile-fail/on-unimplemented/slice-index.rs
@@ -18,5 +18,7 @@ use std::ops::Index;
 fn main() {
     let x = &[1, 2, 3] as &[i32];
     x[1i32]; //~ ERROR E0277
-             //~| NOTE a usize is required
+             //~| NOTE slice indices are of type `usize`
+    x[..1i32]; //~ ERROR E0277
+               //~| NOTE slice indices are of type `usize`
 }