Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
55 changes: 27 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,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn borrow_pat_suggestion(
&self,
err: &mut Diagnostic,
pat: &Pat<'_>,
inner: &Pat<'_>,
expected: Ty<'tcx>,
) {
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>, inner: &Pat<'_>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is pat and inner in this case? Is pat the (direct?) parent of inner always?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. pat is Ref(inner), see

PatKind::Ref(inner, mutbl) => {
self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti)

self.borrow_pat_suggestion(&mut err, pat, inner);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, could we simplify the redundant parameters then, if you think that would be simpler? Or if not, could you leave a comment that explains this relationship.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we really want is to have pat: Pat<PatKind::Ref> or something, but we don't have variant types so everything is messy :(

In the end I've removed inner (we need to match anyway, so that should be fine) and added comments about preconditions

let tcx = self.tcx;
if let PatKind::Binding(..) = inner.kind {
if let PatKind::Ref(_, 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,
hir::Node::Param(hir::Param { ty_span, .. }) if binding.span.hi() <= ty_span.lo() => {
err.multipart_suggestion_verbose(
format!("to take parameter by ref, 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 @@ -1853,7 +1852,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 +1868,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, inner);
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 by ref, 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