Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix suggestions for &a: T parameters #97964

Merged
merged 5 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
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(
WaffleLapkin marked this conversation as resolved.
Show resolved Hide resolved
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