Rollup merge of #68856 - Centril:or-pat-ref-pat, r=matthewjasper

typeck: clarify def_bm adjustments & add tests for or-patterns

Clarify the adjustment algorithm for the expected type / default binding-modes when type checking patterns with more documentation and tweaks that make the algorithm more independent of the pattern forms.

Also resolve the FIXME noted for or-patterns by deciding that the current implementation is correct, noting the rationale and adding tests for the current implementation.

cc https://github.com/rust-lang/rust/issues/54883

r? @oli-obk @varkor
This commit is contained in:
Yuki Okushi 2020-02-15 07:17:47 +09:00 committed by GitHub
commit 829a3635e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 454 additions and 69 deletions

View file

@ -1,4 +0,0 @@
enum Blah { A(isize, isize, usize), B(isize, isize) }
fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } }
//~^ ERROR mismatched types

View file

@ -1,9 +0,0 @@
error[E0308]: mismatched types
--> $DIR/or-pattern-mismatch.rs:3:68
|
LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } }
| ---------------- this expression has type `Blah` ^ expected `usize`, found `isize`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,68 @@
// Here we test type checking of bindings when combined with or-patterns.
// Specifically, we ensure that introducing bindings of different types result in type errors.
#![feature(or_patterns)]
fn main() {
enum Blah {
A(isize, isize, usize),
B(isize, isize),
}
match Blah::A(1, 1, 2) {
Blah::A(_, x, y) | Blah::B(x, y) => {} //~ ERROR mismatched types
}
match Some(Blah::A(1, 1, 2)) {
Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} //~ ERROR mismatched types
}
match (0u8, 1u16) {
(x, y) | (y, x) => {} //~ ERROR mismatched types
//~^ ERROR mismatched types
}
match Some((0u8, Some((1u16, 2u32)))) {
Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
_ => {}
}
if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
//~^ ERROR mismatched types
}
if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
//~^ ERROR mismatched types
}
if let (x, y) | (y, x) = (0u8, 1u16) {
//~^ ERROR mismatched types
//~| ERROR mismatched types
}
if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
//~| ERROR mismatched types
= Some((0u8, Some((1u16, 2u32))))
{}
let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
//~^ ERROR mismatched types
let (x, y) | (y, x) = (0u8, 1u16);
//~^ ERROR mismatched types
//~| ERROR mismatched types
fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
//~^ ERROR mismatched types
fn f2(((x, y) | (y, x)): (u8, u16)) {}
//~^ ERROR mismatched types
//~| ERROR mismatched types
}

View file

@ -0,0 +1,183 @@
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:13:39
|
LL | match Blah::A(1, 1, 2) {
| ---------------- this expression has type `main::Blah`
LL | Blah::A(_, x, y) | Blah::B(x, y) => {}
| ^ expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:17:44
|
LL | match Some(Blah::A(1, 1, 2)) {
| ---------------------- this expression has type `std::option::Option<main::Blah>`
LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {}
| ^ expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:21:19
|
LL | match (0u8, 1u16) {
| ----------- this expression has type `(u8, u16)`
LL | (x, y) | (y, x) => {}
| ^ expected `u16`, found `u8`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:21:22
|
LL | match (0u8, 1u16) {
| ----------- this expression has type `(u8, u16)`
LL | (x, y) | (y, x) => {}
| ^ expected `u8`, found `u16`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:26:41
|
LL | match Some((0u8, Some((1u16, 2u32)))) {
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
| ^ expected `u16`, found `u8`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:26:50
|
LL | match Some((0u8, Some((1u16, 2u32)))) {
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
| ^ expected `u8`, found `u16`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:26:59
|
LL | match Some((0u8, Some((1u16, 2u32)))) {
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
| ^ expected `u32`, found `u16`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:26:62
|
LL | match Some((0u8, Some((1u16, 2u32)))) {
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
| ^ expected `u8`, found `u32`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:34:42
|
LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
| ^ ---------------- this expression has type `main::Blah`
| |
| expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:38:47
|
LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
| ^ ---------------------- this expression has type `std::option::Option<main::Blah>`
| |
| expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:42:22
|
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
| ^ ----------- this expression has type `(u8, u16)`
| |
| expected `u16`, found `u8`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:42:25
|
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
| ^ ----------- this expression has type `(u8, u16)`
| |
| expected `u8`, found `u16`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:47:44
|
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
| ^ expected `u16`, found `u8`
...
LL | = Some((0u8, Some((1u16, 2u32))))
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:47:53
|
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
| ^ expected `u8`, found `u16`
...
LL | = Some((0u8, Some((1u16, 2u32))))
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:47:62
|
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
| ^ expected `u32`, found `u16`
...
LL | = Some((0u8, Some((1u16, 2u32))))
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:47:65
|
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
| ^ expected `u8`, found `u32`
...
LL | = Some((0u8, Some((1u16, 2u32))))
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:55:39
|
LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
| ^ ---------------- this expression has type `main::Blah`
| |
| expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:58:19
|
LL | let (x, y) | (y, x) = (0u8, 1u16);
| ^ ----------- this expression has type `(u8, u16)`
| |
| expected `u16`, found `u8`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:58:22
|
LL | let (x, y) | (y, x) = (0u8, 1u16);
| ^ ----------- this expression has type `(u8, u16)`
| |
| expected `u8`, found `u16`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:62:42
|
LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
| ^ ---- expected due to this
| |
| expected `usize`, found `isize`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:65:22
|
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
| ^ --------- expected due to this
| |
| expected `u16`, found `u8`
error[E0308]: mismatched types
--> $DIR/or-patterns-binding-type-mismatch.rs:65:25
|
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
| ^ --------- expected due to this
| |
| expected `u8`, found `u16`
error: aborting due to 22 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,132 @@
// Test that or-patterns are pass-through with respect to default binding modes.
// check-pass
#![feature(or_patterns)]
#![allow(irrefutable_let_patterns)]
fn main() {
// A regression test for a mistake we made at one point:
match &1 {
e @ &(1..=2) | e @ &(3..=4) => {}
_ => {}
}
match &0 {
0 | &1 => {}
_ => {}
}
type R<'a> = &'a Result<u8, u8>;
let res: R<'_> = &Ok(0);
match res {
// Alternatives propagate expected type / binding mode independently.
Ok(mut x) | &Err(mut x) => drop::<u8>(x),
}
match res {
&(Ok(x) | Err(x)) => drop::<u8>(x),
}
match res {
Ok(x) | Err(x) => drop::<&u8>(x),
}
if let Ok(mut x) | &Err(mut x) = res {
drop::<u8>(x);
}
if let &(Ok(x) | Err(x)) = res {
drop::<u8>(x);
}
let Ok(mut x) | &Err(mut x) = res;
drop::<u8>(x);
let &(Ok(x) | Err(x)) = res;
drop::<u8>(x);
let Ok(x) | Err(x) = res;
drop::<&u8>(x);
for Ok(mut x) | &Err(mut x) in std::iter::once(res) {
drop::<u8>(x);
}
for &(Ok(x) | Err(x)) in std::iter::once(res) {
drop::<u8>(x);
}
for Ok(x) | Err(x) in std::iter::once(res) {
drop::<&u8>(x);
}
fn f1((Ok(mut x) | &Err(mut x)): R<'_>) {
drop::<u8>(x);
}
fn f2(&(Ok(x) | Err(x)): R<'_>) {
drop::<u8>(x);
}
fn f3((Ok(x) | Err(x)): R<'_>) {
drop::<&u8>(x);
}
// Wrap inside another type (a product for a simplity with irrefutable contexts).
#[derive(Copy, Clone)]
struct Wrap<T>(T);
let wres = Wrap(res);
match wres {
Wrap(Ok(mut x) | &Err(mut x)) => drop::<u8>(x),
}
match wres {
Wrap(&(Ok(x) | Err(x))) => drop::<u8>(x),
}
match wres {
Wrap(Ok(x) | Err(x)) => drop::<&u8>(x),
}
if let Wrap(Ok(mut x) | &Err(mut x)) = wres {
drop::<u8>(x);
}
if let Wrap(&(Ok(x) | Err(x))) = wres {
drop::<u8>(x);
}
if let Wrap(Ok(x) | Err(x)) = wres {
drop::<&u8>(x);
}
let Wrap(Ok(mut x) | &Err(mut x)) = wres;
drop::<u8>(x);
let Wrap(&(Ok(x) | Err(x))) = wres;
drop::<u8>(x);
let Wrap(Ok(x) | Err(x)) = wres;
drop::<&u8>(x);
for Wrap(Ok(mut x) | &Err(mut x)) in std::iter::once(wres) {
drop::<u8>(x);
}
for Wrap(&(Ok(x) | Err(x))) in std::iter::once(wres) {
drop::<u8>(x);
}
for Wrap(Ok(x) | Err(x)) in std::iter::once(wres) {
drop::<&u8>(x);
}
fn fw1(Wrap(Ok(mut x) | &Err(mut x)): Wrap<R<'_>>) {
drop::<u8>(x);
}
fn fw2(Wrap(&(Ok(x) | Err(x))): Wrap<R<'_>>) {
drop::<u8>(x);
}
fn fw3(Wrap(Ok(x) | Err(x)): Wrap<R<'_>>) {
drop::<&u8>(x);
}
// Nest some more:
enum Tri<P> {
A(P),
B(P),
C(P),
}
let tri = &Tri::A(&Ok(0));
let Tri::A(Ok(mut x) | Err(mut x))
| Tri::B(&Ok(mut x) | Err(mut x))
| &Tri::C(Ok(mut x) | Err(mut x)) = tri;
drop::<u8>(x);
match tri {
Tri::A(Ok(mut x) | Err(mut x))
| Tri::B(&Ok(mut x) | Err(mut x))
| &Tri::C(Ok(mut x) | Err(mut x)) => drop::<u8>(x),
}
}