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 { impl MutblCap {
fn cap_mutbl_to_not(self, span: Option<Span>) -> Self { 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 { fn as_mutbl(self) -> Mutability {
@ -744,9 +750,14 @@ fn check_pat_ident(
self.tcx.dcx(), self.tcx.dcx(),
ident.span, ident.span,
E0596, 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(); err.emit();
} }
@ -2187,7 +2198,21 @@ fn check_pat_ref(
// 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); debug!("check_pat_ref: expected={:?}", expected);
match *expected.kind() { 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 // `&` pattern eats `&mut` reference
ty::Ref(_, r_ty, Mutability::Mut) ty::Ref(_, r_ty, Mutability::Mut)
@ -2196,16 +2221,7 @@ fn check_pat_ref(
&& self.tcx.features().ref_pat_eat_one_layer_2024) && self.tcx.features().ref_pat_eat_one_layer_2024)
|| self.tcx.features().ref_pat_everywhere) => || self.tcx.features().ref_pat_everywhere) =>
{ {
( (expected, r_ty, pat_info)
expected,
r_ty,
PatInfo {
max_ref_mutbl: pat_info
.max_ref_mutbl
.cap_mutbl_to_not(Some(pat.span.until(inner.span))),
..pat_info
},
)
} }
_ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => { _ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => {

View File

@ -24,18 +24,24 @@ pub fn main() {
//~^ ERROR: mismatched types //~^ ERROR: mismatched types
} }
if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { 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)) { 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)) { if let Some(&mut Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types //~^ ERROR: mismatched types
} }
let &mut _= &&0; let &mut _ = &&0;
//~^ ERROR: mismatched types //~^ ERROR: mismatched types
let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
//~^ ERROR: mismatched types //~^ 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}>` = note: expected enum `Option<{integer}>`
found mutable reference `&mut _` 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 --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:31
| |
LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
| ^ | - ^
| | |
help: change this `&` pattern to an `&mut` | help: replace this `&` with `&mut`: `&mut`
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17
|
LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
| ^
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 --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:31
| |
LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
| ^ | - ^
| | |
help: change this `&` pattern to an `&mut` | help: replace this `&` with `&mut`: `&mut`
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:12
|
LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
| ^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:17 --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:17
@ -102,7 +94,7 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) {
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:9 --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:9
| |
LL | let &mut _= &&0; LL | let &mut _ = &&0;
| ^^^^^^ --- this expression has type `&&{integer}` | ^^^^^^ --- this expression has type `&&{integer}`
| | | |
| expected integer, found `&mut _` | expected integer, found `&mut _`
@ -121,7 +113,16 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
= note: expected type `{integer}` = note: expected type `{integer}`
found mutable reference `&mut _` 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. Some errors have detailed explanations: E0308, E0596.
For more information about an error, try `rustc --explain E0308`. 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] //~^ ERROR: cannot move out of a shared reference [E0507]
let _: &u32 = x; 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)) { 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`.