Skip to content

Commit de2fb72

Browse files
Improve error message for Index trait on slices
1 parent d8406a3 commit de2fb72

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

src/libcore/slice.rs

+4
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@ impl<T> SliceExt for [T] {
503503
}
504504

505505
#[stable(feature = "rust1", since = "1.0.0")]
506+
#[allow(unused_attributes)]
507+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
506508
impl<T> ops::Index<usize> for [T] {
507509
type Output = T;
508510

@@ -513,6 +515,8 @@ impl<T> ops::Index<usize> for [T] {
513515
}
514516

515517
#[stable(feature = "rust1", since = "1.0.0")]
518+
#[allow(unused_attributes)]
519+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
516520
impl<T> ops::IndexMut<usize> for [T] {
517521
#[inline]
518522
fn index_mut(&mut self, index: usize) -> &mut T {

src/librustc/middle/traits/error_reporting.rs

+47-17
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
107107
}
108108
}
109109

110-
fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
110+
fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
111111
did: DefId,
112112
obligation: PredicateObligation<'tcx>)
113113
-> subst::Substs<'tcx> {
@@ -127,35 +127,65 @@ fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
127127
substs
128128
}
129129

130+
fn check_type_parameters<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
131+
trait_substs: &subst::Substs<'tcx>,
132+
impl_substs: &subst::Substs<'tcx>,
133+
obligation: &PredicateObligation<'tcx>) -> bool {
134+
let trait_types = trait_substs.types.as_slice();
135+
let impl_types = impl_substs.types.as_slice();
136+
137+
let mut failed = 0;
138+
for index_to_ignore in 0..trait_types.len() {
139+
for (index, (trait_type, impl_type)) in trait_types.iter()
140+
.zip(impl_types.iter())
141+
.enumerate() {
142+
if index_to_ignore != index &&
143+
infer::mk_eqty(infcx, true,
144+
TypeOrigin::Misc(obligation.cause.span),
145+
trait_type,
146+
impl_type).is_err() {
147+
failed += 1;
148+
break;
149+
}
150+
}
151+
}
152+
failed == trait_types.len() - 1
153+
}
154+
130155
fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
131156
trait_ref: &TraitRef<'tcx>,
132157
obligation: &PredicateObligation<'tcx>)
133-
-> Option<DefId> {
158+
-> Option<(DefId, subst::Substs<'tcx>)> {
134159
let simp = fast_reject::simplify_type(infcx.tcx,
135160
trait_ref.self_ty(),
136161
true);
137162
let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id);
138163

139164
match simp {
140165
Some(_) => {
141-
let mut ret = None;
166+
let mut matching_impls = Vec::new();
142167
trait_def.for_each_impl(infcx.tcx, |def_id| {
143168
let imp = infcx.tcx.impl_trait_ref(def_id).unwrap();
144-
let imp = imp.subst(infcx.tcx, &impl_self_ty(infcx, def_id, obligation.clone()));
145-
if ret.is_none() {
146-
for error in infcx.reported_trait_errors.borrow().iter() {
147-
if let ty::Predicate::Trait(ref t) = error.predicate {
148-
if infer::mk_eqty(infcx, true, TypeOrigin::Misc(obligation.cause.span),
149-
t.skip_binder().trait_ref.self_ty(),
150-
imp.self_ty()).is_ok() {
151-
ret = Some(def_id);
152-
break;
153-
}
154-
}
169+
let substs = impl_substs(infcx, def_id, obligation.clone());
170+
let imp = imp.subst(infcx.tcx, &substs);
171+
172+
if infer::mk_eqty(infcx, true,
173+
TypeOrigin::Misc(obligation.cause.span),
174+
trait_ref.self_ty(),
175+
imp.self_ty()).is_ok() {
176+
if check_type_parameters(infcx, &trait_ref.substs, &imp.substs, obligation) {
177+
matching_impls.push((def_id, imp.substs.clone()));
155178
}
156179
}
157180
});
158-
ret
181+
if matching_impls.len() == 0 {
182+
None
183+
} else if matching_impls.len() == 1 {
184+
Some(matching_impls[0].clone())
185+
} else {
186+
// we need to determine which type is the good one!
187+
Some(matching_impls[0].clone())
188+
}
159189
},
160190
None => None,
161191
}
@@ -178,14 +208,14 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
178208
obligation: &PredicateObligation<'tcx>)
179209
-> Option<String> {
180210
let def_id = match get_current_failing_impl(infcx, trait_ref, obligation) {
181-
Some(def_id) => {
211+
Some((def_id, _)) => {
182212
if let Some(_) = find_attr(infcx, def_id, "rustc_on_unimplemented") {
183213
def_id
184214
} else {
185215
trait_ref.def_id
186216
}
187217
},
188-
None => trait_ref.def_id,
218+
None => trait_ref.def_id,
189219
};
190220
let span = obligation.cause.span;
191221
let mut report = None;

0 commit comments

Comments
 (0)