Rollup merge of #57535 - varkor:stabilise-if-while-let-patterns, r=Centril

Stabilise irrefutable if-let and while-let patterns

This stabilises RFC 2086 (https://github.com/rust-lang/rust/issues/44495).

This replaces https://github.com/rust-lang/rust/pull/55639, as we want to stabilise this in time for the beta cut-off.

Closes https://github.com/rust-lang/rust/pull/55639.

r? @Centril
This commit is contained in:
Mazdak Farrokhzad 2019-01-12 10:55:25 +01:00 committed by GitHub
commit 3117784c18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 176 additions and 239 deletions

View file

@ -1,28 +0,0 @@
# `irrefutable_let_patterns`
The tracking issue for this feature is: [#44495]
[#44495]: https://github.com/rust-lang/rust/issues/44495
------------------------
This feature changes the way that "irrefutable patterns" are handled
in the `if let` and `while let` forms. An *irrefutable pattern* is one
that cannot fail to match -- for example, the `_` pattern matches any
value, and hence it is "irrefutable". Without this feature, using an
irrefutable pattern in an `if let` gives a hard error (since often
this indicates programmer error). But when the feature is enabled, the
error becomes a lint (since in some cases irrefutable patterns are
expected). This means you can use `#[allow]` to silence the lint:
```rust
#![feature(irrefutable_let_patterns)]
#[allow(irrefutable_let_patterns)]
fn main() {
// These two examples used to be errors, but now they
// trigger a lint (that is allowed):
if let _ = 5 {}
while let _ = 5 { break; }
}
```

View file

@ -286,7 +286,7 @@ declare_lint! {
declare_lint! {
pub IRREFUTABLE_LET_PATTERNS,
Deny,
Warn,
"detects irrefutable patterns in if-let and while-let statements"
}

View file

@ -325,11 +325,13 @@ match Some(42) {
"##,
E0162: r##"
#### Note: this error code is no longer emitted by the compiler.
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding instead. For instance:
```compile_fail,E0162
```compile_pass
struct Irrefutable(i32);
let irr = Irrefutable(0);
@ -352,11 +354,13 @@ println!("{}", x);
"##,
E0165: r##"
#### Note: this error code is no longer emitted by the compiler.
A while-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
match), use a regular `let`-binding inside a `loop` instead. For instance:
```compile_fail,E0165
```compile_pass,no_run
struct Irrefutable(i32);
let irr = Irrefutable(0);

View file

@ -350,7 +350,6 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
{
let mut seen = Matrix::empty();
let mut catchall = None;
let mut printed_if_let_err = false;
for (arm_index, &(ref pats, guard)) in arms.iter().enumerate() {
for &(pat, hir_pat) in pats {
let v = smallvec![pat];
@ -359,27 +358,12 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
NotUseful => {
match source {
hir::MatchSource::IfLetDesugar { .. } => {
if cx.tcx.features().irrefutable_let_patterns {
cx.tcx.lint_node(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.id, pat.span,
"irrefutable if-let pattern");
} else {
if printed_if_let_err {
// we already printed an irrefutable if-let pattern error.
// We don't want two, that's just confusing.
} else {
// find the first arm pattern so we can use its span
let &(ref first_arm_pats, _) = &arms[0];
let first_pat = &first_arm_pats[0];
let span = first_pat.0.span;
struct_span_err!(cx.tcx.sess, span, E0162,
"irrefutable if-let pattern")
.span_label(span, "irrefutable pattern")
.emit();
printed_if_let_err = true;
}
}
cx.tcx.lint_node(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.id,
pat.span,
"irrefutable if-let pattern",
);
}
hir::MatchSource::WhileLetDesugar => {
@ -394,21 +378,12 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
},
// The arm with the wildcard pattern.
1 => {
if cx.tcx.features().irrefutable_let_patterns {
cx.tcx.lint_node(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.id, pat.span,
"irrefutable while-let pattern");
} else {
// find the first arm pattern so we can use its span
let &(ref first_arm_pats, _) = &arms[0];
let first_pat = &first_arm_pats[0];
let span = first_pat.0.span;
struct_span_err!(cx.tcx.sess, span, E0165,
"irrefutable while-let pattern")
.span_label(span, "irrefutable pattern")
.emit();
}
cx.tcx.lint_node(
lint::builtin::IRREFUTABLE_LET_PATTERNS,
hir_pat.id,
pat.span,
"irrefutable while-let pattern",
);
},
_ => bug!(),
}

View file

@ -411,9 +411,6 @@ declare_features! (
// `#[doc(alias = "...")]`
(active, doc_alias, "1.27.0", Some(50146), None),
// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
(active, irrefutable_let_patterns, "1.27.0", Some(44495), None),
// inconsistent bounds in where clauses
(active, trivial_bounds, "1.28.0", Some(48214), None),
@ -681,6 +678,8 @@ declare_features! (
(accepted, underscore_imports, "1.33.0", Some(48216), None),
// Allows `#[repr(packed(N))]` attribute on structs.
(accepted, repr_packed, "1.33.0", Some(33158), None),
// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
(accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
(accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None),
// Allows let bindings, assignments and destructuring in `const` functions and constants.

View file

@ -1,12 +0,0 @@
// run-pass
#![feature(irrefutable_let_patterns)]
// must-compile-successfully-irrefutable_let_patterns_with_gate
#[allow(irrefutable_let_patterns)]
fn main() {
if let _ = 5 {}
while let _ = 5 {
break;
}
}

View file

@ -1,8 +0,0 @@
struct Irrefutable(i32);
fn main() {
let irr = Irrefutable(0);
if let Irrefutable(x) = irr { //~ ERROR E0162
println!("{}", x);
}
}

View file

@ -1,9 +0,0 @@
error[E0162]: irrefutable if-let pattern
--> $DIR/E0162.rs:5:12
|
LL | if let Irrefutable(x) = irr { //~ ERROR E0162
| ^^^^^^^^^^^^^^ irrefutable pattern
error: aborting due to previous error
For more information about this error, try `rustc --explain E0162`.

View file

@ -1,9 +0,0 @@
struct Irrefutable(i32);
fn main() {
let irr = Irrefutable(0);
while let Irrefutable(x) = irr { //~ ERROR E0165
//~| irrefutable pattern
// ...
}
}

View file

@ -1,9 +0,0 @@
error[E0165]: irrefutable while-let pattern
--> $DIR/E0165.rs:5:15
|
LL | while let Irrefutable(x) = irr { //~ ERROR E0165
| ^^^^^^^^^^^^^^ irrefutable pattern
error: aborting due to previous error
For more information about this error, try `rustc --explain E0165`.

View file

@ -1,8 +0,0 @@
// gate-test-irrefutable_let_patterns
#[allow(irrefutable_let_patterns)]
fn main() {
if let _ = 5 {}
//~^ ERROR irrefutable if-let pattern [E0162]
}

View file

@ -1,9 +0,0 @@
error[E0162]: irrefutable if-let pattern
--> $DIR/feature-gate-without_gate_irrefutable_pattern.rs:6:12
|
LL | if let _ = 5 {}
| ^ irrefutable pattern
error: aborting due to previous error
For more information about this error, try `rustc --explain E0162`.

View file

@ -1,3 +1,5 @@
// compile-pass
fn macros() {
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
@ -10,20 +12,20 @@ fn macros() {
}}
}
foo!(a, 1, { //~ ERROR irrefutable if-let
foo!(a, 1, { //~ WARN irrefutable if-let
println!("irrefutable pattern");
});
bar!(a, 1, { //~ ERROR irrefutable if-let
bar!(a, 1, { //~ WARN irrefutable if-let
println!("irrefutable pattern");
});
}
pub fn main() {
if let a = 1 { //~ ERROR irrefutable if-let
if let a = 1 { //~ WARN irrefutable if-let
println!("irrefutable pattern");
}
if let a = 1 { //~ ERROR irrefutable if-let
if let a = 1 { //~ WARN irrefutable if-let
println!("irrefutable pattern");
} else if true {
println!("else-if in irrefutable if-let");
@ -33,13 +35,13 @@ pub fn main() {
if let 1 = 2 {
println!("refutable pattern");
} else if let a = 1 { //~ ERROR irrefutable if-let
} else if let a = 1 { //~ WARN irrefutable if-let
println!("irrefutable pattern");
}
if true {
println!("if");
} else if let a = 1 { //~ ERROR irrefutable if-let
} else if let a = 1 { //~ WARN irrefutable if-let
println!("irrefutable pattern");
}
}

View file

@ -1,39 +1,62 @@
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:13:10
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:6:13
|
LL | foo!(a, 1, { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:16:10
LL | if let $p = $e $b
| ^^
...
LL | / foo!(a, 1, { //~ WARN irrefutable if-let
LL | | println!("irrefutable pattern");
LL | | });
| |_______- in this macro invocation
|
LL | bar!(a, 1, { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
= note: #[warn(irrefutable_let_patterns)] on by default
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:22:12
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:6:13
|
LL | if let a = 1 { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
LL | if let $p = $e $b
| ^^
...
LL | / bar!(a, 1, { //~ WARN irrefutable if-let
LL | | println!("irrefutable pattern");
LL | | });
| |_______- in this macro invocation
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:26:12
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:24:5
|
LL | if let a = 1 { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
LL | / if let a = 1 { //~ WARN irrefutable if-let
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:36:19
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:28:5
|
LL | } else if let a = 1 { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
LL | / if let a = 1 { //~ WARN irrefutable if-let
LL | | println!("irrefutable pattern");
LL | | } else if true {
LL | | println!("else-if in irrefutable if-let");
LL | | } else {
LL | | println!("else in irrefutable if-let");
LL | | }
| |_____^
error[E0162]: irrefutable if-let pattern
--> $DIR/if-let.rs:42:19
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:38:12
|
LL | } else if let a = 1 { //~ ERROR irrefutable if-let
| ^ irrefutable pattern
LL | } else if let a = 1 { //~ WARN irrefutable if-let
| ____________^
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
error: aborting due to 6 previous errors
warning: irrefutable if-let pattern
--> $DIR/if-let.rs:44:12
|
LL | } else if let a = 1 { //~ WARN irrefutable if-let
| ____________^
LL | | println!("irrefutable pattern");
LL | | }
| |_____^
For more information about this error, try `rustc --explain E0162`.

View file

@ -10,5 +10,5 @@ fn main() {
[(); return while let Some(n) = Some(0) {}];
//~^ ERROR return statement outside of function body
//~^^ ERROR irrefutable while-let pattern
//~^^ WARN irrefutable while-let pattern
}

View file

@ -22,13 +22,14 @@ error[E0572]: return statement outside of function body
LL | [(); return while let Some(n) = Some(0) {}];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0165]: irrefutable while-let pattern
--> $DIR/issue-51714.rs:11:27
warning: irrefutable while-let pattern
--> $DIR/issue-51714.rs:11:17
|
LL | [(); return while let Some(n) = Some(0) {}];
| ^^^^^^^ irrefutable pattern
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(irrefutable_let_patterns)] on by default
error: aborting due to 5 previous errors
error: aborting due to 4 previous errors
Some errors occurred: E0165, E0572.
For more information about an error, try `rustc --explain E0165`.
For more information about this error, try `rustc --explain E0572`.

View file

@ -0,0 +1,9 @@
#![deny(irrefutable_let_patterns)]
fn main() {
if let _ = 5 {} //~ ERROR irrefutable if-let pattern
while let _ = 5 { //~ ERROR irrefutable while-let pattern
break;
}
}

View file

@ -0,0 +1,22 @@
error: irrefutable if-let pattern
--> $DIR/deny-irrefutable-let-patterns.rs:4:5
|
LL | if let _ = 5 {} //~ ERROR irrefutable if-let pattern
| ^^^^^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/deny-irrefutable-let-patterns.rs:1:9
|
LL | #![deny(irrefutable_let_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: irrefutable while-let pattern
--> $DIR/deny-irrefutable-let-patterns.rs:6:5
|
LL | / while let _ = 5 { //~ ERROR irrefutable while-let pattern
LL | | break;
LL | | }
| |_____^
error: aborting due to 2 previous errors

View file

@ -1,4 +1,5 @@
#![feature(irrefutable_let_patterns)]
// run-pass
#![feature(type_alias_enum_variants)]
#![allow(irrefutable_let_patterns)]

View file

@ -0,0 +1,11 @@
// run-pass
#![allow(irrefutable_let_patterns)]
fn main() {
if let _ = 5 {}
while let _ = 5 {
break;
}
}

View file

@ -2,7 +2,6 @@
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#![feature(irrefutable_let_patterns)]
#[allow(irrefutable_let_patterns)]
fn main() {

View file

@ -1,5 +1,5 @@
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:11:47
--> $DIR/syntax-ambiguity-2015.rs:10:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
@ -8,7 +8,7 @@ LL | if let Range { start: _, end: _ } = true..true && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:14:47
--> $DIR/syntax-ambiguity-2015.rs:13:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
@ -17,7 +17,7 @@ LL | if let Range { start: _, end: _ } = true..true || false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:17:50
--> $DIR/syntax-ambiguity-2015.rs:16:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
@ -26,7 +26,7 @@ LL | while let Range { start: _, end: _ } = true..true && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2015.rs:20:50
--> $DIR/syntax-ambiguity-2015.rs:19:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
@ -35,7 +35,7 @@ LL | while let Range { start: _, end: _ } = true..true || false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:23:19
--> $DIR/syntax-ambiguity-2015.rs:22:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
@ -44,7 +44,7 @@ LL | if let true = false && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:26:22
--> $DIR/syntax-ambiguity-2015.rs:25:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`

View file

@ -2,7 +2,6 @@
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#![feature(irrefutable_let_patterns)]
#[allow(irrefutable_let_patterns)]
fn main() {

View file

@ -1,5 +1,5 @@
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:11:47
--> $DIR/syntax-ambiguity-2018.rs:10:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
@ -8,7 +8,7 @@ LL | if let Range { start: _, end: _ } = true..true && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:14:47
--> $DIR/syntax-ambiguity-2018.rs:13:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
@ -17,7 +17,7 @@ LL | if let Range { start: _, end: _ } = true..true || false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:17:50
--> $DIR/syntax-ambiguity-2018.rs:16:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
@ -26,7 +26,7 @@ LL | while let Range { start: _, end: _ } = true..true && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `||`
--> $DIR/syntax-ambiguity-2018.rs:20:50
--> $DIR/syntax-ambiguity-2018.rs:19:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
@ -35,7 +35,7 @@ LL | while let Range { start: _, end: _ } = true..true || false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:23:19
--> $DIR/syntax-ambiguity-2018.rs:22:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
@ -44,7 +44,7 @@ LL | if let true = false && false { }
= note: see rust-lang/rust#53668 for more information
error: ambiguous use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:26:22
--> $DIR/syntax-ambiguity-2018.rs:25:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`

View file

@ -1,5 +0,0 @@
// should-fail-irrefutable_let_patterns
fn main() {
if let _ = 5 {}
//~^ ERROR irrefutable if-let pattern [E0162]
}

View file

@ -1,9 +0,0 @@
error[E0162]: irrefutable if-let pattern
--> $DIR/should-fail-no_gate_irrefutable_if_let_pattern.rs:3:12
|
LL | if let _ = 5 {}
| ^ irrefutable pattern
error: aborting due to previous error
For more information about this error, try `rustc --explain E0162`.

View file

@ -1,7 +0,0 @@
#![feature(irrefutable_let_patterns)]
// should-fail-irrefutable_let_patterns_with_gate
fn main() {
if let _ = 5 {}
//~^ ERROR irrefutable if-let pattern [irrefutable_let_patterns]
}

View file

@ -1,10 +0,0 @@
error: irrefutable if-let pattern
--> $DIR/should-fail-with_gate_irrefutable_pattern_deny.rs:5:5
|
LL | if let _ = 5 {}
| ^^^^^^^^^^^^^^^
|
= note: #[deny(irrefutable_let_patterns)] on by default
error: aborting due to previous error

View file

@ -1,3 +1,5 @@
// run-pass
fn macros() {
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
@ -10,16 +12,17 @@ fn macros() {
}}
}
foo!(a, 1, { //~ ERROR irrefutable while-let
foo!(a, 1, { //~ WARN irrefutable while-let
println!("irrefutable pattern");
});
bar!(a, 1, { //~ ERROR irrefutable while-let
bar!(a, 1, { //~ WARN irrefutable while-let
println!("irrefutable pattern");
});
}
pub fn main() {
while let a = 1 { //~ ERROR irrefutable while-let
while let a = 1 { //~ WARN irrefutable while-let
println!("irrefutable pattern");
break;
}
}

View file

@ -1,21 +1,33 @@
error[E0165]: irrefutable while-let pattern
--> $DIR/while-let.rs:13:10
warning: irrefutable while-let pattern
--> $DIR/while-let.rs:6:13
|
LL | foo!(a, 1, { //~ ERROR irrefutable while-let
| ^ irrefutable pattern
error[E0165]: irrefutable while-let pattern
--> $DIR/while-let.rs:16:10
LL | while let $p = $e $b
| ^^^^^
...
LL | / foo!(a, 1, { //~ WARN irrefutable while-let
LL | | println!("irrefutable pattern");
LL | | });
| |_______- in this macro invocation
|
LL | bar!(a, 1, { //~ ERROR irrefutable while-let
| ^ irrefutable pattern
= note: #[warn(irrefutable_let_patterns)] on by default
error[E0165]: irrefutable while-let pattern
--> $DIR/while-let.rs:22:15
warning: irrefutable while-let pattern
--> $DIR/while-let.rs:6:13
|
LL | while let a = 1 { //~ ERROR irrefutable while-let
| ^ irrefutable pattern
LL | while let $p = $e $b
| ^^^^^
...
LL | / bar!(a, 1, { //~ WARN irrefutable while-let
LL | | println!("irrefutable pattern");
LL | | });
| |_______- in this macro invocation
error: aborting due to 3 previous errors
warning: irrefutable while-let pattern
--> $DIR/while-let.rs:24:5
|
LL | / while let a = 1 { //~ WARN irrefutable while-let
LL | | println!("irrefutable pattern");
LL | | break;
LL | | }
| |_____^
For more information about this error, try `rustc --explain E0165`.