Skip to content

Commit 309fd8a

Browse files
committed
Auto merge of #49469 - Nokel81:allow-irrefutable-let-patterns, r=nikomatsakis
Implementation of RFC 2086 - Allow Irrefutable Let patterns This is the set of changes for RFC2086. Tracking issue #44495. Rendered [here](rust-lang/rfcs#2086)
2 parents 773ce53 + 9168034 commit 309fd8a

File tree

8 files changed

+143
-22
lines changed

8 files changed

+143
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# `irrefutable_let_patterns`
2+
3+
The tracking issue for this feature is: [#44495]
4+
5+
[#44495]: https://github.com/rust-lang/rust/issues/44495
6+
7+
------------------------
8+
9+
This feature changes the way that "irrefutable patterns" are handled
10+
in the `if let` and `while let` forms. An *irrefutable pattern* is one
11+
that cannot fail to match -- for example, the `_` pattern matches any
12+
value, and hence it is "irrefutable". Without this feature, using an
13+
irrefutable pattern in an `if let` gives a hard error (since often
14+
this indicates programmer error). But when the feature is enabled, the
15+
error becomes a lint (since in some cases irrefutable patterns are
16+
expected). This means you can use `#[allow]` to silence the lint:
17+
18+
```rust
19+
#![feature(irrefutable_let_patterns)]
20+
21+
#[allow(irrefutable_let_patterns)]
22+
fn main() {
23+
// These two examples used to be errors, but now they
24+
// trigger a lint (that is allowed):
25+
if let _ = 5 {}
26+
while let _ = 5 { break; }
27+
}
28+
```

src/librustc/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,12 @@ declare_lint! {
280280
"detects name collision with an existing but unstable method"
281281
}
282282

283+
declare_lint! {
284+
pub IRREFUTABLE_LET_PATTERNS,
285+
Deny,
286+
"detects irrefutable patterns in if-let and while-let statements"
287+
}
288+
283289
declare_lint! {
284290
pub UNUSED_LABELS,
285291
Allow,
@@ -361,6 +367,7 @@ impl LintPass for HardwiredLints {
361367
BARE_TRAIT_OBJECTS,
362368
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
363369
UNSTABLE_NAME_COLLISIONS,
370+
IRREFUTABLE_LET_PATTERNS,
364371
DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
365372
DUPLICATE_MACRO_EXPORTS,
366373
INTRA_DOC_LINK_RESOLUTION_FAILURE,

src/librustc_mir/hair/pattern/check_match.rs

+35-22
Original file line numberDiff line numberDiff line change
@@ -371,43 +371,56 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
371371
NotUseful => {
372372
match source {
373373
hir::MatchSource::IfLetDesugar { .. } => {
374-
if printed_if_let_err {
375-
// we already printed an irrefutable if-let pattern error.
376-
// We don't want two, that's just confusing.
374+
if cx.tcx.features().irrefutable_let_patterns {
375+
cx.tcx.lint_node(
376+
lint::builtin::IRREFUTABLE_LET_PATTERNS,
377+
hir_pat.id, pat.span,
378+
"irrefutable if-let pattern");
377379
} else {
378-
// find the first arm pattern so we can use its span
379-
let &(ref first_arm_pats, _) = &arms[0];
380-
let first_pat = &first_arm_pats[0];
381-
let span = first_pat.0.span;
382-
struct_span_err!(cx.tcx.sess, span, E0162,
383-
"irrefutable if-let pattern")
384-
.span_label(span, "irrefutable pattern")
385-
.emit();
386-
printed_if_let_err = true;
380+
if printed_if_let_err {
381+
// we already printed an irrefutable if-let pattern error.
382+
// We don't want two, that's just confusing.
383+
} else {
384+
// find the first arm pattern so we can use its span
385+
let &(ref first_arm_pats, _) = &arms[0];
386+
let first_pat = &first_arm_pats[0];
387+
let span = first_pat.0.span;
388+
struct_span_err!(cx.tcx.sess, span, E0162,
389+
"irrefutable if-let pattern")
390+
.span_label(span, "irrefutable pattern")
391+
.emit();
392+
printed_if_let_err = true;
393+
}
387394
}
388395
},
389396

390397
hir::MatchSource::WhileLetDesugar => {
391-
// find the first arm pattern so we can use its span
392-
let &(ref first_arm_pats, _) = &arms[0];
393-
let first_pat = &first_arm_pats[0];
394-
let span = first_pat.0.span;
395-
396398
// check which arm we're on.
397399
match arm_index {
398400
// The arm with the user-specified pattern.
399401
0 => {
400402
cx.tcx.lint_node(
401-
lint::builtin::UNREACHABLE_PATTERNS,
403+
lint::builtin::UNREACHABLE_PATTERNS,
402404
hir_pat.id, pat.span,
403405
"unreachable pattern");
404406
},
405407
// The arm with the wildcard pattern.
406408
1 => {
407-
struct_span_err!(cx.tcx.sess, span, E0165,
408-
"irrefutable while-let pattern")
409-
.span_label(span, "irrefutable pattern")
410-
.emit();
409+
if cx.tcx.features().irrefutable_let_patterns {
410+
cx.tcx.lint_node(
411+
lint::builtin::IRREFUTABLE_LET_PATTERNS,
412+
hir_pat.id, pat.span,
413+
"irrefutable while-let pattern");
414+
} else {
415+
// find the first arm pattern so we can use its span
416+
let &(ref first_arm_pats, _) = &arms[0];
417+
let first_pat = &first_arm_pats[0];
418+
let span = first_pat.0.span;
419+
struct_span_err!(cx.tcx.sess, span, E0165,
420+
"irrefutable while-let pattern")
421+
.span_label(span, "irrefutable pattern")
422+
.emit();
423+
}
411424
},
412425
_ => bug!(),
413426
}

src/libsyntax/feature_gate.rs

+3
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,9 @@ declare_features! (
458458
// Scoped attributes
459459
(active, tool_attributes, "1.25.0", Some(44690), None),
460460

461+
// allow irrefutable patterns in if-let and while-let statements (RFC 2086)
462+
(active, irrefutable_let_patterns, "1.27.0", Some(44495), None),
463+
461464
// Allows use of the :literal macro fragment specifier (RFC 1576)
462465
(active, macro_literal_matcher, "1.27.0", Some(35625), None),
463466

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// gate-test-irrefutable_let_patterns
2+
3+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
4+
// file at the top-level directory of this distribution and at
5+
// http://rust-lang.org/COPYRIGHT.
6+
//
7+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10+
// option. This file may not be copied, modified, or distributed
11+
// except according to those terms.
12+
13+
#[allow(irrefutable_let_patterns)]
14+
fn main() {
15+
if let _ = 5 {}
16+
//~^ ERROR 15:12: 15:13: irrefutable if-let pattern [E0162]
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// should-fail-irrefutable_let_patterns
12+
fn main() {
13+
if let _ = 5 {}
14+
//~^ ERROR irrefutable if-let pattern [E0162]
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(irrefutable_let_patterns)]
12+
13+
// should-fail-irrefutable_let_patterns_with_gate
14+
fn main() {
15+
if let _ = 5 {}
16+
//~^ ERROR irrefutable if-let pattern [irrefutable_let_patterns]
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(irrefutable_let_patterns)]
12+
13+
// must-compile-successfully-irrefutable_let_patterns_with_gate
14+
#[allow(irrefutable_let_patterns)]
15+
fn main() {
16+
if let _ = 5 {}
17+
18+
while let _ = 5 {
19+
break;
20+
}
21+
}

0 commit comments

Comments
 (0)