From f2241f640bb9f04cce88b2d28092cbfcee04c43e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 29 Jan 2019 17:10:08 +0100 Subject: [PATCH] Make the existential type errors a little bit more helpful --- src/librustc_typeck/collect.rs | 30 +++++++++++++++---- .../different_defining_uses.stderr | 2 +- .../different_defining_uses_never_type.stderr | 4 +-- .../generic_different_defining_uses.stderr | 2 +- .../generic_duplicate_param_use3.stderr | 2 +- .../generic_duplicate_param_use5.stderr | 2 +- .../generic_duplicate_param_use6.stderr | 2 +- 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7cdcfec339eee..b26a6a2292a04 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1355,10 +1355,9 @@ fn find_existential_constraints<'a, 'tcx>( let mut index_map: FxHashMap = 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| { + 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(); } diff --git a/src/test/ui/existential_types/different_defining_uses.stderr b/src/test/ui/existential_types/different_defining_uses.stderr index 3b3449bbf11f4..3f9ed96400b54 100644 --- a/src/test/ui/existential_types/different_defining_uses.stderr +++ b/src/test/ui/existential_types/different_defining_uses.stderr @@ -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 diff --git a/src/test/ui/existential_types/different_defining_uses_never_type.stderr b/src/test/ui/existential_types/different_defining_uses_never_type.stderr index 161111e3379f5..e29256a5014f9 100644 --- a/src/test/ui/existential_types/different_defining_uses_never_type.stderr +++ b/src/test/ui/existential_types/different_defining_uses_never_type.stderr @@ -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 diff --git a/src/test/ui/existential_types/generic_different_defining_uses.stderr b/src/test/ui/existential_types/generic_different_defining_uses.stderr index 89f70a873d9dc..3f129658b8fd0 100644 --- a/src/test/ui/existential_types/generic_different_defining_uses.stderr +++ b/src/test/ui/existential_types/generic_different_defining_uses.stderr @@ -4,7 +4,7 @@ error: concrete type differs from previous defining existential type use LL | / fn my_iter2(t: T) -> MyIter { //~ ERROR concrete type differs from previous LL | | Some(t).into_iter() LL | | } - | |_^ + | |_^ expected `std::iter::Once`, got `std::option::IntoIter` | note: previous use here --> $DIR/generic_different_defining_uses.rs:7:1 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr index 8f860e7ee0a40..1c96c15a76919 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use3.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use3.stderr @@ -14,7 +14,7 @@ LL | / fn three(_: T, u: U) -> Two { 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 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr index 52befb9c2e12c..166623801c246 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use5.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use5.stderr @@ -5,7 +5,7 @@ LL | / fn three(t: T, u: U) -> Two { 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 diff --git a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr index 2bf1d0c05e625..da49a83be1f70 100644 --- a/src/test/ui/existential_types/generic_duplicate_param_use6.stderr +++ b/src/test/ui/existential_types/generic_duplicate_param_use6.stderr @@ -5,7 +5,7 @@ LL | / fn three(t: T, u: U) -> Two { 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