diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index e4b98ed6445c7..542dfcbe6284f 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -523,8 +523,7 @@ impl 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 ops::Index for [T] { type Output = T; @@ -535,8 +534,7 @@ impl ops::Index 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 ops::IndexMut 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 ops::Index> for [T] { type Output = [T]; @@ -596,6 +595,7 @@ impl ops::Index> for [T] { /// /// Equivalent to `&self[0 .. end]` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl ops::Index> for [T] { type Output = [T]; @@ -611,6 +611,7 @@ impl ops::Index> 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 ops::Index> for [T] { type Output = [T]; @@ -636,6 +637,7 @@ impl ops::Index for [T] { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl ops::Index> for [T] { type Output = [T]; @@ -651,6 +653,7 @@ impl ops::Index> for [T] { } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl ops::Index> for [T] { type Output = [T]; @@ -671,6 +674,7 @@ impl ops::Index> 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 ops::IndexMut> for [T] { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut [T] { @@ -695,6 +699,7 @@ impl ops::IndexMut> 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 ops::IndexMut> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { @@ -708,6 +713,7 @@ impl ops::IndexMut> 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 ops::IndexMut> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { @@ -730,6 +736,7 @@ impl ops::IndexMut for [T] { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl ops::IndexMut> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut [T] { @@ -743,6 +750,7 @@ impl ops::IndexMut> for [T] { } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl ops::IndexMut> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &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 847aade630f6e..9a69958fea014 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 + 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 { + 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 { 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 { - 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 4bf428ef46d9b..2b972af07ff91 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 3ea617d310ba3..264003bb62b81 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 similarity index 100% rename from src/test/compile-fail/on-unimplemented-bad-anno.rs rename to 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 0000000000000..0df8c41ffe1a8 --- /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 or the MIT license +// , 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); +struct Bar(T); + +#[rustc_on_unimplemented = "trait message"] +trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +#[rustc_on_unimplemented = "on impl for Foo"] +impl Index> for [i32] { + type Output = i32; + fn index(&self, _index: Foo) -> &i32 { + loop {} + } +} + +#[rustc_on_unimplemented = "on impl for Bar"] +impl Index> for [i32] { + type Output = i32; + fn index(&self, _index: Bar) -> &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 similarity index 100% rename from src/test/compile-fail/check_on_unimplemented.rs rename to 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 similarity index 100% rename from src/test/compile-fail/on-unimplemented.rs rename to 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 similarity index 81% rename from src/test/compile-fail/check_on_unimplemented_on_slice.rs rename to src/test/compile-fail/on-unimplemented/slice-index.rs index 6f4b211452c82..6a8f9d471e169 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` }