Do not assume const params are printed after type params
This commit is contained in:
parent
39dc268459
commit
97e07da611
4 changed files with 130 additions and 147 deletions
|
@ -717,53 +717,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
value: &mut DiagStyledString,
|
value: &mut DiagStyledString,
|
||||||
other_value: &mut DiagStyledString,
|
other_value: &mut DiagStyledString,
|
||||||
name: String,
|
name: String,
|
||||||
sub: ty::GenericArgsRef<'tcx>,
|
args: &[ty::GenericArg<'tcx>],
|
||||||
pos: usize,
|
pos: usize,
|
||||||
other_ty: Ty<'tcx>,
|
other_ty: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
// `value` and `other_value` hold two incomplete type representation for display.
|
// `value` and `other_value` hold two incomplete type representation for display.
|
||||||
// `name` is the path of both types being compared. `sub`
|
// `name` is the path of both types being compared. `sub`
|
||||||
value.push_highlighted(name);
|
value.push_highlighted(name);
|
||||||
let len = sub.len();
|
|
||||||
if len > 0 {
|
if args.is_empty() {
|
||||||
value.push_highlighted("<");
|
return;
|
||||||
}
|
}
|
||||||
|
value.push_highlighted("<");
|
||||||
|
|
||||||
// Output the lifetimes for the first type
|
for (i, arg) in args.iter().enumerate() {
|
||||||
let lifetimes = sub
|
if i > 0 {
|
||||||
.regions()
|
|
||||||
.map(|lifetime| {
|
|
||||||
let s = lifetime.to_string();
|
|
||||||
if s.is_empty() { "'_".to_string() } else { s }
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ");
|
|
||||||
if !lifetimes.is_empty() {
|
|
||||||
if sub.regions().count() < len {
|
|
||||||
value.push_normal(lifetimes + ", ");
|
|
||||||
} else {
|
|
||||||
value.push_normal(lifetimes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Highlight all the type arguments that aren't at `pos` and compare the type argument at
|
|
||||||
// `pos` and `other_ty`.
|
|
||||||
for (i, type_arg) in sub.types().enumerate() {
|
|
||||||
if i == pos {
|
|
||||||
let values = self.cmp(type_arg, other_ty);
|
|
||||||
value.0.extend((values.0).0);
|
|
||||||
other_value.0.extend((values.1).0);
|
|
||||||
} else {
|
|
||||||
value.push_highlighted(type_arg.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if len > 0 && i != len - 1 {
|
|
||||||
value.push_normal(", ");
|
value.push_normal(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match arg.unpack() {
|
||||||
|
ty::GenericArgKind::Lifetime(lt) => {
|
||||||
|
let s = lt.to_string();
|
||||||
|
value.push_normal(if s.is_empty() { "'_" } else { &s });
|
||||||
|
}
|
||||||
|
ty::GenericArgKind::Const(ct) => {
|
||||||
|
value.push_normal(ct.to_string());
|
||||||
|
}
|
||||||
|
// Highlight all the type arguments that aren't at `pos` and compare
|
||||||
|
// the type argument at `pos` and `other_ty`.
|
||||||
|
ty::GenericArgKind::Type(type_arg) => {
|
||||||
|
if i == pos {
|
||||||
|
let values = self.cmp(type_arg, other_ty);
|
||||||
|
value.0.extend((values.0).0);
|
||||||
|
other_value.0.extend((values.1).0);
|
||||||
|
} else {
|
||||||
|
value.push_highlighted(type_arg.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len > 0 {
|
|
||||||
value.push_highlighted(">");
|
value.push_highlighted(">");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
|
/// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`,
|
||||||
|
@ -791,27 +785,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
t1_out: &mut DiagStyledString,
|
t1_out: &mut DiagStyledString,
|
||||||
t2_out: &mut DiagStyledString,
|
t2_out: &mut DiagStyledString,
|
||||||
path: String,
|
path: String,
|
||||||
sub: &'tcx [ty::GenericArg<'tcx>],
|
args: &'tcx [ty::GenericArg<'tcx>],
|
||||||
other_path: String,
|
other_path: String,
|
||||||
other_ty: Ty<'tcx>,
|
other_ty: Ty<'tcx>,
|
||||||
) -> Option<()> {
|
) -> bool {
|
||||||
// FIXME/HACK: Go back to `GenericArgsRef` to use its inherent methods,
|
for (i, arg) in args.iter().enumerate() {
|
||||||
// ideally that shouldn't be necessary.
|
if let Some(ta) = arg.as_type() {
|
||||||
let sub = self.tcx.mk_args(sub);
|
if ta == other_ty {
|
||||||
for (i, ta) in sub.types().enumerate() {
|
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
|
||||||
if ta == other_ty {
|
return true;
|
||||||
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
|
}
|
||||||
return Some(());
|
if let ty::Adt(def, _) = ta.kind() {
|
||||||
}
|
let path_ = self.tcx.def_path_str(def.did());
|
||||||
if let ty::Adt(def, _) = ta.kind() {
|
if path_ == other_path {
|
||||||
let path_ = self.tcx.def_path_str(def.did());
|
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
|
||||||
if path_ == other_path {
|
return true;
|
||||||
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
|
}
|
||||||
return Some(());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a `,` to the type representation only if it is appropriate.
|
/// Adds a `,` to the type representation only if it is appropriate.
|
||||||
|
@ -819,10 +812,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
value: &mut DiagStyledString,
|
value: &mut DiagStyledString,
|
||||||
other_value: &mut DiagStyledString,
|
other_value: &mut DiagStyledString,
|
||||||
len: usize,
|
|
||||||
pos: usize,
|
pos: usize,
|
||||||
) {
|
) {
|
||||||
if len > 0 && pos != len - 1 {
|
if pos > 0 {
|
||||||
value.push_normal(", ");
|
value.push_normal(", ");
|
||||||
other_value.push_normal(", ");
|
other_value.push_normal(", ");
|
||||||
}
|
}
|
||||||
|
@ -899,10 +891,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let len2 = sig2.inputs().len();
|
let len2 = sig2.inputs().len();
|
||||||
if len1 == len2 {
|
if len1 == len2 {
|
||||||
for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
|
for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
|
||||||
|
self.push_comma(&mut values.0, &mut values.1, i);
|
||||||
let (x1, x2) = self.cmp(*l, *r);
|
let (x1, x2) = self.cmp(*l, *r);
|
||||||
(values.0).0.extend(x1.0);
|
(values.0).0.extend(x1.0);
|
||||||
(values.1).0.extend(x2.0);
|
(values.1).0.extend(x2.0);
|
||||||
self.push_comma(&mut values.0, &mut values.1, len1, i);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i, l) in sig1.inputs().iter().enumerate() {
|
for (i, l) in sig1.inputs().iter().enumerate() {
|
||||||
|
@ -1150,14 +1142,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let len1 = sub_no_defaults_1.len();
|
let len1 = sub_no_defaults_1.len();
|
||||||
let len2 = sub_no_defaults_2.len();
|
let len2 = sub_no_defaults_2.len();
|
||||||
let common_len = cmp::min(len1, len2);
|
let common_len = cmp::min(len1, len2);
|
||||||
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
|
let remainder1 = &sub1[common_len..];
|
||||||
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
|
let remainder2 = &sub2[common_len..];
|
||||||
let common_default_params =
|
let common_default_params =
|
||||||
iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
|
iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
|
||||||
.filter(|(a, b)| a == b)
|
.filter(|(a, b)| a == b)
|
||||||
.count();
|
.count();
|
||||||
let len = sub1.len() - common_default_params;
|
let len = sub1.len() - common_default_params;
|
||||||
let consts_offset = len - sub1.consts().count();
|
|
||||||
|
|
||||||
// Only draw `<...>` if there are lifetime/type arguments.
|
// Only draw `<...>` if there are lifetime/type arguments.
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
|
@ -1169,70 +1160,68 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let s = lifetime.to_string();
|
let s = lifetime.to_string();
|
||||||
if s.is_empty() { "'_".to_string() } else { s }
|
if s.is_empty() { "'_".to_string() } else { s }
|
||||||
}
|
}
|
||||||
// At one point we'd like to elide all lifetimes here, they are irrelevant for
|
|
||||||
// all diagnostics that use this output
|
|
||||||
//
|
|
||||||
// Foo<'x, '_, Bar>
|
|
||||||
// Foo<'y, '_, Qux>
|
|
||||||
// ^^ ^^ --- type arguments are not elided
|
|
||||||
// | |
|
|
||||||
// | elided as they were the same
|
|
||||||
// not elided, they were different, but irrelevant
|
|
||||||
//
|
|
||||||
// For bound lifetimes, keep the names of the lifetimes,
|
|
||||||
// even if they are the same so that it's clear what's happening
|
|
||||||
// if we have something like
|
|
||||||
//
|
|
||||||
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
|
|
||||||
// for<'r> fn(Inv<'r>, Inv<'r>)
|
|
||||||
let lifetimes = sub1.regions().zip(sub2.regions());
|
|
||||||
for (i, lifetimes) in lifetimes.enumerate() {
|
|
||||||
let l1 = lifetime_display(lifetimes.0);
|
|
||||||
let l2 = lifetime_display(lifetimes.1);
|
|
||||||
if lifetimes.0 != lifetimes.1 {
|
|
||||||
values.0.push_highlighted(l1);
|
|
||||||
values.1.push_highlighted(l2);
|
|
||||||
} else if lifetimes.0.is_bound() || self.tcx.sess.opts.verbose {
|
|
||||||
values.0.push_normal(l1);
|
|
||||||
values.1.push_normal(l2);
|
|
||||||
} else {
|
|
||||||
values.0.push_normal("'_");
|
|
||||||
values.1.push_normal("'_");
|
|
||||||
}
|
|
||||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're comparing two types with the same path, so we compare the type
|
for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
|
||||||
// arguments for both. If they are the same, do not highlight and elide from the
|
self.push_comma(&mut values.0, &mut values.1, i);
|
||||||
// output.
|
match arg1.unpack() {
|
||||||
// Foo<_, Bar>
|
// At one point we'd like to elide all lifetimes here, they are
|
||||||
// Foo<_, Qux>
|
// irrelevant for all diagnostics that use this output.
|
||||||
// ^ elided type as this type argument was the same in both sides
|
//
|
||||||
let type_arguments = sub1.types().zip(sub2.types());
|
// Foo<'x, '_, Bar>
|
||||||
let regions_len = sub1.regions().count();
|
// Foo<'y, '_, Qux>
|
||||||
let num_display_types = consts_offset - regions_len;
|
// ^^ ^^ --- type arguments are not elided
|
||||||
for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
|
// | |
|
||||||
let i = i + regions_len;
|
// | elided as they were the same
|
||||||
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
|
// not elided, they were different, but irrelevant
|
||||||
values.0.push_normal("_");
|
//
|
||||||
values.1.push_normal("_");
|
// For bound lifetimes, keep the names of the lifetimes,
|
||||||
} else {
|
// even if they are the same so that it's clear what's happening
|
||||||
recurse(ta1, ta2, &mut values);
|
// if we have something like
|
||||||
}
|
//
|
||||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
|
||||||
}
|
// for<'r> fn(Inv<'r>, Inv<'r>)
|
||||||
|
ty::GenericArgKind::Lifetime(l1) => {
|
||||||
|
let l1_str = lifetime_display(l1);
|
||||||
|
let l2 = arg2.expect_region();
|
||||||
|
let l2_str = lifetime_display(l2);
|
||||||
|
if l1 != l2 {
|
||||||
|
values.0.push_highlighted(l1_str);
|
||||||
|
values.1.push_highlighted(l2_str);
|
||||||
|
} else if l1.is_bound() || self.tcx.sess.opts.verbose {
|
||||||
|
values.0.push_normal(l1_str);
|
||||||
|
values.1.push_normal(l2_str);
|
||||||
|
} else {
|
||||||
|
values.0.push_normal("'_");
|
||||||
|
values.1.push_normal("'_");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::GenericArgKind::Type(ta1) => {
|
||||||
|
let ta2 = arg2.expect_ty();
|
||||||
|
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
|
||||||
|
values.0.push_normal("_");
|
||||||
|
values.1.push_normal("_");
|
||||||
|
} else {
|
||||||
|
recurse(ta1, ta2, &mut values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We're comparing two types with the same path, so we compare the type
|
||||||
|
// arguments for both. If they are the same, do not highlight and elide
|
||||||
|
// from the output.
|
||||||
|
// Foo<_, Bar>
|
||||||
|
// Foo<_, Qux>
|
||||||
|
// ^ elided type as this type argument was the same in both sides
|
||||||
|
|
||||||
// Do the same for const arguments, if they are equal, do not highlight and
|
// Do the same for const arguments, if they are equal, do not highlight and
|
||||||
// elide them from the output.
|
// elide them from the output.
|
||||||
let const_arguments = sub1.consts().zip(sub2.consts());
|
ty::GenericArgKind::Const(ca1) => {
|
||||||
for (i, (ca1, ca2)) in const_arguments.enumerate() {
|
let ca2 = arg2.expect_const();
|
||||||
let i = i + consts_offset;
|
maybe_highlight(ca1, ca2, &mut values, self.tcx);
|
||||||
maybe_highlight(ca1, ca2, &mut values, self.tcx);
|
}
|
||||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the type argument bracket.
|
// Close the type argument bracket.
|
||||||
// Only draw `<...>` if there are lifetime/type arguments.
|
// Only draw `<...>` if there are arguments.
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
values.0.push_normal(">");
|
values.0.push_normal(">");
|
||||||
values.1.push_normal(">");
|
values.1.push_normal(">");
|
||||||
|
@ -1244,17 +1233,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
// Foo<Bar<Qux>
|
// Foo<Bar<Qux>
|
||||||
// ------- this type argument is exactly the same as the other type
|
// ------- this type argument is exactly the same as the other type
|
||||||
// Bar<Qux>
|
// Bar<Qux>
|
||||||
if self
|
if self.cmp_type_arg(
|
||||||
.cmp_type_arg(
|
&mut values.0,
|
||||||
&mut values.0,
|
&mut values.1,
|
||||||
&mut values.1,
|
path1.clone(),
|
||||||
path1.clone(),
|
sub_no_defaults_1,
|
||||||
sub_no_defaults_1,
|
path2.clone(),
|
||||||
path2.clone(),
|
t2,
|
||||||
t2,
|
) {
|
||||||
)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
// Check for case:
|
// Check for case:
|
||||||
|
@ -1262,17 +1248,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
// Bar<Qux>
|
// Bar<Qux>
|
||||||
// Foo<Bar<Qux>>
|
// Foo<Bar<Qux>>
|
||||||
// ------- this type argument is exactly the same as the other type
|
// ------- this type argument is exactly the same as the other type
|
||||||
if self
|
if self.cmp_type_arg(
|
||||||
.cmp_type_arg(
|
&mut values.1,
|
||||||
&mut values.1,
|
&mut values.0,
|
||||||
&mut values.0,
|
path2,
|
||||||
path2,
|
sub_no_defaults_2,
|
||||||
sub_no_defaults_2,
|
path1,
|
||||||
path1,
|
t1,
|
||||||
t1,
|
) {
|
||||||
)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1343,8 +1326,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
|
let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
|
||||||
let len = args1.len();
|
let len = args1.len();
|
||||||
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
|
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
|
||||||
|
self.push_comma(&mut values.0, &mut values.1, i);
|
||||||
recurse(left, right, &mut values);
|
recurse(left, right, &mut values);
|
||||||
self.push_comma(&mut values.0, &mut values.1, len, i);
|
|
||||||
}
|
}
|
||||||
if len == 1 {
|
if len == 1 {
|
||||||
// Keep the output for single element tuples as `(ty,)`.
|
// Keep the output for single element tuples as `(ty,)`.
|
||||||
|
|
|
@ -53,7 +53,7 @@ LL | assert_eq!(smart_ptr.a::<&Foo>(), 2);
|
||||||
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
||||||
|
|
|
|
||||||
= note: expected reference `&Foo`
|
= note: expected reference `&Foo`
|
||||||
found struct `SmartPtr<'_, Foo, >`
|
found struct `SmartPtr<'_, Foo>`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16
|
--> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16
|
||||||
|
@ -62,7 +62,7 @@ LL | assert_eq!(smart_ptr.b::<&Foo>(), 1);
|
||||||
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
||||||
|
|
|
|
||||||
= note: expected reference `&Foo`
|
= note: expected reference `&Foo`
|
||||||
found struct `SmartPtr<'_, Foo, >`
|
found struct `SmartPtr<'_, Foo>`
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ LL | smart_ptr.get::<&Foo>();
|
||||||
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
||||||
|
|
|
|
||||||
= note: expected reference `&Foo`
|
= note: expected reference `&Foo`
|
||||||
found struct `SmartPtr<'_, Foo, >`
|
found struct `SmartPtr<'_, Foo>`
|
||||||
|
|
||||||
error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
|
error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
|
||||||
--> $DIR/arbitrary-self-from-method-substs.rs:92:9
|
--> $DIR/arbitrary-self-from-method-substs.rs:92:9
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | pub fn new(thing: T) -> GenericStruct<1, T> {
|
||||||
LL | Self { thing }
|
LL | Self { thing }
|
||||||
| ^^^^^^^^^^^^^^ expected `1`, found `0`
|
| ^^^^^^^^^^^^^^ expected `1`, found `0`
|
||||||
|
|
|
|
||||||
= note: expected struct `GenericStruct<_, 1>`
|
= note: expected struct `GenericStruct<1, _>`
|
||||||
found struct `GenericStruct<_, 0>`
|
found struct `GenericStruct<0, _>`
|
||||||
help: use the type name directly
|
help: use the type name directly
|
||||||
|
|
|
|
||||||
LL | GenericStruct::<1, T> { thing }
|
LL | GenericStruct::<1, T> { thing }
|
||||||
|
@ -25,8 +25,8 @@ LL | pub fn new(thing: T) -> GenericStruct2<1, T> {
|
||||||
LL | Self { 0: thing }
|
LL | Self { 0: thing }
|
||||||
| ^^^^^^^^^^^^^^^^^ expected `1`, found `0`
|
| ^^^^^^^^^^^^^^^^^ expected `1`, found `0`
|
||||||
|
|
|
|
||||||
= note: expected struct `GenericStruct2<_, 1>`
|
= note: expected struct `GenericStruct2<1, _>`
|
||||||
found struct `GenericStruct2<_, 0>`
|
found struct `GenericStruct2<0, _>`
|
||||||
help: use the type name directly
|
help: use the type name directly
|
||||||
|
|
|
|
||||||
LL | GenericStruct2::<1, T> { 0: thing }
|
LL | GenericStruct2::<1, T> { 0: thing }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue