Rollup merge of #48500 - petrochenkov:parpat, r=nikomatsakis
Support parentheses in patterns under feature gate This is a prerequisite for any other extensions to pattern syntax - `|` with multiple patterns, type ascription, `..PAT` in slice patterns. Closes https://github.com/rust-lang/rfcs/issues/554
This commit is contained in:
commit
38f4d557d0
@ -2472,86 +2472,88 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
|
||||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
|
let node = match p.node {
|
||||||
|
PatKind::Wild => hir::PatKind::Wild,
|
||||||
|
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
||||||
|
match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
|
||||||
|
// `None` can occur in body-less function signatures
|
||||||
|
def @ None | def @ Some(Def::Local(_)) => {
|
||||||
|
let canonical_id = match def {
|
||||||
|
Some(Def::Local(id)) => id,
|
||||||
|
_ => p.id
|
||||||
|
};
|
||||||
|
hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
|
||||||
|
canonical_id,
|
||||||
|
respan(pth1.span, pth1.node.name),
|
||||||
|
sub.as_ref().map(|x| self.lower_pat(x)))
|
||||||
|
}
|
||||||
|
Some(def) => {
|
||||||
|
hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
|
||||||
|
span: pth1.span,
|
||||||
|
def,
|
||||||
|
segments: hir_vec![
|
||||||
|
hir::PathSegment::from_name(pth1.node.name)
|
||||||
|
],
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
|
||||||
|
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
|
||||||
|
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||||
|
ImplTraitContext::Disallowed);
|
||||||
|
hir::PatKind::TupleStruct(qpath,
|
||||||
|
pats.iter().map(|x| self.lower_pat(x)).collect(),
|
||||||
|
ddpos)
|
||||||
|
}
|
||||||
|
PatKind::Path(ref qself, ref path) => {
|
||||||
|
hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
|
||||||
|
ImplTraitContext::Disallowed))
|
||||||
|
}
|
||||||
|
PatKind::Struct(ref path, ref fields, etc) => {
|
||||||
|
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
||||||
|
ImplTraitContext::Disallowed);
|
||||||
|
|
||||||
|
let fs = fields.iter()
|
||||||
|
.map(|f| {
|
||||||
|
Spanned {
|
||||||
|
span: f.span,
|
||||||
|
node: hir::FieldPat {
|
||||||
|
name: self.lower_ident(f.node.ident),
|
||||||
|
pat: self.lower_pat(&f.node.pat),
|
||||||
|
is_shorthand: f.node.is_shorthand,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
hir::PatKind::Struct(qpath, fs, etc)
|
||||||
|
}
|
||||||
|
PatKind::Tuple(ref elts, ddpos) => {
|
||||||
|
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
|
||||||
|
}
|
||||||
|
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
||||||
|
PatKind::Ref(ref inner, mutbl) => {
|
||||||
|
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
|
||||||
|
}
|
||||||
|
PatKind::Range(ref e1, ref e2, ref end) => {
|
||||||
|
hir::PatKind::Range(P(self.lower_expr(e1)),
|
||||||
|
P(self.lower_expr(e2)),
|
||||||
|
self.lower_range_end(end))
|
||||||
|
}
|
||||||
|
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||||
|
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
|
||||||
|
slice.as_ref().map(|x| self.lower_pat(x)),
|
||||||
|
after.iter().map(|x| self.lower_pat(x)).collect())
|
||||||
|
}
|
||||||
|
PatKind::Paren(ref inner) => return self.lower_pat(inner),
|
||||||
|
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
|
||||||
P(hir::Pat {
|
P(hir::Pat {
|
||||||
id: node_id,
|
id: node_id,
|
||||||
hir_id,
|
hir_id,
|
||||||
node: match p.node {
|
node,
|
||||||
PatKind::Wild => hir::PatKind::Wild,
|
|
||||||
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
|
||||||
match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
|
|
||||||
// `None` can occur in body-less function signatures
|
|
||||||
def @ None | def @ Some(Def::Local(_)) => {
|
|
||||||
let canonical_id = match def {
|
|
||||||
Some(Def::Local(id)) => id,
|
|
||||||
_ => p.id
|
|
||||||
};
|
|
||||||
hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
|
|
||||||
canonical_id,
|
|
||||||
respan(pth1.span, pth1.node.name),
|
|
||||||
sub.as_ref().map(|x| self.lower_pat(x)))
|
|
||||||
}
|
|
||||||
Some(def) => {
|
|
||||||
hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
|
|
||||||
span: pth1.span,
|
|
||||||
def,
|
|
||||||
segments: hir_vec![
|
|
||||||
hir::PathSegment::from_name(pth1.node.name)
|
|
||||||
],
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
|
|
||||||
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
|
|
||||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
|
||||||
ImplTraitContext::Disallowed);
|
|
||||||
hir::PatKind::TupleStruct(qpath,
|
|
||||||
pats.iter().map(|x| self.lower_pat(x)).collect(),
|
|
||||||
ddpos)
|
|
||||||
}
|
|
||||||
PatKind::Path(ref qself, ref path) => {
|
|
||||||
hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
|
|
||||||
ImplTraitContext::Disallowed))
|
|
||||||
}
|
|
||||||
PatKind::Struct(ref path, ref fields, etc) => {
|
|
||||||
let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
|
|
||||||
ImplTraitContext::Disallowed);
|
|
||||||
|
|
||||||
let fs = fields.iter()
|
|
||||||
.map(|f| {
|
|
||||||
Spanned {
|
|
||||||
span: f.span,
|
|
||||||
node: hir::FieldPat {
|
|
||||||
name: self.lower_ident(f.node.ident),
|
|
||||||
pat: self.lower_pat(&f.node.pat),
|
|
||||||
is_shorthand: f.node.is_shorthand,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
hir::PatKind::Struct(qpath, fs, etc)
|
|
||||||
}
|
|
||||||
PatKind::Tuple(ref elts, ddpos) => {
|
|
||||||
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
|
|
||||||
}
|
|
||||||
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
|
|
||||||
PatKind::Ref(ref inner, mutbl) => {
|
|
||||||
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
|
|
||||||
}
|
|
||||||
PatKind::Range(ref e1, ref e2, ref end) => {
|
|
||||||
hir::PatKind::Range(P(self.lower_expr(e1)),
|
|
||||||
P(self.lower_expr(e2)),
|
|
||||||
self.lower_range_end(end))
|
|
||||||
}
|
|
||||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
|
||||||
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
|
|
||||||
slice.as_ref().map(|x| self.lower_pat(x)),
|
|
||||||
after.iter().map(|x| self.lower_pat(x)).collect())
|
|
||||||
}
|
|
||||||
PatKind::Mac(_) => panic!("Shouldn't exist here"),
|
|
||||||
},
|
|
||||||
span: p.span,
|
span: p.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -737,6 +737,7 @@ impl EarlyLintPass for IllegalFloatLiteralPattern {
|
|||||||
PatKind::TupleStruct(..) |
|
PatKind::TupleStruct(..) |
|
||||||
PatKind::Ref(..) |
|
PatKind::Ref(..) |
|
||||||
PatKind::Box(..) |
|
PatKind::Box(..) |
|
||||||
|
PatKind::Paren(..) |
|
||||||
PatKind::Slice(..) => (),
|
PatKind::Slice(..) => (),
|
||||||
|
|
||||||
// Extract the expressions and check them
|
// Extract the expressions and check them
|
||||||
|
@ -562,7 +562,7 @@ impl Pat {
|
|||||||
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
|
||||||
s.iter().all(|p| p.walk(it))
|
s.iter().all(|p| p.walk(it))
|
||||||
}
|
}
|
||||||
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
|
PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => {
|
||||||
s.walk(it)
|
s.walk(it)
|
||||||
}
|
}
|
||||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||||
@ -656,6 +656,8 @@ pub enum PatKind {
|
|||||||
/// `[a, b, ..i, y, z]` is represented as:
|
/// `[a, b, ..i, y, z]` is represented as:
|
||||||
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
|
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
|
||||||
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
|
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
|
||||||
|
/// Parentheses in patters used for grouping, i.e. `(PAT)`.
|
||||||
|
Paren(P<Pat>),
|
||||||
/// A macro pattern; pre-expansion
|
/// A macro pattern; pre-expansion
|
||||||
Mac(Mac),
|
Mac(Mac),
|
||||||
}
|
}
|
||||||
|
@ -449,6 +449,9 @@ declare_features! (
|
|||||||
|
|
||||||
// Multiple patterns with `|` in `if let` and `while let`
|
// Multiple patterns with `|` in `if let` and `while let`
|
||||||
(active, if_while_or_patterns, "1.26.0", Some(48215)),
|
(active, if_while_or_patterns, "1.26.0", Some(48215)),
|
||||||
|
|
||||||
|
// Parentheses in patterns
|
||||||
|
(active, pattern_parentheses, "1.26.0", None),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
@ -1663,6 +1666,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||||||
gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
|
gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
|
||||||
"`..=` syntax in patterns is experimental");
|
"`..=` syntax in patterns is experimental");
|
||||||
}
|
}
|
||||||
|
PatKind::Paren(..) => {
|
||||||
|
gate_feature_post!(&self, pattern_parentheses, pattern.span,
|
||||||
|
"parentheses in patterns are unstable");
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_pat(self, pattern)
|
visit::walk_pat(self, pattern)
|
||||||
|
@ -1148,6 +1148,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
|||||||
slice.map(|x| folder.fold_pat(x)),
|
slice.map(|x| folder.fold_pat(x)),
|
||||||
after.move_map(|x| folder.fold_pat(x)))
|
after.move_map(|x| folder.fold_pat(x)))
|
||||||
}
|
}
|
||||||
|
PatKind::Paren(inner) => PatKind::Paren(folder.fold_pat(inner)),
|
||||||
PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac))
|
PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac))
|
||||||
},
|
},
|
||||||
span: folder.new_span(span)
|
span: folder.new_span(span)
|
||||||
|
@ -3484,33 +3484,47 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
|
// Parses a parenthesized list of patterns like
|
||||||
-> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
|
// `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
|
||||||
let mut fields = vec![];
|
// - a vector of the patterns that were parsed
|
||||||
let mut ddpos = None;
|
// - an option indicating the index of the `..` element
|
||||||
|
// - a boolean indicating whether a trailing comma was present.
|
||||||
|
// Trailing commas are significant because (p) and (p,) are different patterns.
|
||||||
|
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
|
||||||
|
self.expect(&token::OpenDelim(token::Paren))?;
|
||||||
|
|
||||||
while !self.check(&token::CloseDelim(token::Paren)) {
|
let mut fields = Vec::new();
|
||||||
if ddpos.is_none() && self.eat(&token::DotDot) {
|
let mut ddpos = None;
|
||||||
ddpos = Some(fields.len());
|
let mut trailing_comma = false;
|
||||||
if self.eat(&token::Comma) {
|
loop {
|
||||||
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
|
if self.eat(&token::DotDot) {
|
||||||
fields.push(self.parse_pat()?);
|
if ddpos.is_none() {
|
||||||
|
ddpos = Some(fields.len());
|
||||||
|
} else {
|
||||||
|
// Emit a friendly error, ignore `..` and continue parsing
|
||||||
|
self.span_err(self.prev_span,
|
||||||
|
"`..` can only be used once per tuple or tuple struct pattern");
|
||||||
}
|
}
|
||||||
} else if ddpos.is_some() && self.eat(&token::DotDot) {
|
} else if !self.check(&token::CloseDelim(token::Paren)) {
|
||||||
// Emit a friendly error, ignore `..` and continue parsing
|
|
||||||
self.span_err(self.prev_span, "`..` can only be used once per \
|
|
||||||
tuple or tuple struct pattern");
|
|
||||||
} else {
|
|
||||||
fields.push(self.parse_pat()?);
|
fields.push(self.parse_pat()?);
|
||||||
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.check(&token::CloseDelim(token::Paren)) ||
|
trailing_comma = self.eat(&token::Comma);
|
||||||
(unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
|
if !trailing_comma {
|
||||||
self.expect(&token::Comma)?;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((fields, ddpos))
|
if ddpos == Some(fields.len()) && trailing_comma {
|
||||||
|
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
|
||||||
|
self.span_err(self.prev_span, "trailing comma is not permitted after `..`");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.expect(&token::CloseDelim(token::Paren))?;
|
||||||
|
|
||||||
|
Ok((fields, ddpos, trailing_comma))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_vec_elements(
|
fn parse_pat_vec_elements(
|
||||||
@ -3714,10 +3728,12 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
token::OpenDelim(token::Paren) => {
|
token::OpenDelim(token::Paren) => {
|
||||||
// Parse (pat,pat,pat,...) as tuple pattern
|
// Parse (pat,pat,pat,...) as tuple pattern
|
||||||
self.bump();
|
let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
|
||||||
let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
|
pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
PatKind::Paren(fields.into_iter().nth(0).unwrap())
|
||||||
pat = PatKind::Tuple(fields, ddpos);
|
} else {
|
||||||
|
PatKind::Tuple(fields, ddpos)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Bracket) => {
|
token::OpenDelim(token::Bracket) => {
|
||||||
// Parse [pat,pat,...] as slice pattern
|
// Parse [pat,pat,...] as slice pattern
|
||||||
@ -3807,9 +3823,7 @@ impl<'a> Parser<'a> {
|
|||||||
return Err(self.fatal("unexpected `(` after qualified path"));
|
return Err(self.fatal("unexpected `(` after qualified path"));
|
||||||
}
|
}
|
||||||
// Parse tuple struct or enum pattern
|
// Parse tuple struct or enum pattern
|
||||||
self.bump();
|
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
|
||||||
let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
|
|
||||||
self.expect(&token::CloseDelim(token::Paren))?;
|
|
||||||
pat = PatKind::TupleStruct(path, fields, ddpos)
|
pat = PatKind::TupleStruct(path, fields, ddpos)
|
||||||
}
|
}
|
||||||
_ => pat = PatKind::Path(qself, path),
|
_ => pat = PatKind::Path(qself, path),
|
||||||
|
@ -2659,6 +2659,11 @@ impl<'a> State<'a> {
|
|||||||
|s, p| s.print_pat(p))?;
|
|s, p| s.print_pat(p))?;
|
||||||
self.s.word("]")?;
|
self.s.word("]")?;
|
||||||
}
|
}
|
||||||
|
PatKind::Paren(ref inner) => {
|
||||||
|
self.popen()?;
|
||||||
|
self.print_pat(inner)?;
|
||||||
|
self.pclose()?;
|
||||||
|
}
|
||||||
PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
|
PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
|
||||||
}
|
}
|
||||||
self.ann.post(self, NodePat(pat))
|
self.ann.post(self, NodePat(pat))
|
||||||
|
@ -425,7 +425,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
|
|||||||
walk_list!(visitor, visit_pat, tuple_elements);
|
walk_list!(visitor, visit_pat, tuple_elements);
|
||||||
}
|
}
|
||||||
PatKind::Box(ref subpattern) |
|
PatKind::Box(ref subpattern) |
|
||||||
PatKind::Ref(ref subpattern, _) => {
|
PatKind::Ref(ref subpattern, _) |
|
||||||
|
PatKind::Paren(ref subpattern) => {
|
||||||
visitor.visit_pat(subpattern)
|
visitor.visit_pat(subpattern)
|
||||||
}
|
}
|
||||||
PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
|
PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
|
||||||
|
@ -12,6 +12,6 @@
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 0 {
|
match 0 {
|
||||||
(pat, ..,) => {} //~ ERROR expected pattern, found `)`
|
(pat, ..,) => {} //~ ERROR trailing comma is not permitted after `..`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
#![feature(pattern_parentheses)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match 0 {
|
match 0 {
|
||||||
(pat) => {} //~ ERROR expected one of `,` or `@`, found `)`
|
(pat) => assert_eq!(pat, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
15
src/test/ui/feature-gate-pattern_parentheses.rs
Normal file
15
src/test/ui/feature-gate-pattern_parentheses.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
(pat) => {} //~ ERROR parentheses in patterns are unstable
|
||||||
|
}
|
||||||
|
}
|
11
src/test/ui/feature-gate-pattern_parentheses.stderr
Normal file
11
src/test/ui/feature-gate-pattern_parentheses.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0658]: parentheses in patterns are unstable
|
||||||
|
--> $DIR/feature-gate-pattern_parentheses.rs:13:9
|
||||||
|
|
|
||||||
|
LL | (pat) => {} //~ ERROR parentheses in patterns are unstable
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(pattern_parentheses)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
If you want more information on this error, try using "rustc --explain E0658"
|
Loading…
x
Reference in New Issue
Block a user