Skip to content

Commit b8fad79

Browse files
Improve error message for Index trait on slices
1 parent e9797d4 commit b8fad79

File tree

3 files changed

+129
-28
lines changed

3 files changed

+129
-28
lines changed

src/libcore/slice.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ impl<T> SliceExt for [T] {
523523
}
524524

525525
#[stable(feature = "rust1", since = "1.0.0")]
526+
#[allow(unused_attributes)]
527+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
526528
impl<T> ops::Index<usize> for [T] {
527529
type Output = T;
528530

@@ -533,6 +535,8 @@ impl<T> ops::Index<usize> for [T] {
533535
}
534536

535537
#[stable(feature = "rust1", since = "1.0.0")]
538+
#[allow(unused_attributes)]
539+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
536540
impl<T> ops::IndexMut<usize> for [T] {
537541
#[inline]
538542
fn index_mut(&mut self, index: usize) -> &mut T {

src/librustc/traits/error_reporting.rs

Lines changed: 79 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use hir::def_id::DefId;
2929
use infer::{self, InferCtxt, TypeOrigin};
3030
use ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable};
3131
use ty::fast_reject;
32-
use ty::fold::{TypeFoldable, TypeFolder};
33-
use ty::::subst::{self, Subst};
32+
use ty::fold::TypeFolder;
33+
use ty::subst::{self, Subst};
3434
use util::nodemap::{FnvHashMap, FnvHashSet};
3535

3636
use std::cmp;
@@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
6262
}
6363
}
6464

65-
fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
65+
fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
6666
did: DefId,
6767
obligation: PredicateObligation<'tcx>)
6868
-> subst::Substs<'tcx> {
@@ -82,35 +82,74 @@ fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
8282
substs
8383
}
8484

85+
/*fn check_type_parameters<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
86+
trait_substs: &subst::Substs<'tcx>,
87+
impl_substs: &subst::Substs<'tcx>,
88+
obligation: &PredicateObligation<'tcx>) -> bool {
89+
let trait_types = trait_substs.types.as_slice();
90+
let impl_types = impl_substs.types.as_slice();
91+
92+
let mut failed = 0;
93+
for index_to_ignore in 0..trait_types.len() {
94+
for (index, (trait_type, impl_type)) in trait_types.iter()
95+
.zip(impl_types.iter())
96+
.enumerate() {
97+
if index_to_ignore != index &&
98+
infer::mk_eqty(infcx, true,
99+
TypeOrigin::Misc(obligation.cause.span),
100+
trait_type,
101+
impl_type).is_err() {
102+
failed += 1;
103+
break;
104+
}
105+
}
106+
}
107+
failed == trait_types.len() - 1
108+
}*/
109+
85110
fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
86111
trait_ref: &TraitRef<'tcx>,
87112
obligation: &PredicateObligation<'tcx>)
88-
-> Option<DefId> {
113+
-> Option<(DefId, subst::Substs<'tcx>)> {
114+
println!("1");
89115
let simp = fast_reject::simplify_type(infcx.tcx,
90116
trait_ref.self_ty(),
91117
true);
92118
let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id);
93119

94120
match simp {
95121
Some(_) => {
96-
let mut ret = None;
122+
println!("2");
123+
let mut matching_impls = Vec::new();
97124
trait_def.for_each_impl(infcx.tcx, |def_id| {
98125
let imp = infcx.tcx.impl_trait_ref(def_id).unwrap();
99-
let imp = imp.subst(infcx.tcx, &impl_self_ty(infcx, def_id, obligation.clone()));
100-
if ret.is_none() {
101-
for error in infcx.reported_trait_errors.borrow().iter() {
102-
if let ty::Predicate::Trait(ref t) = error.predicate {
103-
if infer::mk_eqty(infcx, true, TypeOrigin::Misc(obligation.cause.span),
104-
t.skip_binder().trait_ref.self_ty(),
105-
imp.self_ty()).is_ok() {
106-
ret = Some(def_id);
107-
break;
108-
}
109-
}
110-
}
126+
let substs = impl_substs(infcx, def_id, obligation.clone());
127+
let imp = imp.subst(infcx.tcx, &substs);
128+
129+
if infer::mk_eqty(infcx, true,
130+
TypeOrigin::Misc(obligation.cause.span),
131+
trait_ref.self_ty(),
132+
imp.self_ty()).is_ok() {
133+
//if check_type_parameters(infcx, &trait_ref.substs, &imp.substs, obligation) {
134+
matching_impls.push((def_id, imp.substs.clone()));
135+
//}
111136
}
137+
println!("=> {:?} /// {:?}", def_id, imp.substs);
112138
});
113-
ret
139+
if matching_impls.len() == 0 {
140+
println!("3");
141+
None
142+
} else if matching_impls.len() == 1 {
143+
println!("4");
144+
Some(matching_impls[0].clone())
145+
} else {
146+
println!("5");
147+
// we need to determine which type is the good one!
148+
for &(ref m, ref n) in matching_impls.iter() {
149+
println!("=> {:?} /// {:?}", m, n);
150+
}
151+
Some(matching_impls[0].clone())
152+
}
114153
},
115154
None => None,
116155
}
@@ -128,19 +167,21 @@ fn find_attr<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
128167
None
129168
}
130169

131-
fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
132-
trait_ref: &TraitRef<'tcx>,
133-
obligation: &PredicateObligation<'tcx>)
134-
-> Option<String> {
170+
fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
171+
trait_ref: ty::PolyTraitRef<'tcx>,
172+
obligation: &PredicateObligation<'tcx>) -> Option<String> {
173+
let trait_ref = trait_ref.skip_binder();
174+
//let def_id = trait_ref.def_id;
175+
let mut report = None;
135176
let def_id = match get_current_failing_impl(infcx, trait_ref, obligation) {
136-
Some(def_id) => {
177+
Some((def_id, _)) => {
137178
if let Some(_) = find_attr(infcx, def_id, "rustc_on_unimplemented") {
138179
def_id
139180
} else {
140181
trait_ref.def_id
141182
}
142183
},
143-
None => trait_ref.def_id,
184+
None => trait_ref.def_id,
144185
};
145186
let span = obligation.cause.span;
146187
let mut report = None;
@@ -572,11 +613,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
572613
// "the type `T` can't be frobnicated"
573614
// which is somewhat confusing.
574615
err.help(&format!("consider adding a `where {}` bound",
575-
trait_ref.to_predicate()));
616+
trait_ref.to_predicate()));
576617
} else if let Some(s) = on_unimplemented_note(infcx, trait_ref,
577-
obligation.cause.span) {
578-
// Otherwise, if there is an on-unimplemented note,
579-
// display it.
618+
obligation) {
619+
// If it has a custom "#[rustc_on_unimplemented]"
620+
// error message, let's display it!
580621
err.note(&s);
581622
} else {
582623
let trait_ref = trait_predicate.to_poly_trait_ref();
@@ -624,6 +665,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
624665
}
625666
err
626667
}
668+
// Check if it has a custom "#[rustc_on_unimplemented]"
669+
// error message, report with that message if it does
670+
/*let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
671+
obligation);
672+
if let Some(s) = custom_note {
673+
err.fileline_note(obligation.cause.span, &s);
674+
} else {
675+
note_obligation_cause(infcx, &mut err, obligation);
676+
}*/
677+
err.emit();
627678
}
628679

629680
ty::Predicate::Equate(ref predicate) => {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test if the on_unimplemented message override works
12+
13+
#![feature(on_unimplemented)]
14+
#![feature(rustc_attrs)]
15+
16+
#[rustc_on_unimplemented = "invalid"]
17+
trait Index<Idx: ?Sized> {
18+
type Output: ?Sized;
19+
fn index(&self, index: Idx) -> &Self::Output;
20+
}
21+
22+
struct Foo {
23+
i: usize,
24+
}
25+
26+
#[rustc_on_unimplemented = "a Foo is required to index into a slice"]
27+
impl Index<Foo> for [i32] {
28+
type Output = i32;
29+
fn index(&self, index: Foo) -> &i32 {
30+
&self[index.i]
31+
}
32+
}
33+
34+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
35+
impl Index<usize> for [i32] {
36+
type Output = i32;
37+
fn index(&self, index: usize) -> &i32 {
38+
&self[index]
39+
}
40+
}
41+
42+
#[rustc_error]
43+
fn main() {
44+
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
45+
//~| NOTE a usize is required
46+
}

0 commit comments

Comments
 (0)