Rollup merge of #97964 - WaffleLapkin:fix_borrow_par_suggestions, r=compiler-errors

Fix suggestions for `&a: T` parameters

I've accidentally discovered that we have broken suggestions for `&a: T` parameters:
```rust
fn f(&mut bar: u32) {}

fn main() {
    let _ = |&mut a| ();
}
```
```text
error[E0308]: mismatched types
 --> ./t.rs:1:6
  |
1 | fn f(&mut bar: u32) {}
  |      ^^^^^^^^-----
  |      |         |
  |      |         expected due to this
  |      expected `u32`, found `&mut _`
  |      help: did you mean `bar`: `&u32`
  |
  = note:           expected type `u32`
          found mutable reference `&mut _`

error[E0308]: mismatched types
 --> ./t.rs:4:23
  |
4 |     let _: fn(u32) = |&mut a| ();
  |                       ^^^^^--
  |                       |    |
  |                       |    expected due to this
  |                       expected `u32`, found `&mut _`
  |                       help: did you mean `a`: `&u32`
  |
  = note:           expected type `u32`
          found mutable reference `&mut _`
```

It's hard to see, but
1. The help span is overlapping with "expected" spans
2. It suggests `fn f( &u32) {}` (no `mut` and lost parameter name) and `|&u32 ()` (no closing `|` and lost parameter name)

I've tried to fix this.

r? ``@compiler-errors``
This commit is contained in:
Yuki Okushi 2022-06-16 07:24:39 +09:00 committed by GitHub
commit 52afa3a70c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 480 additions and 88 deletions

View File

@ -649,39 +649,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn borrow_pat_suggestion(
&self,
err: &mut Diagnostic,
pat: &Pat<'_>,
inner: &Pat<'_>,
expected: Ty<'tcx>,
) {
// Precondition: pat is a Ref(_) pattern
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
let tcx = self.tcx;
if let PatKind::Binding(..) = inner.kind {
if let PatKind::Ref(inner, mutbl) = pat.kind
&& let PatKind::Binding(_, _, binding, ..) = inner.kind {
let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
let binding_parent = tcx.hir().get(binding_parent_id);
debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent);
debug!(?inner, ?pat, ?binding_parent);
let mutability = match mutbl {
ast::Mutability::Mut => "mut",
ast::Mutability::Not => "",
};
match binding_parent {
hir::Node::Param(hir::Param { span, .. })
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) =>
{
err.span_suggestion(
*span,
&format!("did you mean `{snippet}`"),
format!(" &{expected}"),
Applicability::MachineApplicable,
// Check that there is explicit type (ie this is not a closure param with inferred type)
// so we don't suggest moving something to the type that does not exist
hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => {
err.multipart_suggestion_verbose(
format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
vec![
(pat.span.until(inner.span), "".to_owned()),
(ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())),
],
Applicability::MachineApplicable
);
}
hir::Node::Arm(_) | hir::Node::Pat(_) => {
hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
// rely on match ergonomics or it might be nested `&&pat`
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
err.span_suggestion(
pat.span,
"you can probably remove the explicit borrow",
snippet,
Applicability::MaybeIncorrect,
);
}
err.span_suggestion_verbose(
pat.span.until(inner.span),
format!("consider removing `&{mutability}` from the pattern"),
"",
Applicability::MaybeIncorrect,
);
}
_ => {} // don't provide suggestions in other cases #55175
}
@ -1836,6 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
box_ty
}
// Precondition: Pat is Ref(inner)
fn check_pat_ref(
&self,
pat: &'tcx Pat<'tcx>,
@ -1853,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Take region, inner-type from expected type if we can,
// to avoid creating needless variables. This also helps with
// the bad interactions of the given hack detailed in (note_1).
// the bad interactions of the given hack detailed in (note_1).
debug!("check_pat_ref: expected={:?}", expected);
match *expected.kind() {
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
@ -1869,7 +1872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat, inner, expected);
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
}
(rptr_ty, inner_ty)

View File

@ -23,10 +23,14 @@ LL | let &&x = &1isize as &dyn T;
| ^^ ----------------- this expression has type `&dyn T`
| |
| expected trait object `dyn T`, found reference
| help: you can probably remove the explicit borrow: `x`
|
= note: expected trait object `dyn T`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let &&x = &1isize as &dyn T;
LL + let &x = &1isize as &dyn T;
|
error[E0308]: mismatched types
--> $DIR/destructure-trait-ref.rs:36:11
@ -35,10 +39,14 @@ LL | let &&&x = &(&1isize as &dyn T);
| ^^ -------------------- this expression has type `&&dyn T`
| |
| expected trait object `dyn T`, found reference
| help: you can probably remove the explicit borrow: `x`
|
= note: expected trait object `dyn T`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let &&&x = &(&1isize as &dyn T);
LL + let &&x = &(&1isize as &dyn T);
|
error[E0308]: mismatched types
--> $DIR/destructure-trait-ref.rs:40:13

View File

@ -0,0 +1,5 @@
fn ugh(&[bar]: &u32) {} //~ ERROR expected an array or slice
fn bgh(&&bar: u32) {} //~ ERROR mismatched types
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0529]: expected an array or slice, found `u32`
--> $DIR/issue-38371-unfixable.rs:1:9
|
LL | fn ugh(&[bar]: &u32) {}
| ^^^^^ pattern cannot match with input type `u32`
error[E0308]: mismatched types
--> $DIR/issue-38371-unfixable.rs:3:8
|
LL | fn bgh(&&bar: u32) {}
| ^^^^^ --- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0308, E0529.
For more information about an error, try `rustc --explain E0308`.

View File

@ -0,0 +1,18 @@
// run-rustfix
// see also issue-38371-unfixable.rs
#![allow(dead_code)]
#[derive(Copy, Clone)]
struct Foo {}
fn foo(_a: &Foo) {} //~ ERROR mismatched types
fn bar(_a: Foo) {}
fn qux(_a: &Foo) {}
fn zar(&_a: &Foo) {}
fn agh(&_a: &u32) {} //~ ERROR mismatched types
fn main() {}

View File

@ -1,27 +1,18 @@
struct Foo {
}
// run-rustfix
// see also issue-38371-unfixable.rs
#![allow(dead_code)]
fn foo(&foo: Foo) { //~ ERROR mismatched types
}
#[derive(Copy, Clone)]
struct Foo {}
fn bar(foo: Foo) {
}
fn foo(&_a: Foo) {} //~ ERROR mismatched types
fn qux(foo: &Foo) {
}
fn bar(_a: Foo) {}
fn zar(&foo: &Foo) {
}
fn qux(_a: &Foo) {}
// The somewhat unexpected help message in this case is courtesy of
// match_default_bindings.
fn agh(&&bar: &u32) { //~ ERROR mismatched types
}
fn zar(&_a: &Foo) {}
fn bgh(&&bar: u32) { //~ ERROR mismatched types
}
fn ugh(&[bar]: &u32) { //~ ERROR expected an array or slice
}
fn agh(&&_a: &u32) {} //~ ERROR mismatched types
fn main() {}

View File

@ -1,46 +1,35 @@
error[E0308]: mismatched types
--> $DIR/issue-38371.rs:4:8
--> $DIR/issue-38371.rs:8:8
|
LL | fn foo(&foo: Foo) {
| ^^^^-----
| | |
| | expected due to this
LL | fn foo(&_a: Foo) {}
| ^^^ --- expected due to this
| |
| expected struct `Foo`, found reference
| help: did you mean `foo`: `&Foo`
|
= note: expected struct `Foo`
found reference `&_`
help: to take parameter `_a` by reference, move `&` to the type
|
LL - fn foo(&_a: Foo) {}
LL + fn foo(_a: &Foo) {}
|
error[E0308]: mismatched types
--> $DIR/issue-38371.rs:18:9
--> $DIR/issue-38371.rs:16:9
|
LL | fn agh(&&bar: &u32) {
| ^^^^ ---- expected due to this
LL | fn agh(&&_a: &u32) {}
| ^^^ ---- expected due to this
| |
| expected `u32`, found reference
| help: you can probably remove the explicit borrow: `bar`
|
= note: expected type `u32`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/issue-38371.rs:21:8
help: consider removing `&` from the pattern
|
LL | fn bgh(&&bar: u32) {
| ^^^^^ --- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
LL - fn agh(&&_a: &u32) {}
LL + fn agh(&_a: &u32) {}
|
error[E0529]: expected an array or slice, found `u32`
--> $DIR/issue-38371.rs:24:9
|
LL | fn ugh(&[bar]: &u32) {
| ^^^^^ pattern cannot match with input type `u32`
error: aborting due to 2 previous errors
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0308, E0529.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,24 @@
// run-rustfix
fn _f0(_a: &u32) {} //~ ERROR mismatched types
fn _f1(_a: &mut u32) {} //~ ERROR mismatched types
fn _f2(&_a: &u32) {} //~ ERROR mismatched types
fn _f3(&mut _a: &mut u32) {} //~ ERROR mismatched types
fn _f4(&_a: &u32) {} //~ ERROR mismatched types
fn _f5(&mut _a: &mut u32) {} //~ ERROR mismatched types
fn main() {
let _: fn(u32) = |_a| (); //~ ERROR mismatched types
let _: fn(u32) = |_a| (); //~ ERROR mismatched types
let _: fn(&u32) = |&_a| (); //~ ERROR mismatched types
let _: fn(&mut u32) = |&mut _a| (); //~ ERROR mismatched types
let _: fn(&u32) = |&_a| (); //~ ERROR mismatched types
let _: fn(&mut u32) = |&mut _a| (); //~ ERROR mismatched types
let _ = |_a: &u32| (); //~ ERROR mismatched types
let _ = |_a: &mut u32| (); //~ ERROR mismatched types
let _ = |&_a: &u32| (); //~ ERROR mismatched types
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
let _ = |&_a: &u32| (); //~ ERROR mismatched types
let _ = |&mut _a: &mut u32| (); //~ ERROR mismatched types
}

View File

@ -0,0 +1,24 @@
// run-rustfix
fn _f0(&_a: u32) {} //~ ERROR mismatched types
fn _f1(&mut _a: u32) {} //~ ERROR mismatched types
fn _f2(&&_a: &u32) {} //~ ERROR mismatched types
fn _f3(&mut &_a: &mut u32) {} //~ ERROR mismatched types
fn _f4(&&mut _a: &u32) {} //~ ERROR mismatched types
fn _f5(&mut &mut _a: &mut u32) {} //~ ERROR mismatched types
fn main() {
let _: fn(u32) = |&_a| (); //~ ERROR mismatched types
let _: fn(u32) = |&mut _a| (); //~ ERROR mismatched types
let _: fn(&u32) = |&&_a| (); //~ ERROR mismatched types
let _: fn(&mut u32) = |&mut &_a| (); //~ ERROR mismatched types
let _: fn(&u32) = |&&mut _a| (); //~ ERROR mismatched types
let _: fn(&mut u32) = |&mut &mut _a| (); //~ ERROR mismatched types
let _ = |&_a: u32| (); //~ ERROR mismatched types
let _ = |&mut _a: u32| (); //~ ERROR mismatched types
let _ = |&&_a: &u32| (); //~ ERROR mismatched types
let _ = |&mut &_a: &mut u32| (); //~ ERROR mismatched types
let _ = |&&mut _a: &u32| (); //~ ERROR mismatched types
let _ = |&mut &mut _a: &mut u32| (); //~ ERROR mismatched types
}

View File

@ -0,0 +1,297 @@
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:3:8
|
LL | fn _f0(&_a: u32) {}
| ^^^ --- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: to take parameter `_a` by reference, move `&` to the type
|
LL - fn _f0(&_a: u32) {}
LL + fn _f0(_a: &u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:4:8
|
LL | fn _f1(&mut _a: u32) {}
| ^^^^^^^ --- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: to take parameter `_a` by reference, move `&mut` to the type
|
LL - fn _f1(&mut _a: u32) {}
LL + fn _f1(_a: &mut u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:5:9
|
LL | fn _f2(&&_a: &u32) {}
| ^^^ ---- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - fn _f2(&&_a: &u32) {}
LL + fn _f2(&_a: &u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:6:13
|
LL | fn _f3(&mut &_a: &mut u32) {}
| ^^^ -------- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - fn _f3(&mut &_a: &mut u32) {}
LL + fn _f3(&mut _a: &mut u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:7:9
|
LL | fn _f4(&&mut _a: &u32) {}
| ^^^^^^^ ---- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - fn _f4(&&mut _a: &u32) {}
LL + fn _f4(&_a: &u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:8:13
|
LL | fn _f5(&mut &mut _a: &mut u32) {}
| ^^^^^^^ -------- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - fn _f5(&mut &mut _a: &mut u32) {}
LL + fn _f5(&mut _a: &mut u32) {}
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:11:23
|
LL | let _: fn(u32) = |&_a| ();
| ^--
| ||
| |expected due to this
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let _: fn(u32) = |&_a| ();
LL + let _: fn(u32) = |_a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:12:23
|
LL | let _: fn(u32) = |&mut _a| ();
| ^^^^^--
| | |
| | expected due to this
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - let _: fn(u32) = |&mut _a| ();
LL + let _: fn(u32) = |_a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:13:25
|
LL | let _: fn(&u32) = |&&_a| ();
| ^--
| ||
| |expected due to this
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let _: fn(&u32) = |&&_a| ();
LL + let _: fn(&u32) = |&_a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:14:33
|
LL | let _: fn(&mut u32) = |&mut &_a| ();
| ^--
| ||
| |expected due to this
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let _: fn(&mut u32) = |&mut &_a| ();
LL + let _: fn(&mut u32) = |&mut _a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:15:25
|
LL | let _: fn(&u32) = |&&mut _a| ();
| ^^^^^--
| | |
| | expected due to this
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - let _: fn(&u32) = |&&mut _a| ();
LL + let _: fn(&u32) = |&_a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:16:33
|
LL | let _: fn(&mut u32) = |&mut &mut _a| ();
| ^^^^^--
| | |
| | expected due to this
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - let _: fn(&mut u32) = |&mut &mut _a| ();
LL + let _: fn(&mut u32) = |&mut _a| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:18:14
|
LL | let _ = |&_a: u32| ();
| ^^^ --- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: to take parameter `_a` by reference, move `&` to the type
|
LL - let _ = |&_a: u32| ();
LL + let _ = |_a: &u32| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:19:14
|
LL | let _ = |&mut _a: u32| ();
| ^^^^^^^ --- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: to take parameter `_a` by reference, move `&mut` to the type
|
LL - let _ = |&mut _a: u32| ();
LL + let _ = |_a: &mut u32| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:20:15
|
LL | let _ = |&&_a: &u32| ();
| ^^^ ---- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let _ = |&&_a: &u32| ();
LL + let _ = |&_a: &u32| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:21:19
|
LL | let _ = |&mut &_a: &mut u32| ();
| ^^^ -------- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - let _ = |&mut &_a: &mut u32| ();
LL + let _ = |&mut _a: &mut u32| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:22:15
|
LL | let _ = |&&mut _a: &u32| ();
| ^^^^^^^ ---- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - let _ = |&&mut _a: &u32| ();
LL + let _ = |&_a: &u32| ();
|
error[E0308]: mismatched types
--> $DIR/ref-pat-suggestions.rs:23:19
|
LL | let _ = |&mut &mut _a: &mut u32| ();
| ^^^^^^^ -------- expected due to this
| |
| expected `u32`, found `&mut _`
|
= note: expected type `u32`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - let _ = |&mut &mut _a: &mut u32| ();
LL + let _ = |&mut _a: &mut u32| ();
|
error: aborting due to 18 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -5,10 +5,14 @@ LL | for ((_, _), (&mut c, _)) in &mut map {
| ^^^^^^ -------- this is an iterator with items of type `(&(char, char), &mut (char, char))`
| |
| expected `char`, found `&mut _`
| help: you can probably remove the explicit borrow: `c`
|
= note: expected type `char`
found mutable reference `&mut _`
help: consider removing `&mut` from the pattern
|
LL - for ((_, _), (&mut c, _)) in &mut map {
LL + for ((_, _), (c, _)) in &mut map {
|
error[E0308]: mismatched types
--> $DIR/for-loop-bad-item.rs:14:14

View File

@ -4,13 +4,15 @@ error[E0308]: mismatched types
LL | match &x[..] {
| ------ this expression has type `&[i32]`
LL | [&v] => {},
| ^^
| |
| expected `i32`, found reference
| help: you can probably remove the explicit borrow: `v`
| ^^ expected `i32`, found reference
|
= note: expected type `i32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - [&v] => {},
LL + [v] => {},
|
error[E0529]: expected an array or slice, found `Vec<i32>`
--> $DIR/match-ergonomics.rs:8:9
@ -34,13 +36,15 @@ error[E0308]: mismatched types
LL | match y {
| - this expression has type `i32`
LL | &v => {},
| ^^
| |
| expected `i32`, found reference
| help: you can probably remove the explicit borrow: `v`
| ^^ expected `i32`, found reference
|
= note: expected type `i32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - &v => {},
LL + v => {},
|
error[E0308]: mismatched types
--> $DIR/match-ergonomics.rs:40:13
@ -49,10 +53,14 @@ LL | if let [&v] = &x[..] {}
| ^^ ------ this expression has type `&[i32]`
| |
| expected `i32`, found reference
| help: you can probably remove the explicit borrow: `v`
|
= note: expected type `i32`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - if let [&v] = &x[..] {}
LL + if let [v] = &x[..] {}
|
error: aborting due to 5 previous errors