Skip to content

Commit

Permalink
Improve error message for Index trait on slices
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Mar 10, 2016
1 parent d8406a3 commit de2fb72
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
4 changes: 4 additions & 0 deletions src/libcore/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ 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"]
impl<T> ops::Index<usize> for [T] {
type Output = T;

Expand All @@ -513,6 +515,8 @@ 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"]
impl<T> ops::IndexMut<usize> for [T] {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut T {
Expand Down
64 changes: 47 additions & 17 deletions src/librustc/middle/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
}

fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
fn impl_substs<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
did: DefId,
obligation: PredicateObligation<'tcx>)
-> subst::Substs<'tcx> {
Expand All @@ -127,35 +127,65 @@ fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
substs
}

fn check_type_parameters<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
trait_substs: &subst::Substs<'tcx>,
impl_substs: &subst::Substs<'tcx>,
obligation: &PredicateObligation<'tcx>) -> bool {
let trait_types = trait_substs.types.as_slice();
let impl_types = impl_substs.types.as_slice();

let mut failed = 0;
for index_to_ignore in 0..trait_types.len() {
for (index, (trait_type, impl_type)) in trait_types.iter()
.zip(impl_types.iter())
.enumerate() {
if index_to_ignore != index &&
infer::mk_eqty(infcx, true,
TypeOrigin::Misc(obligation.cause.span),
trait_type,
impl_type).is_err() {
failed += 1;
break;
}
}
}
failed == trait_types.len() - 1
}

fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
trait_ref: &TraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>)
-> Option<DefId> {
-> Option<(DefId, subst::Substs<'tcx>)> {
let simp = fast_reject::simplify_type(infcx.tcx,
trait_ref.self_ty(),
true);
let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id);

match simp {
Some(_) => {
let mut ret = None;
let mut matching_impls = Vec::new();
trait_def.for_each_impl(infcx.tcx, |def_id| {
let imp = infcx.tcx.impl_trait_ref(def_id).unwrap();
let imp = imp.subst(infcx.tcx, &impl_self_ty(infcx, def_id, obligation.clone()));
if ret.is_none() {
for error in infcx.reported_trait_errors.borrow().iter() {
if let ty::Predicate::Trait(ref t) = error.predicate {
if infer::mk_eqty(infcx, true, TypeOrigin::Misc(obligation.cause.span),
t.skip_binder().trait_ref.self_ty(),
imp.self_ty()).is_ok() {
ret = Some(def_id);
break;
}
}
let substs = impl_substs(infcx, def_id, obligation.clone());
let imp = imp.subst(infcx.tcx, &substs);

if infer::mk_eqty(infcx, true,
TypeOrigin::Misc(obligation.cause.span),
trait_ref.self_ty(),
imp.self_ty()).is_ok() {
if check_type_parameters(infcx, &trait_ref.substs, &imp.substs, obligation) {
matching_impls.push((def_id, imp.substs.clone()));
}
}
});
ret
if matching_impls.len() == 0 {
None
} else if matching_impls.len() == 1 {
Some(matching_impls[0].clone())
} else {
// we need to determine which type is the good one!
Some(matching_impls[0].clone())
}
},
None => None,
}
Expand All @@ -178,14 +208,14 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>)
-> Option<String> {
let def_id = match get_current_failing_impl(infcx, trait_ref, obligation) {
Some(def_id) => {
Some((def_id, _)) => {
if let Some(_) = find_attr(infcx, def_id, "rustc_on_unimplemented") {
def_id
} else {
trait_ref.def_id
}
},
None => trait_ref.def_id,
None => trait_ref.def_id,
};
let span = obligation.cause.span;
let mut report = None;
Expand Down

0 comments on commit de2fb72

Please sign in to comment.