From 9260f2ee472d875b7e9731d109fc76ba2b4f0202 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Fri, 26 Jun 2026 22:59:23 +0600 Subject: [PATCH 1/2] fix: don't produce invalid `Trait` in "consider further restricting this bound" suggestion when a bound already has generic args (e.g. `impl Pair`) the "consider further restricting this bound" suggestion would generate invalid syntax by appending a new `` producing `Pair`. the fix detects when the insertion point immediately follows a `>` and merges into the existing arg list instead producing the valid `Pair`. --- compiler/rustc_middle/src/ty/diagnostics.rs | 27 ++++++++++++++----- ...restrict-bound-already-has-generic-args.rs | 25 +++++++++++++++++ ...rict-bound-already-has-generic-args.stderr | 24 +++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 tests/ui/suggestions/restrict-bound-already-has-generic-args.rs create mode 100644 tests/ui/suggestions/restrict-bound-already-has-generic-args.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index fadf1ee2ee384..ec9b73d415f93 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -398,15 +398,28 @@ pub fn suggest_constraining_type_params<'a>( } }; let constraint = constraint.join(" + "); - let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| { - let suggestion = if span_to_replace.is_some() { - constraint.clone() - } else if constraint.starts_with('<') { - constraint.clone() + let mut suggest_restrict = |span: Span, bound_list_non_empty, open_paren_sp| { + let (span, suggestion) = if span_to_replace.is_some() { + (span, constraint.clone()) + } else if let Some(rest) = constraint.strip_prefix('<') { + // `constraint` adds generic args; check whether the bound already has some. + // Naively inserting `` after `Foo` yields invalid `Foo`. + if span.lo() > BytePos(0) + && tcx + .sess + .source_map() + .span_to_snippet(span.with_lo(span.lo() - BytePos(1))) + .as_deref() + == Ok(">") + { + (span.with_lo(span.lo() - BytePos(1)), format!(", {rest}")) + } else { + (span, constraint.clone()) + } } else if bound_list_non_empty { - format!(" + {constraint}") + (span, format!(" + {constraint}")) } else { - format!(" {constraint}") + (span, format!(" {constraint}")) }; if let Some(open_paren_sp) = open_paren_sp { diff --git a/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs b/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs new file mode 100644 index 0000000000000..912d92fdc762f --- /dev/null +++ b/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs @@ -0,0 +1,25 @@ +// Regression test for https://github.com/rust-lang/rust/issues/142803. + +trait Pair { + type Left; + type Right; + + fn split(self) -> (Self::Left, Self::Right); +} + +impl Pair for (A, B) { + type Left = A; + type Right = B; + + fn split(self) -> (Self::Left, Self::Right) { + self + } +} + +fn frob(pair: impl Pair) -> impl Pair { + //~^ ERROR type mismatch + let (left, right) = pair.split(); + (left, right) +} + +fn main() {} diff --git a/tests/ui/suggestions/restrict-bound-already-has-generic-args.stderr b/tests/ui/suggestions/restrict-bound-already-has-generic-args.stderr new file mode 100644 index 0000000000000..a284f2adb366c --- /dev/null +++ b/tests/ui/suggestions/restrict-bound-already-has-generic-args.stderr @@ -0,0 +1,24 @@ +error[E0271]: type mismatch resolving `<(A, as Pair>::Right) as Pair>::Right == B` + --> $DIR/restrict-bound-already-has-generic-args.rs:19:45 + | +LL | fn frob(pair: impl Pair) -> impl Pair { + | - expected this type parameter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<(A, as Pair>::Right) as Pair>::Right == B` +... +LL | (left, right) + | ------------- return type was inferred to be `(A, as Pair>::Right)` here + | +note: expected this to be `B` + --> $DIR/restrict-bound-already-has-generic-args.rs:12:18 + | +LL | type Right = B; + | ^ + = note: expected type parameter `B` + found associated type ` as Pair>::Right` +help: consider further restricting this bound + | +LL | fn frob(pair: impl Pair) -> impl Pair { + | +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. From dde5f49de98295da08aa694823fb9eaceda1e4cb Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Sat, 27 Jun 2026 16:43:23 +0600 Subject: [PATCH 2/2] fix: add regression test for invalid `Trait` bound suggestion --- compiler/rustc_middle/src/ty/diagnostics.rs | 27 +++++-------------- ...restrict-bound-already-has-generic-args.rs | 2 ++ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index ec9b73d415f93..fadf1ee2ee384 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -398,28 +398,15 @@ pub fn suggest_constraining_type_params<'a>( } }; let constraint = constraint.join(" + "); - let mut suggest_restrict = |span: Span, bound_list_non_empty, open_paren_sp| { - let (span, suggestion) = if span_to_replace.is_some() { - (span, constraint.clone()) - } else if let Some(rest) = constraint.strip_prefix('<') { - // `constraint` adds generic args; check whether the bound already has some. - // Naively inserting `` after `Foo` yields invalid `Foo`. - if span.lo() > BytePos(0) - && tcx - .sess - .source_map() - .span_to_snippet(span.with_lo(span.lo() - BytePos(1))) - .as_deref() - == Ok(">") - { - (span.with_lo(span.lo() - BytePos(1)), format!(", {rest}")) - } else { - (span, constraint.clone()) - } + let mut suggest_restrict = |span, bound_list_non_empty, open_paren_sp| { + let suggestion = if span_to_replace.is_some() { + constraint.clone() + } else if constraint.starts_with('<') { + constraint.clone() } else if bound_list_non_empty { - (span, format!(" + {constraint}")) + format!(" + {constraint}") } else { - (span, format!(" {constraint}")) + format!(" {constraint}") }; if let Some(open_paren_sp) = open_paren_sp { diff --git a/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs b/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs index 912d92fdc762f..0350ef50705d9 100644 --- a/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs +++ b/tests/ui/suggestions/restrict-bound-already-has-generic-args.rs @@ -18,6 +18,8 @@ impl Pair for (A, B) { fn frob(pair: impl Pair) -> impl Pair { //~^ ERROR type mismatch + //~| HELP consider further restricting this bound + //~| SUGGESTION , Right = B let (left, right) = pair.split(); (left, right) }