Skip to content

Commit e9d49b2

Browse files
committed
Fix suggestions for &a: T parameters
Previously we were suggesting stuff like `fn f( &u32) {}`
1 parent f19ccc2 commit e9d49b2

12 files changed

+476
-88
lines changed

compiler/rustc_typeck/src/check/pat.rs

+27-28
Original file line numberDiff line numberDiff line change
@@ -649,39 +649,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
649649
}
650650
}
651651

652-
fn borrow_pat_suggestion(
653-
&self,
654-
err: &mut Diagnostic,
655-
pat: &Pat<'_>,
656-
inner: &Pat<'_>,
657-
expected: Ty<'tcx>,
658-
) {
652+
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>, inner: &Pat<'_>) {
659653
let tcx = self.tcx;
660-
if let PatKind::Binding(..) = inner.kind {
654+
if let PatKind::Ref(_, mutbl) = pat.kind
655+
&& let PatKind::Binding(_, _, binding, ..) = inner.kind {
661656
let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
662657
let binding_parent = tcx.hir().get(binding_parent_id);
663-
debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent);
658+
debug!(?inner, ?pat, ?binding_parent);
659+
660+
let mutability = match mutbl {
661+
ast::Mutability::Mut => "mut",
662+
ast::Mutability::Not => "",
663+
};
664+
664665
match binding_parent {
665-
hir::Node::Param(hir::Param { span, .. })
666-
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) =>
667-
{
668-
err.span_suggestion(
669-
*span,
670-
&format!("did you mean `{snippet}`"),
671-
format!(" &{expected}"),
672-
Applicability::MachineApplicable,
666+
hir::Node::Param(hir::Param { ty_span, .. }) if binding.span.hi() <= ty_span.lo() => {
667+
err.multipart_suggestion_verbose(
668+
format!("to take parameter by ref, move `&{mutability}` to the type"),
669+
vec![
670+
(pat.span.until(inner.span), "".to_owned()),
671+
(ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())),
672+
],
673+
Applicability::MachineApplicable
673674
);
674675
}
675-
hir::Node::Arm(_) | hir::Node::Pat(_) => {
676+
hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
676677
// rely on match ergonomics or it might be nested `&&pat`
677-
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
678-
err.span_suggestion(
679-
pat.span,
680-
"you can probably remove the explicit borrow",
681-
snippet,
682-
Applicability::MaybeIncorrect,
683-
);
684-
}
678+
err.span_suggestion_verbose(
679+
pat.span.until(inner.span),
680+
format!("consider removing `&{mutability}` from the pattern"),
681+
"",
682+
Applicability::MaybeIncorrect,
683+
);
685684
}
686685
_ => {} // don't provide suggestions in other cases #55175
687686
}
@@ -1853,7 +1852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18531852

18541853
// Take region, inner-type from expected type if we can,
18551854
// to avoid creating needless variables. This also helps with
1856-
// the bad interactions of the given hack detailed in (note_1).
1855+
// the bad interactions of the given hack detailed in (note_1).
18571856
debug!("check_pat_ref: expected={:?}", expected);
18581857
match *expected.kind() {
18591858
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
@@ -1869,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18691868
// Look for a case like `fn foo(&foo: u32)` and suggest
18701869
// `fn foo(foo: &u32)`
18711870
if let Some(mut err) = err {
1872-
self.borrow_pat_suggestion(&mut err, pat, inner, expected);
1871+
self.borrow_pat_suggestion(&mut err, pat, inner);
18731872
err.emit();
18741873
}
18751874
(rptr_ty, inner_ty)

src/test/ui/destructure-trait-ref.stderr

+10-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ LL | let &&x = &1isize as &dyn T;
2323
| ^^ ----------------- this expression has type `&dyn T`
2424
| |
2525
| expected trait object `dyn T`, found reference
26-
| help: you can probably remove the explicit borrow: `x`
2726
|
2827
= note: expected trait object `dyn T`
2928
found reference `&_`
29+
help: consider removing `&` from the pattern
30+
|
31+
LL - let &&x = &1isize as &dyn T;
32+
LL + let &x = &1isize as &dyn T;
33+
|
3034

3135
error[E0308]: mismatched types
3236
--> $DIR/destructure-trait-ref.rs:36:11
@@ -35,10 +39,14 @@ LL | let &&&x = &(&1isize as &dyn T);
3539
| ^^ -------------------- this expression has type `&&dyn T`
3640
| |
3741
| expected trait object `dyn T`, found reference
38-
| help: you can probably remove the explicit borrow: `x`
3942
|
4043
= note: expected trait object `dyn T`
4144
found reference `&_`
45+
help: consider removing `&` from the pattern
46+
|
47+
LL - let &&&x = &(&1isize as &dyn T);
48+
LL + let &&x = &(&1isize as &dyn T);
49+
|
4250

4351
error[E0308]: mismatched types
4452
--> $DIR/destructure-trait-ref.rs:40:13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn ugh(&[bar]: &u32) {} //~ ERROR expected an array or slice
2+
3+
fn bgh(&&bar: u32) {} //~ ERROR mismatched types
4+
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0529]: expected an array or slice, found `u32`
2+
--> $DIR/issue-38371-unfixable.rs:1:9
3+
|
4+
LL | fn ugh(&[bar]: &u32) {}
5+
| ^^^^^ pattern cannot match with input type `u32`
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-38371-unfixable.rs:3:8
9+
|
10+
LL | fn bgh(&&bar: u32) {}
11+
| ^^^^^ --- expected due to this
12+
| |
13+
| expected `u32`, found reference
14+
|
15+
= note: expected type `u32`
16+
found reference `&_`
17+
18+
error: aborting due to 2 previous errors
19+
20+
Some errors have detailed explanations: E0308, E0529.
21+
For more information about an error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// run-rustfix
2+
// see also issue-38371-unfixable.rs
3+
#![allow(dead_code)]
4+
5+
#[derive(Copy, Clone)]
6+
struct Foo {}
7+
8+
fn foo(_a: &Foo) {} //~ ERROR mismatched types
9+
10+
fn bar(_a: Foo) {}
11+
12+
fn qux(_a: &Foo) {}
13+
14+
fn zar(&_a: &Foo) {}
15+
16+
fn agh(&_a: &u32) {} //~ ERROR mismatched types
17+
18+
fn main() {}
+10-19
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,18 @@
1-
struct Foo {
2-
}
1+
// run-rustfix
2+
// see also issue-38371-unfixable.rs
3+
#![allow(dead_code)]
34

4-
fn foo(&foo: Foo) { //~ ERROR mismatched types
5-
}
5+
#[derive(Copy, Clone)]
6+
struct Foo {}
67

7-
fn bar(foo: Foo) {
8-
}
8+
fn foo(&_a: Foo) {} //~ ERROR mismatched types
99

10-
fn qux(foo: &Foo) {
11-
}
10+
fn bar(_a: Foo) {}
1211

13-
fn zar(&foo: &Foo) {
14-
}
12+
fn qux(_a: &Foo) {}
1513

16-
// The somewhat unexpected help message in this case is courtesy of
17-
// match_default_bindings.
18-
fn agh(&&bar: &u32) { //~ ERROR mismatched types
19-
}
14+
fn zar(&_a: &Foo) {}
2015

21-
fn bgh(&&bar: u32) { //~ ERROR mismatched types
22-
}
23-
24-
fn ugh(&[bar]: &u32) { //~ ERROR expected an array or slice
25-
}
16+
fn agh(&&_a: &u32) {} //~ ERROR mismatched types
2617

2718
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-38371.rs:4:8
2+
--> $DIR/issue-38371.rs:8:8
33
|
4-
LL | fn foo(&foo: Foo) {
5-
| ^^^^-----
6-
| | |
7-
| | expected due to this
4+
LL | fn foo(&_a: Foo) {}
5+
| ^^^ --- expected due to this
6+
| |
87
| expected struct `Foo`, found reference
9-
| help: did you mean `foo`: `&Foo`
108
|
119
= note: expected struct `Foo`
1210
found reference `&_`
11+
help: to take parameter by ref, move `&` to the type
12+
|
13+
LL - fn foo(&_a: Foo) {}
14+
LL + fn foo(_a: &Foo) {}
15+
|
1316

1417
error[E0308]: mismatched types
15-
--> $DIR/issue-38371.rs:18:9
18+
--> $DIR/issue-38371.rs:16:9
1619
|
17-
LL | fn agh(&&bar: &u32) {
18-
| ^^^^ ---- expected due to this
20+
LL | fn agh(&&_a: &u32) {}
21+
| ^^^ ---- expected due to this
1922
| |
2023
| expected `u32`, found reference
21-
| help: you can probably remove the explicit borrow: `bar`
22-
|
23-
= note: expected type `u32`
24-
found reference `&_`
25-
26-
error[E0308]: mismatched types
27-
--> $DIR/issue-38371.rs:21:8
28-
|
29-
LL | fn bgh(&&bar: u32) {
30-
| ^^^^^ --- expected due to this
31-
| |
32-
| expected `u32`, found reference
3324
|
3425
= note: expected type `u32`
3526
found reference `&_`
36-
37-
error[E0529]: expected an array or slice, found `u32`
38-
--> $DIR/issue-38371.rs:24:9
27+
help: consider removing `&` from the pattern
3928
|
40-
LL | fn ugh(&[bar]: &u32) {
41-
| ^^^^^ pattern cannot match with input type `u32`
29+
LL - fn agh(&&_a: &u32) {}
30+
LL + fn agh(&_a: &u32) {}
31+
|
4232

43-
error: aborting due to 4 previous errors
33+
error: aborting due to 2 previous errors
4434

45-
Some errors have detailed explanations: E0308, E0529.
46-
For more information about an error, try `rustc --explain E0308`.
35+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
3+
fn _f0(_a: &u32) {} //~ ERROR mismatched types
4+
fn _f1(_a: &mut u32) {} //~ ERROR mismatched types
5+
fn _f2(&_a: &u32) {} //~ ERROR mismatched types
6+
fn _f3(&mut _a: &mut u32) {} //~ ERROR mismatched types
7+
fn _f4(&_a: &u32) {} //~ ERROR mismatched types
8+
fn _f5(&mut _a: &mut u32) {} //~ ERROR mismatched types
9+
10+
fn main() {
11+
let _: fn(u32) = |_a| (); //~ ERROR mismatched types
12+
let _: fn(u32) = |_a| (); //~ ERROR mismatched types
13+
let _: fn(&u32) = |&_a| (); //~ ERROR mismatched types
14+
let _: fn(&mut u32) = |&mut _a| (); //~ ERROR mismatched types
15+
let _: fn(&u32) = |&_a| (); //~ ERROR mismatched types
16+
let _: fn(&mut u32) = |&mut _a| (); //~ ERROR mismatched types
17+
18+
let _ = |_a: &u32| (); //~ ERROR mismatched types
19+
let _ = |_a: &mut u32| (); //~ ERROR mismatched types
20+
let _ = |&_a: &u32| (); //~ ERROR mismatched types
21+
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
22+
let _ = |&_a: &u32| (); //~ ERROR mismatched types
23+
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-rustfix
2+
3+
fn _f0(&_a: u32) {} //~ ERROR mismatched types
4+
fn _f1(&mut _a: u32) {} //~ ERROR mismatched types
5+
fn _f2(&&_a: &u32) {} //~ ERROR mismatched types
6+
fn _f3(&mut &_a: &mut u32) {} //~ ERROR mismatched types
7+
fn _f4(&&mut _a: &u32) {} //~ ERROR mismatched types
8+
fn _f5(&mut &mut _a: &mut u32) {} //~ ERROR mismatched types
9+
10+
fn main() {
11+
let _: fn(u32) = |&_a| (); //~ ERROR mismatched types
12+
let _: fn(u32) = |&mut _a| (); //~ ERROR mismatched types
13+
let _: fn(&u32) = |&&_a| (); //~ ERROR mismatched types
14+
let _: fn(&mut u32) = |&mut &_a| (); //~ ERROR mismatched types
15+
let _: fn(&u32) = |&&mut _a| (); //~ ERROR mismatched types
16+
let _: fn(&mut u32) = |&mut &mut _a| (); //~ ERROR mismatched types
17+
18+
let _ = |&_a: u32| (); //~ ERROR mismatched types
19+
let _ = |&mut _a: u32| (); //~ ERROR mismatched types
20+
let _ = |&&_a: &u32| (); //~ ERROR mismatched types
21+
let _ = |&mut &_a: &mut u32| (); //~ ERROR mismatched types
22+
let _ = |&&mut _a: &u32| (); //~ ERROR mismatched types
23+
let _ = |&mut &mut _a: &mut u32| (); //~ ERROR mismatched types
24+
}

0 commit comments

Comments
 (0)