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:
commit
829a3635e4
@ -89,6 +89,18 @@ fn demand_eqtype_pat(
|
||||
}
|
||||
}
|
||||
|
||||
const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not);
|
||||
|
||||
/// Mode for adjusting the expected type and binding mode.
|
||||
enum AdjustMode {
|
||||
/// Peel off all immediate reference types.
|
||||
Peel,
|
||||
/// Reset binding mode to the inital mode.
|
||||
Reset,
|
||||
/// Pass on the input binding mode and expected type.
|
||||
Pass,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Type check the given top level pattern against the `expected` type.
|
||||
///
|
||||
@ -105,8 +117,7 @@ pub fn check_pat_top(
|
||||
span: Option<Span>,
|
||||
origin_expr: bool,
|
||||
) {
|
||||
let def_bm = BindingMode::BindByValue(hir::Mutability::Not);
|
||||
self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span });
|
||||
self.check_pat(pat, expected, INITIAL_BM, TopInfo { expected, origin_expr, span });
|
||||
}
|
||||
|
||||
/// Type check the given `pat` against the `expected` type
|
||||
@ -123,12 +134,12 @@ fn check_pat(
|
||||
) {
|
||||
debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
|
||||
|
||||
let path_resolution = match &pat.kind {
|
||||
let path_res = match &pat.kind {
|
||||
PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
|
||||
_ => None,
|
||||
};
|
||||
let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res));
|
||||
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp);
|
||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
||||
|
||||
let ty = match pat.kind {
|
||||
PatKind::Wild => expected,
|
||||
@ -141,7 +152,7 @@ fn check_pat(
|
||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
|
||||
}
|
||||
PatKind::Path(ref qpath) => {
|
||||
self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected)
|
||||
self.check_pat_path(pat, path_res.unwrap(), qpath, expected)
|
||||
}
|
||||
PatKind::Struct(ref qpath, fields, etc) => {
|
||||
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
|
||||
@ -223,15 +234,48 @@ fn calc_default_binding_mode(
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: BindingMode,
|
||||
is_non_ref_pat: bool,
|
||||
adjust_mode: AdjustMode,
|
||||
) -> (Ty<'tcx>, BindingMode) {
|
||||
if is_non_ref_pat {
|
||||
debug!("pattern is non reference pattern");
|
||||
self.peel_off_references(pat, expected, def_bm)
|
||||
} else {
|
||||
// When you encounter a `&pat` pattern, reset to "by
|
||||
// value". This is so that `x` and `y` here are by value,
|
||||
// as they appear to be:
|
||||
match adjust_mode {
|
||||
AdjustMode::Pass => (expected, def_bm),
|
||||
AdjustMode::Reset => (expected, INITIAL_BM),
|
||||
AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm),
|
||||
}
|
||||
}
|
||||
|
||||
/// How should the binding mode and expected type be adjusted?
|
||||
///
|
||||
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
|
||||
fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
|
||||
match &pat.kind {
|
||||
// Type checking these product-like types successfully always require
|
||||
// that the expected type be of those types and not reference types.
|
||||
PatKind::Struct(..)
|
||||
| PatKind::TupleStruct(..)
|
||||
| PatKind::Tuple(..)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Slice(..) => AdjustMode::Peel,
|
||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||
// All other literals result in non-reference types.
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
|
||||
PatKind::Lit(lt) => match self.check_expr(lt).kind {
|
||||
ty::Ref(..) => AdjustMode::Pass,
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
PatKind::Path(_) => match opt_path_res.unwrap() {
|
||||
// These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
|
||||
// Peeling the reference types too early will cause type checking failures.
|
||||
// Although it would be possible to *also* peel the types of the constants too.
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => AdjustMode::Pass,
|
||||
// In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which
|
||||
// could successfully compile. The former being `Self` requires a unit struct.
|
||||
// In either case, and unlike constants, the pattern itself cannot be
|
||||
// a reference type wherefore peeling doesn't give up any expressivity.
|
||||
_ => AdjustMode::Peel,
|
||||
},
|
||||
// When encountering a `& mut? pat` pattern, reset to "by value".
|
||||
// This is so that `x` and `y` here are by value, as they appear to be:
|
||||
//
|
||||
// ```
|
||||
// match &(&22, &44) {
|
||||
@ -240,47 +284,18 @@ fn calc_default_binding_mode(
|
||||
// ```
|
||||
//
|
||||
// See issue #46688.
|
||||
let def_bm = match pat.kind {
|
||||
PatKind::Ref(..) => ty::BindByValue(hir::Mutability::Not),
|
||||
_ => def_bm,
|
||||
};
|
||||
(expected, def_bm)
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the pattern a "non reference pattern"?
|
||||
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
|
||||
fn is_non_ref_pat(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> bool {
|
||||
match pat.kind {
|
||||
PatKind::Struct(..)
|
||||
| PatKind::TupleStruct(..)
|
||||
| PatKind::Tuple(..)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Slice(..) => true,
|
||||
PatKind::Lit(ref lt) => {
|
||||
let ty = self.check_expr(lt);
|
||||
match ty.kind {
|
||||
ty::Ref(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
PatKind::Path(_) => match opt_path_res.unwrap() {
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false,
|
||||
_ => true,
|
||||
},
|
||||
// FIXME(or_patterns; Centril | dlrobertson): To keep things compiling
|
||||
// for or-patterns at the top level, we need to make `p_0 | ... | p_n`
|
||||
// a "non reference pattern". For example the following currently compiles:
|
||||
// ```
|
||||
// match &1 {
|
||||
// e @ &(1...2) | e @ &(3...4) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// We should consider whether we should do something special in nested or-patterns.
|
||||
PatKind::Or(_) | PatKind::Wild | PatKind::Binding(..) | PatKind::Ref(..) => false,
|
||||
PatKind::Ref(..) => AdjustMode::Reset,
|
||||
// A `_` pattern works with any expected type, so there's no need to do anything.
|
||||
PatKind::Wild
|
||||
// Bindings also work with whatever the expected type is,
|
||||
// and moreover if we peel references off, that will give us the wrong binding type.
|
||||
// Also, we can have a subpattern `binding @ pat`.
|
||||
// Each side of the `@` should be treated independently (like with OR-patterns).
|
||||
| PatKind::Binding(..)
|
||||
// An OR-pattern just propagates to each individual alternative.
|
||||
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
|
||||
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
|
||||
| PatKind::Or(_) => AdjustMode::Pass,
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,7 +523,7 @@ fn check_pat_ident(
|
||||
let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty;
|
||||
let eq_ty = match bm {
|
||||
ty::BindByReference(mutbl) => {
|
||||
// If the binding is like `ref x | ref const x | ref mut x`
|
||||
// If the binding is like `ref x | ref mut x`,
|
||||
// then `x` is assigned a value of type `&M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
//
|
||||
|
@ -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
|
@ -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`.
|
68
src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs
Normal file
68
src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs
Normal 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
|
||||
}
|
183
src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
Normal file
183
src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
Normal 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`.
|
132
src/test/ui/or-patterns/or-patterns-default-binding-modes.rs
Normal file
132
src/test/ui/or-patterns/or-patterns-default-binding-modes.rs
Normal 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),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user