Various fixes:

- Only show error when move-check would not be triggered
- Add structured suggestion
This commit is contained in:
Jules Bertholet 2024-05-04 14:57:27 -04:00
parent 4f76f1069a
commit ed96c655c6
No known key found for this signature in database
GPG Key ID: 32034DAFC38C1BFC
5 changed files with 71 additions and 38 deletions

View File

@ -163,7 +163,13 @@ enum MutblCap {
impl MutblCap {
fn cap_mutbl_to_not(self, span: Option<Span>) -> Self {
if self == MutblCap::Mut { MutblCap::Not(span) } else { self }
if let Some(s) = span
&& self != MutblCap::Not(None)
{
MutblCap::Not(Some(s))
} else {
MutblCap::Not(None)
}
}
fn as_mutbl(self) -> Mutability {
@ -744,9 +750,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.dcx(),
ident.span,
E0596,
"cannot bind with `ref mut` behind an `&` pattern"
"cannot borrow as mutable inside an `&` pattern"
);
err.span_suggestion(
and_pat_span,
"replace this `&` with `&mut`",
"&mut ",
Applicability::MachineApplicable,
);
err.span_help(and_pat_span, "change this `&` pattern to an `&mut`");
err.emit();
}
@ -2187,7 +2198,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 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, pat_info),
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => {
let pat_info = if r_mutbl == Mutability::Not
&& ((pat.span.at_least_rust_2024()
&& self.tcx.features().ref_pat_eat_one_layer_2024)
|| self.tcx.features().ref_pat_everywhere)
{
PatInfo {
max_ref_mutbl: pat_info.max_ref_mutbl.cap_mutbl_to_not(None),
..pat_info
}
} else {
pat_info
};
(expected, r_ty, pat_info)
}
// `&` pattern eats `&mut` reference
ty::Ref(_, r_ty, Mutability::Mut)
@ -2196,16 +2221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.tcx.features().ref_pat_eat_one_layer_2024)
|| self.tcx.features().ref_pat_everywhere) =>
{
(
expected,
r_ty,
PatInfo {
max_ref_mutbl: pat_info
.max_ref_mutbl
.cap_mutbl_to_not(Some(pat.span.until(inner.span))),
..pat_info
},
)
(expected, r_ty, pat_info)
}
_ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => {

View File

@ -24,18 +24,24 @@ pub fn main() {
//~^ ERROR: mismatched types
}
if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
//~^ ERROR: cannot bind with `ref mut` behind an `&` pattern
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
}
if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
//~^ ERROR: cannot bind with `ref mut` behind an `&` pattern
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
}
if let Some(&mut Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types
}
let &mut _= &&0;
let &mut _ = &&0;
//~^ ERROR: mismatched types
let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
//~^ ERROR: mismatched types
macro_rules! pat {
($var:ident) => { ref mut $var };
}
let &pat!(x) = &mut 0;
//~^ ERROR: cannot borrow as mutable inside an `&` pattern
}

View File

@ -64,29 +64,21 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
= note: expected enum `Option<{integer}>`
found mutable reference `&mut _`
error[E0596]: cannot bind with `ref mut` behind an `&` pattern
error[E0596]: cannot borrow as mutable inside an `&` pattern
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:31
|
LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
| ^
|
help: change this `&` pattern to an `&mut`
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17
|
LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
| ^
| - ^
| |
| help: replace this `&` with `&mut`: `&mut`
error[E0596]: cannot bind with `ref mut` behind an `&` pattern
error[E0596]: cannot borrow as mutable inside an `&` pattern
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:31
|
LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
| ^
|
help: change this `&` pattern to an `&mut`
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:12
|
LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
| ^
| - ^
| |
| help: replace this `&` with `&mut`: `&mut`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:17
@ -102,8 +94,8 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:9
|
LL | let &mut _= &&0;
| ^^^^^^ --- this expression has type `&&{integer}`
LL | let &mut _ = &&0;
| ^^^^^^ --- this expression has type `&&{integer}`
| |
| expected integer, found `&mut _`
|
@ -121,7 +113,16 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
= note: expected type `{integer}`
found mutable reference `&mut _`
error: aborting due to 11 previous errors
error[E0596]: cannot borrow as mutable inside an `&` pattern
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:15
|
LL | ($var:ident) => { ref mut $var };
| ------------ help: replace this `&` with `&mut`: `&mut`
LL | }
LL | let &pat!(x) = &mut 0;
| ^
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0308, E0596.
For more information about an error, try `rustc --explain E0308`.

View File

@ -8,4 +8,7 @@ pub fn main() {
//~^ ERROR: cannot move out of a shared reference [E0507]
let _: &u32 = x;
}
let &ref mut x = &0;
//~^ cannot borrow data in a `&` reference as mutable [E0596]
}

View File

@ -12,6 +12,13 @@ help: consider borrowing the pattern binding
LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
| +++
error: aborting due to 1 previous error
error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10
|
LL | let &ref mut x = &0;
| ^^^^^^^^^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0507`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0507, E0596.
For more information about an error, try `rustc --explain E0507`.