Add never_patterns
feature gate
This commit is contained in:
parent
1bcbb7c93b
commit
a3838c8550
@ -645,6 +645,7 @@ impl Pat {
|
|||||||
// These patterns do not contain subpatterns, skip.
|
// These patterns do not contain subpatterns, skip.
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
| PatKind::Rest
|
| PatKind::Rest
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Lit(_)
|
| PatKind::Lit(_)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Ident(..)
|
| PatKind::Ident(..)
|
||||||
@ -795,6 +796,9 @@ pub enum PatKind {
|
|||||||
/// only one rest pattern may occur in the pattern sequences.
|
/// only one rest pattern may occur in the pattern sequences.
|
||||||
Rest,
|
Rest,
|
||||||
|
|
||||||
|
// A never pattern `!`
|
||||||
|
Never,
|
||||||
|
|
||||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||||
Paren(P<Pat>),
|
Paren(P<Pat>),
|
||||||
|
|
||||||
|
@ -1249,7 +1249,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
|
|||||||
let Pat { id, kind, span, tokens } = pat.deref_mut();
|
let Pat { id, kind, span, tokens } = pat.deref_mut();
|
||||||
vis.visit_id(id);
|
vis.visit_id(id);
|
||||||
match kind {
|
match kind {
|
||||||
PatKind::Wild | PatKind::Rest => {}
|
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||||
PatKind::Ident(_binding_mode, ident, sub) => {
|
PatKind::Ident(_binding_mode, ident, sub) => {
|
||||||
vis.visit_ident(ident);
|
vis.visit_ident(ident);
|
||||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||||
|
@ -559,7 +559,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||||||
walk_list!(visitor, visit_expr, lower_bound);
|
walk_list!(visitor, visit_expr, lower_bound);
|
||||||
walk_list!(visitor, visit_expr, upper_bound);
|
walk_list!(visitor, visit_expr, upper_bound);
|
||||||
}
|
}
|
||||||
PatKind::Wild | PatKind::Rest => {}
|
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||||
walk_list!(visitor, visit_pat, elems);
|
walk_list!(visitor, visit_pat, elems);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
let node = loop {
|
let node = loop {
|
||||||
match &pattern.kind {
|
match &pattern.kind {
|
||||||
PatKind::Wild => break hir::PatKind::Wild,
|
PatKind::Wild => break hir::PatKind::Wild,
|
||||||
|
PatKind::Never => break hir::PatKind::Never,
|
||||||
PatKind::Ident(binding_mode, ident, sub) => {
|
PatKind::Ident(binding_mode, ident, sub) => {
|
||||||
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
|
let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
|
||||||
break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);
|
break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);
|
||||||
|
@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||||
gate_all!(generic_const_items, "generic const items are experimental");
|
gate_all!(generic_const_items, "generic const items are experimental");
|
||||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||||
|
gate_all!(never_patterns, "`!` patterns are experimental");
|
||||||
|
|
||||||
if !visitor.features.negative_bounds {
|
if !visitor.features.negative_bounds {
|
||||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||||
|
@ -1343,6 +1343,7 @@ impl<'a> State<'a> {
|
|||||||
is that it doesn't matter */
|
is that it doesn't matter */
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
PatKind::Wild => self.word("_"),
|
PatKind::Wild => self.word("_"),
|
||||||
|
PatKind::Never => self.word("!"),
|
||||||
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
|
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
|
||||||
if *by_ref == ByRef::Yes {
|
if *by_ref == ByRef::Yes {
|
||||||
self.word_nbsp("ref");
|
self.word_nbsp("ref");
|
||||||
|
@ -147,7 +147,7 @@ macro_rules! declare_features {
|
|||||||
// was set.
|
// was set.
|
||||||
//
|
//
|
||||||
// Note that the features are grouped into internal/user-facing and then
|
// Note that the features are grouped into internal/user-facing and then
|
||||||
// sorted by version inside those groups. This is enforced with tidy.
|
// sorted alphabetically inside those groups. This is enforced with tidy.
|
||||||
//
|
//
|
||||||
// N.B., `tools/tidy/src/features.rs` parses this information directly out of the
|
// N.B., `tools/tidy/src/features.rs` parses this information directly out of the
|
||||||
// source, so take care when modifying it.
|
// source, so take care when modifying it.
|
||||||
@ -512,6 +512,8 @@ declare_features! (
|
|||||||
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
|
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
|
||||||
/// Allow negative trait implementations.
|
/// Allow negative trait implementations.
|
||||||
(unstable, negative_impls, "1.44.0", Some(68318), None),
|
(unstable, negative_impls, "1.44.0", Some(68318), None),
|
||||||
|
/// Allows the `!` pattern.
|
||||||
|
(incomplete, never_patterns, "CURRENT_RUSTC_VERSION", Some(118155), None),
|
||||||
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
|
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
|
||||||
(unstable, never_type, "1.13.0", Some(35121), None),
|
(unstable, never_type, "1.13.0", Some(35121), None),
|
||||||
/// Allows diverging expressions to fall back to `!` rather than `()`.
|
/// Allows diverging expressions to fall back to `!` rather than `()`.
|
||||||
|
@ -1002,7 +1002,7 @@ impl<'hir> Pat<'hir> {
|
|||||||
|
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
|
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
|
||||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
|
||||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||||
@ -1029,7 +1029,7 @@ impl<'hir> Pat<'hir> {
|
|||||||
|
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
|
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {}
|
||||||
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
|
||||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||||
@ -1142,6 +1142,9 @@ pub enum PatKind<'hir> {
|
|||||||
/// Invariant: `pats.len() >= 2`.
|
/// Invariant: `pats.len() >= 2`.
|
||||||
Or(&'hir [Pat<'hir>]),
|
Or(&'hir [Pat<'hir>]),
|
||||||
|
|
||||||
|
/// A never pattern `!`.
|
||||||
|
Never,
|
||||||
|
|
||||||
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
||||||
Path(QPath<'hir>),
|
Path(QPath<'hir>),
|
||||||
|
|
||||||
|
@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
|
|||||||
walk_list!(visitor, visit_expr, lower_bound);
|
walk_list!(visitor, visit_expr, lower_bound);
|
||||||
walk_list!(visitor, visit_expr, upper_bound);
|
walk_list!(visitor, visit_expr, upper_bound);
|
||||||
}
|
}
|
||||||
PatKind::Wild => (),
|
PatKind::Never | PatKind::Wild => (),
|
||||||
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
||||||
walk_list!(visitor, visit_pat, prepatterns);
|
walk_list!(visitor, visit_pat, prepatterns);
|
||||||
walk_list!(visitor, visit_pat, slice_pattern);
|
walk_list!(visitor, visit_pat, slice_pattern);
|
||||||
|
@ -662,6 +662,7 @@ fn resolve_local<'tcx>(
|
|||||||
PatKind::Ref(_, _)
|
PatKind::Ref(_, _)
|
||||||
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
|
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Path(_)
|
| PatKind::Path(_)
|
||||||
| PatKind::Lit(_)
|
| PatKind::Lit(_)
|
||||||
| PatKind::Range(_, _, _) => false,
|
| PatKind::Range(_, _, _) => false,
|
||||||
|
@ -1724,6 +1724,7 @@ impl<'a> State<'a> {
|
|||||||
// is that it doesn't matter
|
// is that it doesn't matter
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
PatKind::Wild => self.word("_"),
|
PatKind::Wild => self.word("_"),
|
||||||
|
PatKind::Never => self.word("!"),
|
||||||
PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
|
PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
|
||||||
if by_ref == ByRef::Yes {
|
if by_ref == ByRef::Yes {
|
||||||
self.word_nbsp("ref");
|
self.word_nbsp("ref");
|
||||||
|
@ -401,12 +401,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||||||
mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
|
mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
PatKind::Binding(.., opt_sub_pat) => {
|
PatKind::Binding(.., opt_sub_pat) => {
|
||||||
// If the opt_sub_pat is None, than the binding does not count as
|
// If the opt_sub_pat is None, then the binding does not count as
|
||||||
// a wildcard for the purpose of borrowing discr.
|
// a wildcard for the purpose of borrowing discr.
|
||||||
if opt_sub_pat.is_none() {
|
if opt_sub_pat.is_none() {
|
||||||
needs_to_be_read = true;
|
needs_to_be_read = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatKind::Never => {
|
||||||
|
// A never pattern reads the value.
|
||||||
|
// FIXME(never_patterns): does this do what I expect?
|
||||||
|
needs_to_be_read = true;
|
||||||
|
}
|
||||||
PatKind::Path(qpath) => {
|
PatKind::Path(qpath) => {
|
||||||
// A `Path` pattern is just a name like `Foo`. This is either a
|
// A `Path` pattern is just a name like `Foo`. This is either a
|
||||||
// named constant or else it refers to an ADT variant
|
// named constant or else it refers to an ADT variant
|
||||||
|
@ -766,6 +766,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||||||
| PatKind::Binding(.., None)
|
| PatKind::Binding(.., None)
|
||||||
| PatKind::Lit(..)
|
| PatKind::Lit(..)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Wild => {
|
| PatKind::Wild => {
|
||||||
// always ok
|
// always ok
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let ty = match pat.kind {
|
let ty = match pat.kind {
|
||||||
PatKind::Wild => expected,
|
PatKind::Wild => expected,
|
||||||
|
// FIXME(never_patterns): check the type is uninhabited. If that is not possible within
|
||||||
|
// typeck, do that in a later phase.
|
||||||
|
PatKind::Never => expected,
|
||||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||||
PatKind::Binding(ba, var_id, _, sub) => {
|
PatKind::Binding(ba, var_id, _, sub) => {
|
||||||
@ -287,9 +290,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
| PatKind::Box(_)
|
| PatKind::Box(_)
|
||||||
| PatKind::Range(..)
|
| PatKind::Range(..)
|
||||||
| PatKind::Slice(..) => AdjustMode::Peel,
|
| PatKind::Slice(..) => AdjustMode::Peel,
|
||||||
|
// A never pattern behaves somewhat like a literal or unit variant.
|
||||||
|
PatKind::Never => AdjustMode::Peel,
|
||||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||||
// All other literals result in non-reference types.
|
// All other literals result in non-reference types.
|
||||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
|
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
||||||
//
|
//
|
||||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||||
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
|
PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
|
||||||
@ -743,6 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
| PatKind::Slice(..) => "binding",
|
| PatKind::Slice(..) => "binding",
|
||||||
|
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Binding(..)
|
| PatKind::Binding(..)
|
||||||
| PatKind::Path(..)
|
| PatKind::Path(..)
|
||||||
| PatKind::Box(..)
|
| PatKind::Box(..)
|
||||||
|
@ -1154,7 +1154,7 @@ impl EarlyLintPass for UnusedParens {
|
|||||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||||
Paren(_)
|
Paren(_)
|
||||||
// The other cases do not contain sub-patterns.
|
// The other cases do not contain sub-patterns.
|
||||||
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
| Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
|
||||||
// These are list-like patterns; parens can always be removed.
|
// These are list-like patterns; parens can always be removed.
|
||||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||||
|
@ -635,7 +635,12 @@ impl<'tcx> Pat<'tcx> {
|
|||||||
|
|
||||||
use PatKind::*;
|
use PatKind::*;
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
|
Wild
|
||||||
|
| Never
|
||||||
|
| Range(..)
|
||||||
|
| Binding { subpattern: None, .. }
|
||||||
|
| Constant { .. }
|
||||||
|
| Error(_) => {}
|
||||||
AscribeUserType { subpattern, .. }
|
AscribeUserType { subpattern, .. }
|
||||||
| Binding { subpattern: Some(subpattern), .. }
|
| Binding { subpattern: Some(subpattern), .. }
|
||||||
| Deref { subpattern }
|
| Deref { subpattern }
|
||||||
@ -809,6 +814,9 @@ pub enum PatKind<'tcx> {
|
|||||||
pats: Box<[Box<Pat<'tcx>>]>,
|
pats: Box<[Box<Pat<'tcx>>]>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A never pattern `!`.
|
||||||
|
Never,
|
||||||
|
|
||||||
/// An error has been encountered during lowering. We probably shouldn't report more lints
|
/// An error has been encountered during lowering. We probably shouldn't report more lints
|
||||||
/// related to this pattern.
|
/// related to this pattern.
|
||||||
Error(ErrorGuaranteed),
|
Error(ErrorGuaranteed),
|
||||||
@ -1069,6 +1077,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
PatKind::Wild => write!(f, "_"),
|
PatKind::Wild => write!(f, "_"),
|
||||||
|
PatKind::Never => write!(f, "!"),
|
||||||
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
|
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
|
||||||
PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
|
PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
|
||||||
let is_mut = match mode {
|
let is_mut = match mode {
|
||||||
|
@ -227,7 +227,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
|
|||||||
is_primary: _,
|
is_primary: _,
|
||||||
name: _,
|
name: _,
|
||||||
} => visitor.visit_pat(subpattern),
|
} => visitor.visit_pat(subpattern),
|
||||||
Binding { .. } | Wild | Error(_) => {}
|
Binding { .. } | Wild | Never | Error(_) => {}
|
||||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||||
for subpattern in subpatterns {
|
for subpattern in subpatterns {
|
||||||
visitor.visit_pat(&subpattern.pattern);
|
visitor.visit_pat(&subpattern.pattern);
|
||||||
|
@ -827,6 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
PatKind::Constant { .. }
|
PatKind::Constant { .. }
|
||||||
| PatKind::Range { .. }
|
| PatKind::Range { .. }
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Error(_) => {}
|
| PatKind::Error(_) => {}
|
||||||
|
|
||||||
PatKind::Deref { ref subpattern } => {
|
PatKind::Deref { ref subpattern } => {
|
||||||
|
@ -194,6 +194,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatKind::Never => {
|
||||||
|
// A never pattern acts like a load from the place.
|
||||||
|
// FIXME(never_patterns): load from the place
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
PatKind::Constant { .. } => {
|
PatKind::Constant { .. } => {
|
||||||
// FIXME normalize patterns when possible
|
// FIXME normalize patterns when possible
|
||||||
Err(match_pair)
|
Err(match_pair)
|
||||||
|
@ -75,6 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
| PatKind::Array { .. }
|
| PatKind::Array { .. }
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
| PatKind::Binding { .. }
|
| PatKind::Binding { .. }
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Leaf { .. }
|
| PatKind::Leaf { .. }
|
||||||
| PatKind::Deref { .. }
|
| PatKind::Deref { .. }
|
||||||
| PatKind::Error(_) => self.error_simplifiable(match_pair),
|
| PatKind::Error(_) => self.error_simplifiable(match_pair),
|
||||||
@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
PatKind::Slice { .. }
|
PatKind::Slice { .. }
|
||||||
| PatKind::Array { .. }
|
| PatKind::Array { .. }
|
||||||
| PatKind::Wild
|
| PatKind::Wild
|
||||||
|
| PatKind::Never
|
||||||
| PatKind::Or { .. }
|
| PatKind::Or { .. }
|
||||||
| PatKind::Binding { .. }
|
| PatKind::Binding { .. }
|
||||||
| PatKind::AscribeUserType { .. }
|
| PatKind::AscribeUserType { .. }
|
||||||
|
@ -247,8 +247,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||||||
self.requires_unsafe(pat.span, AccessToUnionField);
|
self.requires_unsafe(pat.span, AccessToUnionField);
|
||||||
return; // we can return here since this already requires unsafe
|
return; // we can return here since this already requires unsafe
|
||||||
}
|
}
|
||||||
// wildcard doesn't take anything
|
// wildcard/never don't take anything
|
||||||
PatKind::Wild |
|
PatKind::Wild |
|
||||||
|
PatKind::Never |
|
||||||
// these just wrap other patterns
|
// these just wrap other patterns
|
||||||
PatKind::Or { .. } |
|
PatKind::Or { .. } |
|
||||||
PatKind::InlineConstant { .. } |
|
PatKind::InlineConstant { .. } |
|
||||||
|
@ -1557,6 +1557,12 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
|||||||
let pats = expand_or_pat(pat);
|
let pats = expand_or_pat(pat);
|
||||||
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
|
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
|
||||||
}
|
}
|
||||||
|
PatKind::Never => {
|
||||||
|
// FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default
|
||||||
|
// in the meantime.
|
||||||
|
ctor = Wildcard;
|
||||||
|
fields = Fields::empty();
|
||||||
|
}
|
||||||
PatKind::Error(_) => {
|
PatKind::Error(_) => {
|
||||||
ctor = Opaque(OpaqueId::new());
|
ctor = Opaque(OpaqueId::new());
|
||||||
fields = Fields::empty();
|
fields = Fields::empty();
|
||||||
|
@ -251,6 +251,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
let kind = match pat.kind {
|
let kind = match pat.kind {
|
||||||
hir::PatKind::Wild => PatKind::Wild,
|
hir::PatKind::Wild => PatKind::Wild,
|
||||||
|
|
||||||
|
hir::PatKind::Never => PatKind::Never,
|
||||||
|
|
||||||
hir::PatKind::Lit(value) => self.lower_lit(value),
|
hir::PatKind::Lit(value) => self.lower_lit(value),
|
||||||
|
|
||||||
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||||
|
@ -636,6 +636,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||||||
PatKind::Wild => {
|
PatKind::Wild => {
|
||||||
print_indented!(self, "Wild", depth_lvl + 1);
|
print_indented!(self, "Wild", depth_lvl + 1);
|
||||||
}
|
}
|
||||||
|
PatKind::Never => {
|
||||||
|
print_indented!(self, "Never", depth_lvl + 1);
|
||||||
|
}
|
||||||
PatKind::AscribeUserType { ascription, subpattern } => {
|
PatKind::AscribeUserType { ascription, subpattern } => {
|
||||||
print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
|
print_indented!(self, "AscribeUserType: {", depth_lvl + 1);
|
||||||
print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
|
print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2);
|
||||||
|
@ -368,8 +368,12 @@ impl<'a> Parser<'a> {
|
|||||||
self.recover_dotdotdot_rest_pat(lo)
|
self.recover_dotdotdot_rest_pat(lo)
|
||||||
} else if let Some(form) = self.parse_range_end() {
|
} else if let Some(form) = self.parse_range_end() {
|
||||||
self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
|
self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
|
||||||
|
} else if self.eat(&token::Not) {
|
||||||
|
// Parse `!`
|
||||||
|
self.sess.gated_spans.gate(sym::never_patterns, self.prev_token.span);
|
||||||
|
PatKind::Never
|
||||||
} else if self.eat_keyword(kw::Underscore) {
|
} else if self.eat_keyword(kw::Underscore) {
|
||||||
// Parse _
|
// Parse `_`
|
||||||
PatKind::Wild
|
PatKind::Wild
|
||||||
} else if self.eat_keyword(kw::Mut) {
|
} else if self.eat_keyword(kw::Mut) {
|
||||||
self.parse_pat_ident_mut(syntax_loc)?
|
self.parse_pat_ident_mut(syntax_loc)?
|
||||||
|
@ -286,7 +286,21 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||||||
fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
|
fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
|
||||||
record_variants!(
|
record_variants!(
|
||||||
(self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind),
|
(self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind),
|
||||||
[Wild, Binding, Struct, TupleStruct, Or, Path, Tuple, Box, Ref, Lit, Range, Slice]
|
[
|
||||||
|
Wild,
|
||||||
|
Binding,
|
||||||
|
Struct,
|
||||||
|
TupleStruct,
|
||||||
|
Or,
|
||||||
|
Never,
|
||||||
|
Path,
|
||||||
|
Tuple,
|
||||||
|
Box,
|
||||||
|
Ref,
|
||||||
|
Lit,
|
||||||
|
Range,
|
||||||
|
Slice
|
||||||
|
]
|
||||||
);
|
);
|
||||||
hir_visit::walk_pat(self, p)
|
hir_visit::walk_pat(self, p)
|
||||||
}
|
}
|
||||||
@ -554,6 +568,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||||||
Range,
|
Range,
|
||||||
Slice,
|
Slice,
|
||||||
Rest,
|
Rest,
|
||||||
|
Never,
|
||||||
Paren,
|
Paren,
|
||||||
MacCall
|
MacCall
|
||||||
]
|
]
|
||||||
|
@ -1097,6 +1097,7 @@ symbols! {
|
|||||||
negative_impls,
|
negative_impls,
|
||||||
neon,
|
neon,
|
||||||
never,
|
never,
|
||||||
|
never_patterns,
|
||||||
never_type,
|
never_type,
|
||||||
never_type_fallback,
|
never_type_fallback,
|
||||||
new,
|
new,
|
||||||
|
@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
|||||||
debug!("trying to get a name from pattern: {p:?}");
|
debug!("trying to get a name from pattern: {p:?}");
|
||||||
|
|
||||||
Symbol::intern(&match p.kind {
|
Symbol::intern(&match p.kind {
|
||||||
PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
|
// FIXME(never_patterns): does this make sense?
|
||||||
|
PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore,
|
||||||
PatKind::Binding(_, _, ident, _) => return ident.name,
|
PatKind::Binding(_, _, ident, _) => return ident.name,
|
||||||
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
|
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
|
||||||
PatKind::Or(pats) => {
|
PatKind::Or(pats) => {
|
||||||
|
@ -46,7 +46,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
|||||||
pats.iter().all(unary_pattern)
|
pats.iter().all(unary_pattern)
|
||||||
}
|
}
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
|
PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => {
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
|
||||||
|
@ -150,6 +150,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum NormalizedPat<'a> {
|
enum NormalizedPat<'a> {
|
||||||
Wild,
|
Wild,
|
||||||
|
Never,
|
||||||
Struct(Option<DefId>, &'a [(Symbol, Self)]),
|
Struct(Option<DefId>, &'a [(Symbol, Self)]),
|
||||||
Tuple(Option<DefId>, &'a [Self]),
|
Tuple(Option<DefId>, &'a [Self]),
|
||||||
Or(&'a [Self]),
|
Or(&'a [Self]),
|
||||||
@ -229,6 +230,7 @@ impl<'a> NormalizedPat<'a> {
|
|||||||
PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
|
PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
|
||||||
Self::from_pat(cx, arena, pat)
|
Self::from_pat(cx, arena, pat)
|
||||||
},
|
},
|
||||||
|
PatKind::Never => Self::Never,
|
||||||
PatKind::Struct(ref path, fields, _) => {
|
PatKind::Struct(ref path, fields, _) => {
|
||||||
let fields =
|
let fields =
|
||||||
arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat))));
|
arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat))));
|
||||||
@ -333,6 +335,7 @@ impl<'a> NormalizedPat<'a> {
|
|||||||
fn has_overlapping_values(&self, other: &Self) -> bool {
|
fn has_overlapping_values(&self, other: &Self) -> bool {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
(Self::Wild, _) | (_, Self::Wild) => true,
|
(Self::Wild, _) | (_, Self::Wild) => true,
|
||||||
|
(Self::Never, Self::Never) => true,
|
||||||
(Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => {
|
(Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => {
|
||||||
pats.iter().any(|pat| pat.has_overlapping_values(other))
|
pats.iter().any(|pat| pat.has_overlapping_values(other))
|
||||||
},
|
},
|
||||||
|
@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
|||||||
// Therefore they are not some form of constructor `C`,
|
// Therefore they are not some form of constructor `C`,
|
||||||
// with which a pattern `C(p_0)` may be formed,
|
// with which a pattern `C(p_0)` may be formed,
|
||||||
// which we would want to join with other `C(p_j)`s.
|
// which we would want to join with other `C(p_j)`s.
|
||||||
Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
|
Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_)
|
||||||
// Skip immutable refs, as grouping them saves few characters,
|
// Skip immutable refs, as grouping them saves few characters,
|
||||||
// and almost always requires adding parens (increasing noisiness).
|
// and almost always requires adding parens (increasing noisiness).
|
||||||
// In the case of only two patterns, replacement adds net characters.
|
// In the case of only two patterns, replacement adds net characters.
|
||||||
|
@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
match pat.value.kind {
|
match pat.value.kind {
|
||||||
PatKind::Wild => kind!("Wild"),
|
PatKind::Wild => kind!("Wild"),
|
||||||
|
PatKind::Never => kind!("Never"),
|
||||||
PatKind::Binding(ann, _, name, sub) => {
|
PatKind::Binding(ann, _, name, sub) => {
|
||||||
bind!(self, name);
|
bind!(self, name);
|
||||||
opt_bind!(self, sub);
|
opt_bind!(self, sub);
|
||||||
|
@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
e.hash(&mut self.s);
|
e.hash(&mut self.s);
|
||||||
},
|
},
|
||||||
|
PatKind::Never => {},
|
||||||
PatKind::Wild => {},
|
PatKind::Wild => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1707,6 +1707,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
|||||||
|
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
PatKind::Wild => false,
|
PatKind::Wild => false,
|
||||||
|
PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
|
||||||
PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
|
PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
|
||||||
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
|
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
|
||||||
PatKind::Lit(..) | PatKind::Range(..) => true,
|
PatKind::Lit(..) | PatKind::Range(..) => true,
|
||||||
|
@ -40,7 +40,9 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
|
|||||||
|
|
||||||
fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
|
||||||
match pat.kind {
|
match pat.kind {
|
||||||
ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
|
ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => {
|
||||||
|
true
|
||||||
|
}
|
||||||
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
|
||||||
ast::PatKind::Struct(..)
|
ast::PatKind::Struct(..)
|
||||||
| ast::PatKind::MacCall(..)
|
| ast::PatKind::MacCall(..)
|
||||||
@ -193,6 +195,7 @@ impl Rewrite for Pat {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatKind::Never => None,
|
||||||
PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
|
PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
|
||||||
let infix = match end_kind.node {
|
let infix = match end_kind.node {
|
||||||
RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
|
RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
|
||||||
|
27
tests/ui/feature-gates/feature-gate-never_patterns.rs
Normal file
27
tests/ui/feature-gates/feature-gate-never_patterns.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Check that never patterns require the feature gate.
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
enum Void {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let res: Result<u32, Void> = Ok(0);
|
||||||
|
let (Ok(_x) | Err(&!)) = res.as_ref();
|
||||||
|
//~^ ERROR `!` patterns are experimental
|
||||||
|
//~| ERROR: is not bound in all patterns
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr: *const Void = NonNull::dangling().as_ptr();
|
||||||
|
match *ptr {
|
||||||
|
! => {} //~ ERROR `!` patterns are experimental
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the gate operates even behind `cfg`.
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
unsafe {
|
||||||
|
let ptr: *const Void = NonNull::dangling().as_ptr();
|
||||||
|
match *ptr {
|
||||||
|
! => {} //~ ERROR `!` patterns are experimental
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
tests/ui/feature-gates/feature-gate-never_patterns.stderr
Normal file
39
tests/ui/feature-gates/feature-gate-never_patterns.stderr
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
error[E0408]: variable `_x` is not bound in all patterns
|
||||||
|
--> $DIR/feature-gate-never_patterns.rs:8:19
|
||||||
|
|
|
||||||
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
|
||||||
|
| -- ^^^^^^^ pattern doesn't bind `_x`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0658]: `!` patterns are experimental
|
||||||
|
--> $DIR/feature-gate-never_patterns.rs:8:24
|
||||||
|
|
|
||||||
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
|
||||||
|
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: `!` patterns are experimental
|
||||||
|
--> $DIR/feature-gate-never_patterns.rs:15:13
|
||||||
|
|
|
||||||
|
LL | ! => {}
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
|
||||||
|
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: `!` patterns are experimental
|
||||||
|
--> $DIR/feature-gate-never_patterns.rs:24:13
|
||||||
|
|
|
||||||
|
LL | ! => {}
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
|
||||||
|
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0408, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0408`.
|
@ -11,6 +11,7 @@
|
|||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(explicit_tail_calls)]
|
#![feature(explicit_tail_calls)]
|
||||||
#![feature(more_qualified_paths)]
|
#![feature(more_qualified_paths)]
|
||||||
|
#![feature(never_patterns)]
|
||||||
#![feature(raw_ref_op)]
|
#![feature(raw_ref_op)]
|
||||||
#![feature(trait_alias)]
|
#![feature(trait_alias)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
@ -635,6 +636,10 @@ fn test_pat() {
|
|||||||
// PatKind::Rest
|
// PatKind::Rest
|
||||||
c1!(pat, [ .. ], "..");
|
c1!(pat, [ .. ], "..");
|
||||||
|
|
||||||
|
// PatKind::Never
|
||||||
|
c1!(pat, [ Some(!) ], "Some(!)");
|
||||||
|
c1!(pat, [ None | Some(!) ], "None | Some(!)");
|
||||||
|
|
||||||
// PatKind::Paren
|
// PatKind::Paren
|
||||||
c1!(pat, [ (pat) ], "(pat)");
|
c1!(pat, [ (pat) ], "(pat)");
|
||||||
|
|
||||||
|
99
tests/ui/pattern/never_patterns.rs
Normal file
99
tests/ui/pattern/never_patterns.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#![feature(never_patterns)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
enum Void {}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// The classic use for empty types.
|
||||||
|
fn safe_unwrap_result<T>(res: Result<T, Void>) {
|
||||||
|
let Ok(_x) = res;
|
||||||
|
// FIXME(never_patterns): These should be allowed
|
||||||
|
let (Ok(_x) | Err(!)) = &res;
|
||||||
|
//~^ ERROR: is not bound in all patterns
|
||||||
|
let (Ok(_x) | Err(&!)) = res.as_ref();
|
||||||
|
//~^ ERROR: is not bound in all patterns
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we only accept `!` where we want to.
|
||||||
|
fn never_pattern_location(void: Void) {
|
||||||
|
// FIXME(never_patterns): Don't accept on a non-empty type.
|
||||||
|
match Some(0) {
|
||||||
|
None => {}
|
||||||
|
Some(!) => {}
|
||||||
|
}
|
||||||
|
// FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches.
|
||||||
|
match () {
|
||||||
|
() => {}
|
||||||
|
! => {}
|
||||||
|
}
|
||||||
|
// FIXME(never_patterns): Don't accept even on an empty branch.
|
||||||
|
match None::<Void> {
|
||||||
|
None => {}
|
||||||
|
! => {}
|
||||||
|
}
|
||||||
|
// FIXME(never_patterns): Let alone if the emptiness is behind a reference.
|
||||||
|
match None::<&Void> {
|
||||||
|
None => {}
|
||||||
|
! => {}
|
||||||
|
}
|
||||||
|
// Participate in match ergonomics.
|
||||||
|
match &void {
|
||||||
|
! => {}
|
||||||
|
}
|
||||||
|
match &&void {
|
||||||
|
! => {}
|
||||||
|
}
|
||||||
|
match &&void {
|
||||||
|
&! => {}
|
||||||
|
}
|
||||||
|
match &None::<Void> {
|
||||||
|
None => {}
|
||||||
|
Some(!) => {}
|
||||||
|
}
|
||||||
|
match None::<&Void> {
|
||||||
|
None => {}
|
||||||
|
Some(!) => {}
|
||||||
|
}
|
||||||
|
// Accept on a composite empty type.
|
||||||
|
match None::<&(u32, Void)> {
|
||||||
|
None => {}
|
||||||
|
Some(&!) => {}
|
||||||
|
}
|
||||||
|
// Accept on an simple empty type.
|
||||||
|
match None::<Void> {
|
||||||
|
None => {}
|
||||||
|
Some(!) => {}
|
||||||
|
}
|
||||||
|
match None::<&Void> {
|
||||||
|
None => {}
|
||||||
|
Some(&!) => {}
|
||||||
|
}
|
||||||
|
match None::<&(u32, Void)> {
|
||||||
|
None => {}
|
||||||
|
Some(&(_, !)) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn never_and_bindings() {
|
||||||
|
let x: Result<bool, &(u32, Void)> = Ok(false);
|
||||||
|
|
||||||
|
// FIXME(never_patterns): Never patterns in or-patterns don't need to share the same bindings.
|
||||||
|
match x {
|
||||||
|
Ok(_x) | Err(&!) => {}
|
||||||
|
//~^ ERROR: is not bound in all patterns
|
||||||
|
}
|
||||||
|
let (Ok(_x) | Err(&!)) = x;
|
||||||
|
//~^ ERROR: is not bound in all patterns
|
||||||
|
|
||||||
|
// FIXME(never_patterns): A never pattern mustn't have bindings.
|
||||||
|
match x {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(&(_b, !)) => {}
|
||||||
|
}
|
||||||
|
match x {
|
||||||
|
Ok(_a) | Err(&(_b, !)) => {}
|
||||||
|
//~^ ERROR: is not bound in all patterns
|
||||||
|
//~| ERROR: is not bound in all patterns
|
||||||
|
}
|
||||||
|
}
|
51
tests/ui/pattern/never_patterns.stderr
Normal file
51
tests/ui/pattern/never_patterns.stderr
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
error[E0408]: variable `_x` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:12:19
|
||||||
|
|
|
||||||
|
LL | let (Ok(_x) | Err(!)) = &res;
|
||||||
|
| -- ^^^^^^ pattern doesn't bind `_x`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0408]: variable `_x` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:14:19
|
||||||
|
|
|
||||||
|
LL | let (Ok(_x) | Err(&!)) = res.as_ref();
|
||||||
|
| -- ^^^^^^^ pattern doesn't bind `_x`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0408]: variable `_x` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:83:18
|
||||||
|
|
|
||||||
|
LL | Ok(_x) | Err(&!) => {}
|
||||||
|
| -- ^^^^^^^ pattern doesn't bind `_x`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0408]: variable `_x` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:86:19
|
||||||
|
|
|
||||||
|
LL | let (Ok(_x) | Err(&!)) = x;
|
||||||
|
| -- ^^^^^^^ pattern doesn't bind `_x`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error[E0408]: variable `_b` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:95:9
|
||||||
|
|
|
||||||
|
LL | Ok(_a) | Err(&(_b, !)) => {}
|
||||||
|
| ^^^^^^ -- variable not in all patterns
|
||||||
|
| |
|
||||||
|
| pattern doesn't bind `_b`
|
||||||
|
|
||||||
|
error[E0408]: variable `_a` is not bound in all patterns
|
||||||
|
--> $DIR/never_patterns.rs:95:18
|
||||||
|
|
|
||||||
|
LL | Ok(_a) | Err(&(_b, !)) => {}
|
||||||
|
| -- ^^^^^^^^^^^^^ pattern doesn't bind `_a`
|
||||||
|
| |
|
||||||
|
| variable not in all patterns
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0408`.
|
Loading…
x
Reference in New Issue
Block a user