Skip to content

Commit

Permalink
Unrolled build for rust-lang#135749
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#135749 - compiler-errors:param-ordering, r=davidtwco

Do not assume const params are printed after type params

Fixes rust-lang#135737
  • Loading branch information
rust-timer authored Jan 25, 2025
2 parents 1e9b017 + 97e07da commit a5f3985
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 145 deletions.
259 changes: 121 additions & 138 deletions compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,53 +717,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
value: &mut DiagStyledString,
other_value: &mut DiagStyledString,
name: String,
sub: ty::GenericArgsRef<'tcx>,
args: &[ty::GenericArg<'tcx>],
pos: usize,
other_ty: Ty<'tcx>,
) {
// `value` and `other_value` hold two incomplete type representation for display.
// `name` is the path of both types being compared. `sub`
value.push_highlighted(name);
let len = sub.len();
if len > 0 {
value.push_highlighted("<");
}

// Output the lifetimes for the first type
let lifetimes = sub
.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);
}
if args.is_empty() {
return;
}
value.push_highlighted("<");

// 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());
for (i, arg) in args.iter().enumerate() {
if i > 0 {
value.push_normal(", ");
}

if len > 0 && i != len - 1 {
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`,
Expand Down Expand Up @@ -791,38 +785,36 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
t1_out: &mut DiagStyledString,
t2_out: &mut DiagStyledString,
path: String,
sub: &'tcx [ty::GenericArg<'tcx>],
args: &'tcx [ty::GenericArg<'tcx>],
other_path: String,
other_ty: Ty<'tcx>,
) -> Option<()> {
// FIXME/HACK: Go back to `GenericArgsRef` to use its inherent methods,
// ideally that shouldn't be necessary.
let sub = self.tcx.mk_args(sub);
for (i, ta) in sub.types().enumerate() {
if ta == other_ty {
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 path_ == other_path {
self.highlight_outer(t1_out, t2_out, path, sub, i, other_ty);
return Some(());
) -> bool {
for (i, arg) in args.iter().enumerate() {
if let Some(ta) = arg.as_type() {
if ta == other_ty {
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
return true;
}
if let ty::Adt(def, _) = ta.kind() {
let path_ = self.tcx.def_path_str(def.did());
if path_ == other_path {
self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
return true;
}
}
}
}
None
false
}

/// Adds a `,` to the type representation only if it is appropriate.
fn push_comma(
&self,
value: &mut DiagStyledString,
other_value: &mut DiagStyledString,
len: usize,
pos: usize,
) {
if len > 0 && pos != len - 1 {
if pos > 0 {
value.push_normal(", ");
other_value.push_normal(", ");
}
Expand Down Expand Up @@ -899,10 +891,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len2 = sig2.inputs().len();
if len1 == len2 {
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);
(values.0).0.extend(x1.0);
(values.1).0.extend(x2.0);
self.push_comma(&mut values.0, &mut values.1, len1, i);
}
} else {
for (i, l) in sig1.inputs().iter().enumerate() {
Expand Down Expand Up @@ -1150,14 +1142,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let len1 = sub_no_defaults_1.len();
let len2 = sub_no_defaults_2.len();
let common_len = cmp::min(len1, len2);
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
let remainder1 = &sub1[common_len..];
let remainder2 = &sub2[common_len..];
let common_default_params =
iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
.filter(|(a, b)| a == b)
.count();
let len = sub1.len() - common_default_params;
let consts_offset = len - sub1.consts().count();

// Only draw `<...>` if there are lifetime/type arguments.
if len > 0 {
Expand All @@ -1169,70 +1160,68 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let s = lifetime.to_string();
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
// 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
let type_arguments = sub1.types().zip(sub2.types());
let regions_len = sub1.regions().count();
let num_display_types = consts_offset - regions_len;
for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() {
let i = i + regions_len;
if ta1 == ta2 && !self.tcx.sess.opts.verbose {
values.0.push_normal("_");
values.1.push_normal("_");
} else {
recurse(ta1, ta2, &mut values);
for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
self.push_comma(&mut values.0, &mut values.1, i);
match arg1.unpack() {
// 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>)
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
// elide them from the output.
ty::GenericArgKind::Const(ca1) => {
let ca2 = arg2.expect_const();
maybe_highlight(ca1, ca2, &mut values, self.tcx);
}
}
self.push_comma(&mut values.0, &mut values.1, len, i);
}

// Do the same for const arguments, if they are equal, do not highlight and
// elide them from the output.
let const_arguments = sub1.consts().zip(sub2.consts());
for (i, (ca1, ca2)) in const_arguments.enumerate() {
let i = i + consts_offset;
maybe_highlight(ca1, ca2, &mut values, self.tcx);
self.push_comma(&mut values.0, &mut values.1, len, i);
}

// Close the type argument bracket.
// Only draw `<...>` if there are lifetime/type arguments.
// Only draw `<...>` if there are arguments.
if len > 0 {
values.0.push_normal(">");
values.1.push_normal(">");
Expand All @@ -1244,35 +1233,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Foo<Bar<Qux>
// ------- this type argument is exactly the same as the other type
// Bar<Qux>
if self
.cmp_type_arg(
&mut values.0,
&mut values.1,
path1.clone(),
sub_no_defaults_1,
path2.clone(),
t2,
)
.is_some()
{
if self.cmp_type_arg(
&mut values.0,
&mut values.1,
path1.clone(),
sub_no_defaults_1,
path2.clone(),
t2,
) {
return values;
}
// Check for case:
// let x: Bar<Qux> = y:<Foo<Bar<Qux>>>();
// Bar<Qux>
// Foo<Bar<Qux>>
// ------- this type argument is exactly the same as the other type
if self
.cmp_type_arg(
&mut values.1,
&mut values.0,
path2,
sub_no_defaults_2,
path1,
t1,
)
.is_some()
{
if self.cmp_type_arg(
&mut values.1,
&mut values.0,
path2,
sub_no_defaults_2,
path1,
t1,
) {
return values;
}

Expand Down Expand Up @@ -1343,8 +1326,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
let len = args1.len();
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);
self.push_comma(&mut values.0, &mut values.1, len, i);
}
if len == 1 {
// Keep the output for single element tuples as `(ty,)`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ LL | assert_eq!(smart_ptr.a::<&Foo>(), 2);
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
= note: expected reference `&Foo`
found struct `SmartPtr<'_, Foo, >`
found struct `SmartPtr<'_, Foo>`

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

error: aborting due to 8 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ LL | smart_ptr.get::<&Foo>();
| ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
|
= note: expected reference `&Foo`
found struct `SmartPtr<'_, Foo, >`
found struct `SmartPtr<'_, Foo>`

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

0 comments on commit a5f3985

Please sign in to comment.