mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-08 16:07:43 +00:00
always peel &mut
, to allow matching on &mut str
This commit is contained in:
parent
fe98130e0f
commit
17bb4bbc86
@ -740,10 +740,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
|
||||
// If the pattern has as many or more layers of reference as the expected type, we can match
|
||||
// without peeling more, *unless* we find a smart pointer that we also need to peel.
|
||||
// TODO: always peel `&mut`
|
||||
// without peeling more, unless we find a smart pointer or `&mut` that we also need to peel.
|
||||
// We don't treat `&` and `&mut` as interchangeable, but by peeling `&mut`s before matching,
|
||||
// we can still, e.g., match on a `&mut str` with a string literal pattern. This is because
|
||||
// string literal patterns may be used where `str` is expected.
|
||||
let mut expected_ref_layers = 0;
|
||||
while let ty::Ref(_, inner_ty, _) = *expected.kind() {
|
||||
while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
|
||||
if mutbl.is_mut() {
|
||||
// Mutable references can't be in the final value of constants, thus they can't be
|
||||
// at the head of their types, thus we should always peel `&mut`.
|
||||
return true;
|
||||
}
|
||||
expected_ref_layers += 1;
|
||||
expected = inner_ty;
|
||||
}
|
||||
|
@ -33,4 +33,23 @@ fn main() {
|
||||
if let b"test" = *b"this array is too long" {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
// Test matching on `&mut T`: we peel the `&mut` before applying the usual special cases.
|
||||
// No special cases apply to `()`, so the "found" type is the type of the literal.
|
||||
if let b"test" = &mut () {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected `()`, found `&[u8; 4]`
|
||||
|
||||
// If the pointee is an array or slice, the usual special cases will apply to the "found" type:
|
||||
if let b"test" = &mut [] as &mut [i8] {}
|
||||
//~^ ERROR mismatched type
|
||||
//~| NOTE expected `[i8]`, found `[u8]`
|
||||
|
||||
if let b"test" = &mut [()] {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected `[(); 1]`, found `[u8; 4]`
|
||||
|
||||
if let b"test" = &mut *b"this array is too long" {}
|
||||
//~^ ERROR mismatched type
|
||||
//~| NOTE expected an array with a size of 22, found one with a size of 4
|
||||
}
|
||||
|
@ -47,6 +47,44 @@ LL | if let b"test" = *b"this array is too long" {}
|
||||
| |
|
||||
| expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:39:12
|
||||
|
|
||||
LL | if let b"test" = &mut () {}
|
||||
| ^^^^^^^ ------- this expression has type `&mut ()`
|
||||
| |
|
||||
| expected `()`, found `&[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:44:12
|
||||
|
|
||||
LL | if let b"test" = &mut [] as &mut [i8] {}
|
||||
| ^^^^^^^ -------------------- this expression has type `&mut [i8]`
|
||||
| |
|
||||
| expected `[i8]`, found `[u8]`
|
||||
|
|
||||
= note: expected slice `[i8]`
|
||||
found slice `[u8]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:48:12
|
||||
|
|
||||
LL | if let b"test" = &mut [()] {}
|
||||
| ^^^^^^^ --------- this expression has type `&mut [(); 1]`
|
||||
| |
|
||||
| expected `[(); 1]`, found `[u8; 4]`
|
||||
|
|
||||
= note: expected array `[(); 1]`
|
||||
found array `[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:52:12
|
||||
|
|
||||
LL | if let b"test" = &mut *b"this array is too long" {}
|
||||
| ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]`
|
||||
| |
|
||||
| expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -45,4 +45,10 @@ fn main() {
|
||||
if let b"..." = Box::new(&x) {}
|
||||
//[stable]~^ ERROR mismatched types
|
||||
has_type::<[u8; 3]>(x);
|
||||
|
||||
// `&` and `&mut` aren't interchangeable: `&mut`s need to be peeled before unifying, like boxes:
|
||||
let mut x = uninferred();
|
||||
if let "..." = &mut x {}
|
||||
//[stable]~^ ERROR mismatched types
|
||||
has_type::<&str>(x);
|
||||
}
|
||||
|
@ -39,6 +39,17 @@ help: consider dereferencing to access the inner value using the Deref trait
|
||||
LL | if let b"..." = *Box::new(&x) {}
|
||||
| +
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-pats-do-not-mislead-inference.rs:51:12
|
||||
|
|
||||
LL | if let "..." = &mut x {}
|
||||
| ^^^^^ ------ this expression has type `&mut _`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static str`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -46,4 +46,13 @@ fn main() {
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// `deref_patterns` allows string and byte string patterns to match on mutable references.
|
||||
// See also `tests/ui/pattern/byte-string-mutability-mismatch.rs`.
|
||||
if let "str" = &mut *"str".to_string() {}
|
||||
//~^ ERROR mismatched types
|
||||
if let b"str" = &mut b"str".clone() {}
|
||||
//~^ ERROR mismatched types
|
||||
if let b"str" = &mut b"str".clone()[..] {}
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
@ -77,7 +77,40 @@ LL | match "str".to_owned() {
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected `String`, found `&str`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:52:12
|
||||
|
|
||||
LL | if let "str" = &mut *"str".to_string() {}
|
||||
| ^^^^^ ----------------------- this expression has type `&mut str`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:54:12
|
||||
|
|
||||
LL | if let b"str" = &mut b"str".clone() {}
|
||||
| ^^^^^^ ------------------- this expression has type `&mut [u8; 3]`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:56:12
|
||||
|
|
||||
LL | if let b"str" = &mut b"str".clone()[..] {}
|
||||
| ^^^^^^ ----------------------- this expression has type `&mut [u8]`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
@ -14,6 +14,14 @@ fn main() {
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test matching on `&mut str`.
|
||||
let test_actual = match &mut *test_in.to_string() {
|
||||
"zero" => 0,
|
||||
"one" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test string literals in deref patterns.
|
||||
let test_actual = match test_in.to_string() {
|
||||
deref!("zero") => 0,
|
||||
@ -55,6 +63,22 @@ fn main() {
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test matching on `&mut [u8; N]`.
|
||||
let test_actual = match &mut test_in.clone() {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test matching on `&mut [u8]`.
|
||||
let test_actual = match &mut test_in.clone()[..] {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as arrays in deref patterns.
|
||||
let test_actual = match Box::new(*test_in) {
|
||||
deref!(b"0") => 0,
|
||||
|
Loading…
Reference in New Issue
Block a user