From 0eaa3366f904e9fde3bd3ada9d2642f23140577d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 11 Oct 2025 12:04:17 +0900 Subject: [PATCH 1/3] Improve error message for ambiguous numeric types in closure parameters --- compiler/rustc_hir_typeck/src/method/suggest.rs | 16 ++++++++++++++++ .../ambiguous-numeric-in-closure-ref.fixed | 9 +++++++++ .../ambiguous-numeric-in-closure-ref.rs | 9 +++++++++ .../ambiguous-numeric-in-closure-ref.stderr | 16 ++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed create mode 100644 tests/ui/inference/ambiguous-numeric-in-closure-ref.rs create mode 100644 tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 44602e6289940..3c3c979c05ec5 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2568,6 +2568,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } + // For closure parameters with reference patterns (e.g., |&v|), suggest the type annotation + // on the pattern itself, e.g., |&v: &i32| + (FileName::Real(_), Node::Pat(pat)) + if let Node::Pat(binding_pat) = self.tcx.hir_node(hir_id) + && let hir::PatKind::Binding(..) = binding_pat.kind + && let Node::Pat(parent_pat) = parent_node + && matches!(parent_pat.kind, hir::PatKind::Ref(..)) => + { + err.span_label(span, "you must specify a type for this binding"); + err.span_suggestion_verbose( + pat.span.shrink_to_hi(), + "specify the type in the closure argument list", + format!(": &{concrete_type}"), + Applicability::MaybeIncorrect, + ); + } _ => { err.span_label(span, msg); } diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed b/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed new file mode 100644 index 0000000000000..0bb81c7df125d --- /dev/null +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed @@ -0,0 +1,9 @@ +// Test for better error message when numeric type is ambiguous in closure parameter with reference + +//@ run-rustfix + +fn main() { + let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + //~| SUGGESTION &i32 +} diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs b/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs new file mode 100644 index 0000000000000..7a6f779ab8329 --- /dev/null +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs @@ -0,0 +1,9 @@ +// Test for better error message when numeric type is ambiguous in closure parameter with reference + +//@ run-rustfix + +fn main() { + let _ = (0..10).filter(|&v| v.pow(2) > 0); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + //~| SUGGESTION &i32 +} diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr b/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr new file mode 100644 index 0000000000000..a2225d940a30f --- /dev/null +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr @@ -0,0 +1,16 @@ +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/ambiguous-numeric-in-closure-ref.rs:6:35 + | +LL | let _ = (0..10).filter(|&v| v.pow(2) > 0); + | - ^^^ + | | + | you must specify a type for this binding + | +help: specify the type in the closure argument list + | +LL | let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0); + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0689`. From dbc7327748d6dc190c594c8343dd53e8e60ca49c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 11 Oct 2025 21:17:17 +0900 Subject: [PATCH 2/3] Fix suggestions for nested refs and muts --- .../rustc_hir_typeck/src/method/suggest.rs | 24 ++++++++++++++++++- .../ambiguous-numeric-in-closure-ref.fixed | 5 ++++ .../ambiguous-numeric-in-closure-ref.rs | 5 ++++ .../ambiguous-numeric-in-closure-ref.stderr | 15 +++++++++++- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3c3c979c05ec5..a2ec7075fac94 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2577,10 +2577,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && matches!(parent_pat.kind, hir::PatKind::Ref(..)) => { err.span_label(span, "you must specify a type for this binding"); + + let mut ref_muts = Vec::new(); + let mut current_node = parent_node; + + while let Node::Pat(parent_pat) = current_node { + if let hir::PatKind::Ref(_, mutability) = parent_pat.kind { + ref_muts.push(mutability); + current_node = self.tcx.parent_hir_node(parent_pat.hir_id); + } else { + break; + } + } + + let mut type_annotation = String::new(); + for mutability in ref_muts.iter().rev() { + match mutability { + hir::Mutability::Mut => type_annotation.push_str("&mut "), + hir::Mutability::Not => type_annotation.push('&'), + } + } + type_annotation.push_str(&concrete_type); + err.span_suggestion_verbose( pat.span.shrink_to_hi(), "specify the type in the closure argument list", - format!(": &{concrete_type}"), + format!(": {type_annotation}"), Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed b/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed index 0bb81c7df125d..683d581d034b1 100644 --- a/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.fixed @@ -6,4 +6,9 @@ fn main() { let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0); //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` //~| SUGGESTION &i32 + + let v = vec![0, 1, 2]; + let _ = v.iter().filter(|&&v: &&i32| v.pow(2) > 0); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + //~| SUGGESTION &&i32 } diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs b/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs index 7a6f779ab8329..eab309c701d69 100644 --- a/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.rs @@ -6,4 +6,9 @@ fn main() { let _ = (0..10).filter(|&v| v.pow(2) > 0); //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` //~| SUGGESTION &i32 + + let v = vec![0, 1, 2]; + let _ = v.iter().filter(|&&v| v.pow(2) > 0); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + //~| SUGGESTION &&i32 } diff --git a/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr b/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr index a2225d940a30f..0789581abea80 100644 --- a/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr +++ b/tests/ui/inference/ambiguous-numeric-in-closure-ref.stderr @@ -11,6 +11,19 @@ help: specify the type in the closure argument list LL | let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0); | ++++++ -error: aborting due to 1 previous error +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/ambiguous-numeric-in-closure-ref.rs:11:37 + | +LL | let _ = v.iter().filter(|&&v| v.pow(2) > 0); + | - ^^^ + | | + | you must specify a type for this binding + | +help: specify the type in the closure argument list + | +LL | let _ = v.iter().filter(|&&v: &&i32| v.pow(2) > 0); + | +++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0689`. From 632e759497ec9ec93b96c863479c8512f9511650 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 11 Oct 2025 21:32:47 +0900 Subject: [PATCH 3/3] Add FIXME about FileName check's fragility --- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a2ec7075fac94..e1073de49d305 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2547,6 +2547,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "you must specify a type for this binding, like `{concrete_type}`", ); + // FIXME: Maybe FileName::Anon should also be handled, + // otherwise there would be no suggestion if the source is STDIN for example. match (filename, parent_node) { ( FileName::Real(_),