Skip to content

Commit

Permalink
Rollup merge of rust-lang#97964 - WaffleLapkin:fix_borrow_par_suggest…
Browse files Browse the repository at this point in the history
…ions, 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`
  • Loading branch information
GuillaumeGomez authored Jun 15, 2022
2 parents c3605f8 + 33ccd76 commit 2a8abe6
Show file tree
Hide file tree
Showing 12 changed files with 480 additions and 88 deletions.
59 changes: 31 additions & 28 deletions compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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>,
Expand All @@ -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),
Expand All @@ -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)
Expand Down
12 changes: 10 additions & 2 deletions src/test/ui/destructure-trait-ref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/mismatched_types/issue-38371-unfixable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn ugh(&[bar]: &u32) {} //~ ERROR expected an array or slice

fn bgh(&&bar: u32) {} //~ ERROR mismatched types

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/mismatched_types/issue-38371-unfixable.stderr
Original file line number Diff line number Diff line change
@@ -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`.
18 changes: 18 additions & 0 deletions src/test/ui/mismatched_types/issue-38371.fixed
Original file line number Diff line number Diff line change
@@ -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() {}
29 changes: 10 additions & 19 deletions src/test/ui/mismatched_types/issue-38371.rs
Original file line number Diff line number Diff line change
@@ -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() {}
47 changes: 18 additions & 29 deletions src/test/ui/mismatched_types/issue-38371.stderr
Original file line number Diff line number Diff line change
@@ -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
|
LL | fn bgh(&&bar: u32) {
| ^^^^^ --- expected due to this
| |
| expected `u32`, found reference
|
= note: expected type `u32`
found reference `&_`

error[E0529]: expected an array or slice, found `u32`
--> $DIR/issue-38371.rs:24:9
help: consider removing `&` from the pattern
|
LL | fn ugh(&[bar]: &u32) {
| ^^^^^ pattern cannot match with input type `u32`
LL - fn agh(&&_a: &u32) {}
LL + fn agh(&_a: &u32) {}
|

error: aborting due to 4 previous errors
error: aborting due to 2 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`.
24 changes: 24 additions & 0 deletions src/test/ui/mismatched_types/ref-pat-suggestions.fixed
Original file line number Diff line number Diff line change
@@ -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
}
24 changes: 24 additions & 0 deletions src/test/ui/mismatched_types/ref-pat-suggestions.rs
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 2a8abe6

Please sign in to comment.