Skip to content

Commit b45a8c4

Browse files
Do not assume const params are printed after type params
1 parent 39dc268 commit b45a8c4

File tree

4 files changed

+127
-143
lines changed

4 files changed

+127
-143
lines changed

compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

Lines changed: 120 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -717,51 +717,46 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
717717
value: &mut DiagStyledString,
718718
other_value: &mut DiagStyledString,
719719
name: String,
720-
sub: ty::GenericArgsRef<'tcx>,
720+
args: &[ty::GenericArg<'tcx>],
721721
pos: usize,
722722
other_ty: Ty<'tcx>,
723723
) {
724724
// `value` and `other_value` hold two incomplete type representation for display.
725725
// `name` is the path of both types being compared. `sub`
726726
value.push_highlighted(name);
727-
let len = sub.len();
728-
if len > 0 {
729-
value.push_highlighted("<");
730-
}
731727

732-
// Output the lifetimes for the first type
733-
let lifetimes = sub
734-
.regions()
735-
.map(|lifetime| {
736-
let s = lifetime.to_string();
737-
if s.is_empty() { "'_".to_string() } else { s }
738-
})
739-
.collect::<Vec<_>>()
740-
.join(", ");
741-
if !lifetimes.is_empty() {
742-
if sub.regions().count() < len {
743-
value.push_normal(lifetimes + ", ");
744-
} else {
745-
value.push_normal(lifetimes);
746-
}
728+
if !args.is_empty() {
729+
value.push_highlighted("<");
747730
}
748731

749-
// Highlight all the type arguments that aren't at `pos` and compare the type argument at
750-
// `pos` and `other_ty`.
751-
for (i, type_arg) in sub.types().enumerate() {
752-
if i == pos {
753-
let values = self.cmp(type_arg, other_ty);
754-
value.0.extend((values.0).0);
755-
other_value.0.extend((values.1).0);
756-
} else {
757-
value.push_highlighted(type_arg.to_string());
732+
for (i, arg) in args.iter().enumerate() {
733+
if i > 0 {
734+
value.push_normal(", ");
758735
}
759736

760-
if len > 0 && i != len - 1 {
761-
value.push_normal(", ");
737+
match arg.unpack() {
738+
ty::GenericArgKind::Lifetime(lt) => {
739+
let s = lt.to_string();
740+
value.push_normal(if s.is_empty() { "'_" } else { &s });
741+
}
742+
ty::GenericArgKind::Const(ct) => {
743+
value.push_normal(ct.to_string());
744+
}
745+
// Highlight all the type arguments that aren't at `pos` and compare
746+
// the type argument at `pos` and `other_ty`.
747+
ty::GenericArgKind::Type(type_arg) => {
748+
if i == pos {
749+
let values = self.cmp(type_arg, other_ty);
750+
value.0.extend((values.0).0);
751+
other_value.0.extend((values.1).0);
752+
} else {
753+
value.push_highlighted(type_arg.to_string());
754+
}
755+
}
762756
}
763757
}
764-
if len > 0 {
758+
759+
if !args.is_empty() {
765760
value.push_highlighted(">");
766761
}
767762
}
@@ -791,38 +786,36 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
791786
t1_out: &mut DiagStyledString,
792787
t2_out: &mut DiagStyledString,
793788
path: String,
794-
sub: &'tcx [ty::GenericArg<'tcx>],
789+
args: &'tcx [ty::GenericArg<'tcx>],
795790
other_path: String,
796791
other_ty: Ty<'tcx>,
797-
) -> Option<()> {
798-
// FIXME/HACK: Go back to `GenericArgsRef` to use its inherent methods,
799-
// ideally that shouldn't be necessary.
800-
let sub = self.tcx.mk_args(sub);
801-
for (i, ta) in sub.types().enumerate() {
802-
if ta == other_ty {
803-
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
804-
return Some(());
805-
}
806-
if let ty::Adt(def, _) = ta.kind() {
807-
let path_ = self.tcx.def_path_str(def.did());
808-
if path_ == other_path {
809-
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
810-
return Some(());
792+
) -> bool {
793+
for (i, arg) in args.iter().enumerate() {
794+
if let Some(ta) = arg.as_type() {
795+
if ta == other_ty {
796+
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
797+
return true;
798+
}
799+
if let ty::Adt(def, _) = ta.kind() {
800+
let path_ = self.tcx.def_path_str(def.did());
801+
if path_ == other_path {
802+
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
803+
return true;
804+
}
811805
}
812806
}
813807
}
814-
None
808+
false
815809
}
816810

817811
/// Adds a `,` to the type representation only if it is appropriate.
818812
fn push_comma(
819813
&self,
820814
value: &mut DiagStyledString,
821815
other_value: &mut DiagStyledString,
822-
len: usize,
823816
pos: usize,
824817
) {
825-
if len > 0 && pos != len - 1 {
818+
if pos > 0 {
826819
value.push_normal(", ");
827820
other_value.push_normal(", ");
828821
}
@@ -899,10 +892,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
899892
let len2 = sig2.inputs().len();
900893
if len1 == len2 {
901894
for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
895+
self.push_comma(&mut values.0, &mut values.1, i);
902896
let (x1, x2) = self.cmp(*l, *r);
903897
(values.0).0.extend(x1.0);
904898
(values.1).0.extend(x2.0);
905-
self.push_comma(&mut values.0, &mut values.1, len1, i);
906899
}
907900
} else {
908901
for (i, l) in sig1.inputs().iter().enumerate() {
@@ -1150,14 +1143,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11501143
let len1 = sub_no_defaults_1.len();
11511144
let len2 = sub_no_defaults_2.len();
11521145
let common_len = cmp::min(len1, len2);
1153-
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
1154-
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
1146+
let remainder1 = &sub1[common_len..];
1147+
let remainder2 = &sub2[common_len..];
11551148
let common_default_params =
11561149
iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
11571150
.filter(|(a, b)| a == b)
11581151
.count();
11591152
let len = sub1.len() - common_default_params;
1160-
let consts_offset = len - sub1.consts().count();
11611153

11621154
// Only draw `<...>` if there are lifetime/type arguments.
11631155
if len > 0 {
@@ -1169,70 +1161,68 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11691161
let s = lifetime.to_string();
11701162
if s.is_empty() { "'_".to_string() } else { s }
11711163
}
1172-
// At one point we'd like to elide all lifetimes here, they are irrelevant for
1173-
// all diagnostics that use this output
1174-
//
1175-
// Foo<'x, '_, Bar>
1176-
// Foo<'y, '_, Qux>
1177-
// ^^ ^^ --- type arguments are not elided
1178-
// | |
1179-
// | elided as they were the same
1180-
// not elided, they were different, but irrelevant
1181-
//
1182-
// For bound lifetimes, keep the names of the lifetimes,
1183-
// even if they are the same so that it's clear what's happening
1184-
// if we have something like
1185-
//
1186-
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
1187-
// for<'r> fn(Inv<'r>, Inv<'r>)
1188-
let lifetimes = sub1.regions().zip(sub2.regions());
1189-
for (i, lifetimes) in lifetimes.enumerate() {
1190-
let l1 = lifetime_display(lifetimes.0);
1191-
let l2 = lifetime_display(lifetimes.1);
1192-
if lifetimes.0 != lifetimes.1 {
1193-
values.0.push_highlighted(l1);
1194-
values.1.push_highlighted(l2);
1195-
} else if lifetimes.0.is_bound() || self.tcx.sess.opts.verbose {
1196-
values.0.push_normal(l1);
1197-
values.1.push_normal(l2);
1198-
} else {
1199-
values.0.push_normal("'_");
1200-
values.1.push_normal("'_");
1201-
}
1202-
self.push_comma(&mut values.0, &mut values.1, len, i);
1203-
}
12041164

1205-
// We're comparing two types with the same path, so we compare the type
1206-
// arguments for both. If they are the same, do not highlight and elide from the
1207-
// output.
1208-
// Foo<_, Bar>
1209-
// Foo<_, Qux>
1210-
// ^ elided type as this type argument was the same in both sides
1211-
let type_arguments = sub1.types().zip(sub2.types());
1212-
let regions_len = sub1.regions().count();
1213-
let num_display_types = consts_offset - regions_len;
1214-
for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
1215-
let i = i + regions_len;
1216-
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
1217-
values.0.push_normal("_");
1218-
values.1.push_normal("_");
1219-
} else {
1220-
recurse(ta1, ta2, &mut values);
1165+
for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
1166+
self.push_comma(&mut values.0, &mut values.1, i);
1167+
match arg1.unpack() {
1168+
// At one point we'd like to elide all lifetimes here, they are
1169+
// irrelevant for all diagnostics that use this output.
1170+
//
1171+
// Foo<'x, '_, Bar>
1172+
// Foo<'y, '_, Qux>
1173+
// ^^ ^^ --- type arguments are not elided
1174+
// | |
1175+
// | elided as they were the same
1176+
// not elided, they were different, but irrelevant
1177+
//
1178+
// For bound lifetimes, keep the names of the lifetimes,
1179+
// even if they are the same so that it's clear what's happening
1180+
// if we have something like
1181+
//
1182+
// for<'r, 's> fn(Inv<'r>, Inv<'s>)
1183+
// for<'r> fn(Inv<'r>, Inv<'r>)
1184+
ty::GenericArgKind::Lifetime(l1) => {
1185+
let l1_str = lifetime_display(l1);
1186+
let l2 = arg2.expect_region();
1187+
let l2_str = lifetime_display(l2);
1188+
if l1 != l2 {
1189+
values.0.push_highlighted(l1_str);
1190+
values.1.push_highlighted(l2_str);
1191+
} else if l1.is_bound() || self.tcx.sess.opts.verbose {
1192+
values.0.push_normal(l1_str);
1193+
values.1.push_normal(l2_str);
1194+
} else {
1195+
values.0.push_normal("'_");
1196+
values.1.push_normal("'_");
1197+
}
1198+
}
1199+
ty::GenericArgKind::Type(ta1) => {
1200+
let ta2 = arg2.expect_ty();
1201+
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
1202+
values.0.push_normal("_");
1203+
values.1.push_normal("_");
1204+
} else {
1205+
recurse(ta1, ta2, &mut values);
1206+
}
1207+
}
1208+
// We're comparing two types with the same path, so we compare the type
1209+
// arguments for both. If they are the same, do not highlight and elide
1210+
// from the output.
1211+
// Foo<_, Bar>
1212+
// Foo<_, Qux>
1213+
// ^ elided type as this type argument was the same in both sides
1214+
1215+
// Do the same for const arguments, if they are equal, do not highlight and
1216+
// elide them from the output.
1217+
ty::GenericArgKind::Const(ca1) => {
1218+
let ca2 = arg2.expect_const();
1219+
maybe_highlight(ca1, ca2, &mut values, self.tcx);
1220+
}
12211221
}
1222-
self.push_comma(&mut values.0, &mut values.1, len, i);
1223-
}
1224-
1225-
// Do the same for const arguments, if they are equal, do not highlight and
1226-
// elide them from the output.
1227-
let const_arguments = sub1.consts().zip(sub2.consts());
1228-
for (i, (ca1, ca2)) in const_arguments.enumerate() {
1229-
let i = i + consts_offset;
1230-
maybe_highlight(ca1, ca2, &mut values, self.tcx);
1231-
self.push_comma(&mut values.0, &mut values.1, len, i);
12321222
}
12331223

12341224
// Close the type argument bracket.
1235-
// Only draw `<...>` if there are lifetime/type arguments.
1225+
// Only draw `<...>` if there are arguments.
12361226
if len > 0 {
12371227
values.0.push_normal(">");
12381228
values.1.push_normal(">");
@@ -1244,35 +1234,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12441234
// Foo<Bar<Qux>
12451235
// ------- this type argument is exactly the same as the other type
12461236
// Bar<Qux>
1247-
if self
1248-
.cmp_type_arg(
1249-
&mut values.0,
1250-
&mut values.1,
1251-
path1.clone(),
1252-
sub_no_defaults_1,
1253-
path2.clone(),
1254-
t2,
1255-
)
1256-
.is_some()
1257-
{
1237+
if self.cmp_type_arg(
1238+
&mut values.0,
1239+
&mut values.1,
1240+
path1.clone(),
1241+
sub_no_defaults_1,
1242+
path2.clone(),
1243+
t2,
1244+
) {
12581245
return values;
12591246
}
12601247
// Check for case:
12611248
// let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
12621249
// Bar<Qux>
12631250
// Foo<Bar<Qux>>
12641251
// ------- this type argument is exactly the same as the other type
1265-
if self
1266-
.cmp_type_arg(
1267-
&mut values.1,
1268-
&mut values.0,
1269-
path2,
1270-
sub_no_defaults_2,
1271-
path1,
1272-
t1,
1273-
)
1274-
.is_some()
1275-
{
1252+
if self.cmp_type_arg(
1253+
&mut values.1,
1254+
&mut values.0,
1255+
path2,
1256+
sub_no_defaults_2,
1257+
path1,
1258+
t1,
1259+
) {
12761260
return values;
12771261
}
12781262

@@ -1343,8 +1327,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13431327
let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
13441328
let len = args1.len();
13451329
for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
1330+
self.push_comma(&mut values.0, &mut values.1, i);
13461331
recurse(left, right, &mut values);
1347-
self.push_comma(&mut values.0, &mut values.1, len, i);
13481332
}
13491333
if len == 1 {
13501334
// Keep the output for single element tuples as `(ty,)`.

tests/ui/self/arbitrary-self-from-method-substs-with-receiver.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ LL | assert_eq!(smart_ptr.a::<&Foo>(), 2);
5353
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
5454
|
5555
= note: expected reference `&Foo`
56-
found struct `SmartPtr<'_, Foo, >`
56+
found struct `SmartPtr<'_, Foo>`
5757

5858
error[E0308]: mismatched types
5959
--> $DIR/arbitrary-self-from-method-substs-with-receiver.rs:62:16
@@ -62,7 +62,7 @@ LL | assert_eq!(smart_ptr.b::<&Foo>(), 1);
6262
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
6363
|
6464
= note: expected reference `&Foo`
65-
found struct `SmartPtr<'_, Foo, >`
65+
found struct `SmartPtr<'_, Foo>`
6666

6767
error: aborting due to 8 previous errors
6868

tests/ui/self/arbitrary-self-from-method-substs.feature.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ LL | smart_ptr.get::<&Foo>();
8383
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
8484
|
8585
= note: expected reference `&Foo`
86-
found struct `SmartPtr<'_, Foo, >`
86+
found struct `SmartPtr<'_, Foo>`
8787

8888
error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
8989
--> $DIR/arbitrary-self-from-method-substs.rs:92:9

0 commit comments

Comments
 (0)