Skip to content

Commit 5be6c6f

Browse files
authored
Rollup merge of #147577 - JohnTitor:issue-147312, r=davidtwco
Improve error message for ambiguous numeric types in closure parameters Closes #147312
2 parents fd847d4 + 632e759 commit 5be6c6f

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,6 +2547,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25472547
"you must specify a type for this binding, like `{concrete_type}`",
25482548
);
25492549

2550+
// FIXME: Maybe FileName::Anon should also be handled,
2551+
// otherwise there would be no suggestion if the source is STDIN for example.
25502552
match (filename, parent_node) {
25512553
(
25522554
FileName::Real(_),
@@ -2568,6 +2570,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25682570
Applicability::MaybeIncorrect,
25692571
);
25702572
}
2573+
// For closure parameters with reference patterns (e.g., |&v|), suggest the type annotation
2574+
// on the pattern itself, e.g., |&v: &i32|
2575+
(FileName::Real(_), Node::Pat(pat))
2576+
if let Node::Pat(binding_pat) = self.tcx.hir_node(hir_id)
2577+
&& let hir::PatKind::Binding(..) = binding_pat.kind
2578+
&& let Node::Pat(parent_pat) = parent_node
2579+
&& matches!(parent_pat.kind, hir::PatKind::Ref(..)) =>
2580+
{
2581+
err.span_label(span, "you must specify a type for this binding");
2582+
2583+
let mut ref_muts = Vec::new();
2584+
let mut current_node = parent_node;
2585+
2586+
while let Node::Pat(parent_pat) = current_node {
2587+
if let hir::PatKind::Ref(_, mutability) = parent_pat.kind {
2588+
ref_muts.push(mutability);
2589+
current_node = self.tcx.parent_hir_node(parent_pat.hir_id);
2590+
} else {
2591+
break;
2592+
}
2593+
}
2594+
2595+
let mut type_annotation = String::new();
2596+
for mutability in ref_muts.iter().rev() {
2597+
match mutability {
2598+
hir::Mutability::Mut => type_annotation.push_str("&mut "),
2599+
hir::Mutability::Not => type_annotation.push('&'),
2600+
}
2601+
}
2602+
type_annotation.push_str(&concrete_type);
2603+
2604+
err.span_suggestion_verbose(
2605+
pat.span.shrink_to_hi(),
2606+
"specify the type in the closure argument list",
2607+
format!(": {type_annotation}"),
2608+
Applicability::MaybeIncorrect,
2609+
);
2610+
}
25712611
_ => {
25722612
err.span_label(span, msg);
25732613
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Test for better error message when numeric type is ambiguous in closure parameter with reference
2+
3+
//@ run-rustfix
4+
5+
fn main() {
6+
let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0);
7+
//~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}`
8+
//~| SUGGESTION &i32
9+
10+
let v = vec![0, 1, 2];
11+
let _ = v.iter().filter(|&&v: &&i32| v.pow(2) > 0);
12+
//~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}`
13+
//~| SUGGESTION &&i32
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Test for better error message when numeric type is ambiguous in closure parameter with reference
2+
3+
//@ run-rustfix
4+
5+
fn main() {
6+
let _ = (0..10).filter(|&v| v.pow(2) > 0);
7+
//~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}`
8+
//~| SUGGESTION &i32
9+
10+
let v = vec![0, 1, 2];
11+
let _ = v.iter().filter(|&&v| v.pow(2) > 0);
12+
//~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}`
13+
//~| SUGGESTION &&i32
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
2+
--> $DIR/ambiguous-numeric-in-closure-ref.rs:6:35
3+
|
4+
LL | let _ = (0..10).filter(|&v| v.pow(2) > 0);
5+
| - ^^^
6+
| |
7+
| you must specify a type for this binding
8+
|
9+
help: specify the type in the closure argument list
10+
|
11+
LL | let _ = (0..10).filter(|&v: &i32| v.pow(2) > 0);
12+
| ++++++
13+
14+
error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
15+
--> $DIR/ambiguous-numeric-in-closure-ref.rs:11:37
16+
|
17+
LL | let _ = v.iter().filter(|&&v| v.pow(2) > 0);
18+
| - ^^^
19+
| |
20+
| you must specify a type for this binding
21+
|
22+
help: specify the type in the closure argument list
23+
|
24+
LL | let _ = v.iter().filter(|&&v: &&i32| v.pow(2) > 0);
25+
| +++++++
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0689`.

0 commit comments

Comments
 (0)