Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c03f891

Browse files
authored
Rollup merge of rust-lang#118157 - Nadrieril:never_pat-feature-gate, r=compiler-errors
Add `never_patterns` feature gate This PR adds the feature gate and most basic parsing for the experimental `never_patterns` feature. See the tracking issue (rust-lang#118155) for details on the experiment. `@scottmcm` has agreed to be my lang-team liaison for this experiment.
2 parents ec1f21c + a3838c8 commit c03f891

File tree

40 files changed

+325
-18
lines changed

40 files changed

+325
-18
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ impl Pat {
645645
// These patterns do not contain subpatterns, skip.
646646
PatKind::Wild
647647
| PatKind::Rest
648+
| PatKind::Never
648649
| PatKind::Lit(_)
649650
| PatKind::Range(..)
650651
| PatKind::Ident(..)
@@ -795,6 +796,9 @@ pub enum PatKind {
795796
/// only one rest pattern may occur in the pattern sequences.
796797
Rest,
797798

799+
// A never pattern `!`
800+
Never,
801+
798802
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
799803
Paren(P<Pat>),
800804

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
12491249
let Pat { id, kind, span, tokens } = pat.deref_mut();
12501250
vis.visit_id(id);
12511251
match kind {
1252-
PatKind::Wild | PatKind::Rest => {}
1252+
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
12531253
PatKind::Ident(_binding_mode, ident, sub) => {
12541254
vis.visit_ident(ident);
12551255
visit_opt(sub, |sub| vis.visit_pat(sub));

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
559559
walk_list!(visitor, visit_expr, lower_bound);
560560
walk_list!(visitor, visit_expr, upper_bound);
561561
}
562-
PatKind::Wild | PatKind::Rest => {}
562+
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
563563
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
564564
walk_list!(visitor, visit_pat, elems);
565565
}

compiler/rustc_ast_lowering/src/pat.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
2424
let node = loop {
2525
match &pattern.kind {
2626
PatKind::Wild => break hir::PatKind::Wild,
27+
PatKind::Never => break hir::PatKind::Never,
2728
PatKind::Ident(binding_mode, ident, sub) => {
2829
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
2930
break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
555555
gate_all!(explicit_tail_calls, "`become` expression is experimental");
556556
gate_all!(generic_const_items, "generic const items are experimental");
557557
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
558+
gate_all!(never_patterns, "`!` patterns are experimental");
558559

559560
if !visitor.features.negative_bounds {
560561
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,7 @@ impl<'a> State<'a> {
13431343
is that it doesn't matter */
13441344
match &pat.kind {
13451345
PatKind::Wild => self.word("_"),
1346+
PatKind::Never => self.word("!"),
13461347
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
13471348
if *by_ref == ByRef::Yes {
13481349
self.word_nbsp("ref");

compiler/rustc_feature/src/unstable.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ macro_rules! declare_features {
155155
// was set.
156156
//
157157
// Note that the features are grouped into internal/user-facing and then
158-
// sorted by version inside those groups. This is enforced with tidy.
158+
// sorted alphabetically inside those groups. This is enforced with tidy.
159159
//
160160
// N.B., `tools/tidy/src/features.rs` parses this information directly out of the
161161
// source, so take care when modifying it.
@@ -520,6 +520,8 @@ declare_features! (
520520
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
521521
/// Allow negative trait implementations.
522522
(unstable, negative_impls, "1.44.0", Some(68318), None),
523+
/// Allows the `!` pattern.
524+
(incomplete, never_patterns, "CURRENT_RUSTC_VERSION", Some(118155), None),
523525
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
524526
(unstable, never_type, "1.13.0", Some(35121), None),
525527
/// Allows diverging expressions to fall back to `!` rather than `()`.

compiler/rustc_hir/src/hir.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ impl<'hir> Pat<'hir> {
10021002

10031003
use PatKind::*;
10041004
match self.kind {
1005-
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
1005+
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
10061006
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
10071007
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
10081008
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@@ -1029,7 +1029,7 @@ impl<'hir> Pat<'hir> {
10291029

10301030
use PatKind::*;
10311031
match self.kind {
1032-
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
1032+
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
10331033
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
10341034
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
10351035
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1142,6 +1142,9 @@ pub enum PatKind<'hir> {
11421142
/// Invariant: `pats.len() >= 2`.
11431143
Or(&'hir [Pat<'hir>]),
11441144

1145+
/// A never pattern `!`.
1146+
Never,
1147+
11451148
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
11461149
Path(QPath<'hir>),
11471150

compiler/rustc_hir/src/intravisit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
660660
walk_list!(visitor, visit_expr, lower_bound);
661661
walk_list!(visitor, visit_expr, upper_bound);
662662
}
663-
PatKind::Wild => (),
663+
PatKind::Never | PatKind::Wild => (),
664664
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
665665
walk_list!(visitor, visit_pat, prepatterns);
666666
walk_list!(visitor, visit_pat, slice_pattern);

compiler/rustc_hir_analysis/src/check/region.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ fn resolve_local<'tcx>(
662662
PatKind::Ref(_, _)
663663
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
664664
| PatKind::Wild
665+
| PatKind::Never
665666
| PatKind::Path(_)
666667
| PatKind::Lit(_)
667668
| PatKind::Range(_, _, _) => false,

0 commit comments

Comments
 (0)