Make the existential type errors a little bit more helpful
This commit is contained in:
parent
984688ace3
commit
f2241f640b
7 changed files with 32 additions and 12 deletions
|
|
@ -1355,10 +1355,9 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
|
||||
// skip binder is ok, since we only use this to find generic parameters and their
|
||||
// positions.
|
||||
for subst in substs.iter() {
|
||||
for (idx, subst) in substs.iter().enumerate() {
|
||||
if let UnpackedKind::Type(ty) = subst.unpack() {
|
||||
if let ty::Param(p) = ty.sty {
|
||||
let idx = index_map.len();
|
||||
if index_map.insert(p, idx).is_some() {
|
||||
// there was already an entry for `p`, meaning a generic parameter
|
||||
// was used twice
|
||||
|
|
@ -1391,20 +1390,24 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
}).collect();
|
||||
if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
|
||||
let mut ty = concrete_type.walk().fuse();
|
||||
let mut prev_ty = prev_ty.walk().fuse();
|
||||
let iter_eq = (&mut ty).zip(&mut prev_ty).all(|(t, p)| match (&t.sty, &p.sty) {
|
||||
let mut p_ty = prev_ty.walk().fuse();
|
||||
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) {
|
||||
// type parameters are equal to any other type parameter for the purpose of
|
||||
// concrete type equality, as it is possible to obtain the same type just
|
||||
// by passing matching parameters to a function.
|
||||
(ty::Param(_), ty::Param(_)) => true,
|
||||
_ => t == p,
|
||||
});
|
||||
if !iter_eq || ty.next().is_some() || prev_ty.next().is_some() {
|
||||
if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
|
||||
// found different concrete types for the existential type
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
"concrete type differs from previous defining existential type use",
|
||||
);
|
||||
err.span_label(
|
||||
span,
|
||||
format!("expected `{}`, got `{}`", prev_ty, concrete_type),
|
||||
);
|
||||
err.span_note(prev_span, "previous use here");
|
||||
err.emit();
|
||||
} else if indices != *prev_indices {
|
||||
|
|
@ -1413,6 +1416,23 @@ fn find_existential_constraints<'a, 'tcx>(
|
|||
span,
|
||||
"concrete type's generic parameters differ from previous defining use",
|
||||
);
|
||||
use std::fmt::Write;
|
||||
let mut s = String::new();
|
||||
write!(s, "expected [").unwrap();
|
||||
let list = |s: &mut String, indices: &Vec<usize>| {
|
||||
let mut indices = indices.iter().cloned();
|
||||
if let Some(first) = indices.next() {
|
||||
write!(s, "`{}`", substs[first]).unwrap();
|
||||
for i in indices {
|
||||
write!(s, ", `{}`", substs[i]).unwrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
list(&mut s, prev_indices);
|
||||
write!(s, "], got [").unwrap();
|
||||
list(&mut s, &indices);
|
||||
write!(s, "]").unwrap();
|
||||
err.span_label(span, s);
|
||||
err.span_note(prev_span, "previous use here");
|
||||
err.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use
|
|||
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | 42i32
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `&'static str`, got `i32`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different_defining_uses.rs:8:1
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use
|
|||
LL | / fn bar() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | panic!()
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `&'static str`, got `()`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different_defining_uses_never_type.rs:8:1
|
||||
|
|
@ -20,7 +20,7 @@ error: concrete type differs from previous defining existential type use
|
|||
LL | / fn boo() -> Foo { //~ ERROR concrete type differs from previous
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `&'static str`, got `()`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/different_defining_uses_never_type.rs:8:1
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use
|
|||
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR concrete type differs from previous
|
||||
LL | | Some(t).into_iter()
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `std::iter::Once<T>`, got `std::option::IntoIter<T>`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_different_defining_uses.rs:7:1
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ LL | / fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
|
|||
LL | | //~^ concrete type's generic parameters differ from previous defining use
|
||||
LL | | u
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected [`T`], got [`U`]
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use3.rs:15:1
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
|||
LL | | //~^ concrete type differs from previous
|
||||
LL | | (u, t)
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `(T, U)`, got `(U, T)`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use5.rs:10:1
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
|
|||
LL | | //~^ concrete type differs from previous
|
||||
LL | | (u, t)
|
||||
LL | | }
|
||||
| |_^
|
||||
| |_^ expected `(T, T)`, got `(U, T)`
|
||||
|
|
||||
note: previous use here
|
||||
--> $DIR/generic_duplicate_param_use6.rs:10:1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue