Rollup merge of #62550 - Centril:rest-patterns, r=petrochenkov

Implement RFC 2707 + Parser recovery for range patterns

Implement https://github.com/rust-lang/rfcs/pull/2707.

- Add a new basic syntactic pattern form `ast::PatKind::Rest` (parsed as `..` or `DOTDOT`) and simplify `ast::PatKind::{Slice, Tuple, TupleStruct}` as a result.

- Lower `ast::PatKind::Rest` in combination with the aforementioned `PatKind` variants as well as `PatKind::Ident`. The HIR remains unchanged for now (may be advisable to make slight adjustments later).

- Refactor `parser.rs` wrt. parsing sequences and lists of things in the process.

- Add parser recovery for range patterns of form `X..`, `X..=`, `X...`, `..Y`, `..=Y`, and `...Y`.
   This should make it easy to actually support these patterns semantically later if we so desire.

cc https://github.com/rust-lang/rust/issues/62254

r? @petrochenkov
This commit is contained in:
Mazdak Farrokhzad 2019-07-28 11:11:04 +02:00 committed by GitHub
commit 75e23ff411
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 1547 additions and 676 deletions

View File

@ -17,7 +17,7 @@ matched against that pattern. For example:
fn is_symmetric(list: &[u32]) -> bool { fn is_symmetric(list: &[u32]) -> bool {
match list { match list {
&[] | &[_] => true, &[] | &[_] => true,
&[x, ref inside.., y] if x == y => is_symmetric(inside), &[x, ref inside @ .., y] if x == y => is_symmetric(inside),
&[..] => false, &[..] => false,
} }
} }

View File

@ -58,6 +58,7 @@ use std::mem;
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax::attr; use syntax::attr;
use syntax::ast; use syntax::ast;
use syntax::ptr::P as AstP;
use syntax::ast::*; use syntax::ast::*;
use syntax::errors; use syntax::errors;
use syntax::ext::hygiene::ExpnId; use syntax::ext::hygiene::ExpnId;
@ -467,7 +468,7 @@ impl<'a> LoweringContext<'a> {
fn visit_pat(&mut self, p: &'tcx Pat) { fn visit_pat(&mut self, p: &'tcx Pat) {
match p.node { match p.node {
// Doesn't generate a HIR node // Doesn't generate a HIR node
PatKind::Paren(..) => {}, PatKind::Paren(..) | PatKind::Rest => {},
_ => { _ => {
if let Some(owner) = self.hir_id_owner { if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner); self.lctx.lower_node_id_with_owner(p.id, owner);
@ -1156,7 +1157,7 @@ impl<'a> LoweringContext<'a> {
&mut self, &mut self,
capture_clause: CaptureBy, capture_clause: CaptureBy,
closure_node_id: NodeId, closure_node_id: NodeId,
ret_ty: Option<syntax::ptr::P<Ty>>, ret_ty: Option<AstP<Ty>>,
span: Span, span: Span,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
) -> hir::ExprKind { ) -> hir::ExprKind {
@ -4171,33 +4172,11 @@ impl<'a> LoweringContext<'a> {
let node = match p.node { let node = match p.node {
PatKind::Wild => hir::PatKind::Wild, PatKind::Wild => hir::PatKind::Wild,
PatKind::Ident(ref binding_mode, ident, ref sub) => { PatKind::Ident(ref binding_mode, ident, ref sub) => {
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x));
// `None` can occur in body-less function signatures self.lower_pat_ident(p, binding_mode, ident, lower_sub)
res @ None | res @ Some(Res::Local(_)) => {
let canonical_id = match res {
Some(Res::Local(id)) => id,
_ => p.id,
};
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
self.lower_node_id(canonical_id),
ident,
sub.as_ref().map(|x| self.lower_pat(x)),
)
}
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
span: ident.span,
res: self.lower_res(res),
segments: hir_vec![hir::PathSegment::from_ident(ident)],
}),
)),
}
} }
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))), PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
PatKind::TupleStruct(ref path, ref pats, ddpos) => { PatKind::TupleStruct(ref path, ref pats) => {
let qpath = self.lower_qpath( let qpath = self.lower_qpath(
p.id, p.id,
&None, &None,
@ -4205,11 +4184,8 @@ impl<'a> LoweringContext<'a> {
ParamMode::Optional, ParamMode::Optional,
ImplTraitContext::disallowed(), ImplTraitContext::disallowed(),
); );
hir::PatKind::TupleStruct( let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
qpath, hir::PatKind::TupleStruct(qpath, pats, ddpos)
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos,
)
} }
PatKind::Path(ref qself, ref path) => { PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath( let qpath = self.lower_qpath(
@ -4246,8 +4222,9 @@ impl<'a> LoweringContext<'a> {
.collect(); .collect();
hir::PatKind::Struct(qpath, fs, etc) hir::PatKind::Struct(qpath, fs, etc)
} }
PatKind::Tuple(ref elts, ddpos) => { PatKind::Tuple(ref pats) => {
hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos) let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
hir::PatKind::Tuple(pats, ddpos)
} }
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
PatKind::Ref(ref inner, mutbl) => { PatKind::Ref(ref inner, mutbl) => {
@ -4258,15 +4235,138 @@ impl<'a> LoweringContext<'a> {
P(self.lower_expr(e2)), P(self.lower_expr(e2)),
self.lower_range_end(end), self.lower_range_end(end),
), ),
PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice( PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
before.iter().map(|x| self.lower_pat(x)).collect(), PatKind::Rest => {
slice.as_ref().map(|x| self.lower_pat(x)), // If we reach here the `..` pattern is not semantically allowed.
after.iter().map(|x| self.lower_pat(x)).collect(), self.ban_illegal_rest_pat(p.span)
), }
PatKind::Paren(ref inner) => return self.lower_pat(inner), PatKind::Paren(ref inner) => return self.lower_pat(inner),
PatKind::Mac(_) => panic!("Shouldn't exist here"), PatKind::Mac(_) => panic!("Shouldn't exist here"),
}; };
self.pat_with_node_id_of(p, node)
}
fn lower_pat_tuple(
&mut self,
pats: &[AstP<Pat>],
ctx: &str,
) -> (HirVec<P<hir::Pat>>, Option<usize>) {
let mut elems = Vec::with_capacity(pats.len());
let mut rest = None;
let mut iter = pats.iter().enumerate();
while let Some((idx, pat)) = iter.next() {
// Interpret the first `..` pattern as a subtuple pattern.
if pat.is_rest() {
rest = Some((idx, pat.span));
break;
}
// It was not a subslice pattern so lower it normally.
elems.push(self.lower_pat(pat));
}
while let Some((_, pat)) = iter.next() {
// There was a previous subtuple pattern; make sure we don't allow more.
if pat.is_rest() {
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
} else {
elems.push(self.lower_pat(pat));
}
}
(elems.into(), rest.map(|(ddpos, _)| ddpos))
}
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
let mut before = Vec::new();
let mut after = Vec::new();
let mut slice = None;
let mut prev_rest_span = None;
let mut iter = pats.iter();
while let Some(pat) = iter.next() {
// Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
match pat.node {
PatKind::Rest => {
prev_rest_span = Some(pat.span);
slice = Some(self.pat_wild_with_node_id_of(pat));
break;
},
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
prev_rest_span = Some(sub.span);
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
slice = Some(self.pat_with_node_id_of(pat, node));
break;
},
_ => {}
}
// It was not a subslice pattern so lower it normally.
before.push(self.lower_pat(pat));
}
while let Some(pat) = iter.next() {
// There was a previous subslice pattern; make sure we don't allow more.
let rest_span = match pat.node {
PatKind::Rest => Some(pat.span),
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
after.push(self.pat_wild_with_node_id_of(pat));
Some(sub.span)
},
_ => None,
};
if let Some(rest_span) = rest_span {
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
} else {
after.push(self.lower_pat(pat));
}
}
hir::PatKind::Slice(before.into(), slice, after.into())
}
fn lower_pat_ident(
&mut self,
p: &Pat,
binding_mode: &BindingMode,
ident: Ident,
lower_sub: impl FnOnce(&mut Self) -> Option<P<hir::Pat>>,
) -> hir::PatKind {
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
// `None` can occur in body-less function signatures
res @ None | res @ Some(Res::Local(_)) => {
let canonical_id = match res {
Some(Res::Local(id)) => id,
_ => p.id,
};
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
self.lower_node_id(canonical_id),
ident,
lower_sub(self),
)
}
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
None,
P(hir::Path {
span: ident.span,
res: self.lower_res(res),
segments: hir_vec![hir::PathSegment::from_ident(ident)],
}),
)),
}
}
fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> P<hir::Pat> {
self.pat_with_node_id_of(p, hir::PatKind::Wild)
}
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
fn pat_with_node_id_of(&mut self, p: &Pat, node: hir::PatKind) -> P<hir::Pat> {
P(hir::Pat { P(hir::Pat {
hir_id: self.lower_node_id(p.id), hir_id: self.lower_node_id(p.id),
node, node,
@ -4274,6 +4374,28 @@ impl<'a> LoweringContext<'a> {
}) })
} }
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
self.diagnostic()
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
.span_label(prev_sp, "previously used here")
.emit();
}
/// Used to ban the `..` pattern in places it shouldn't be semantically.
fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind {
self.diagnostic()
.struct_span_err(sp, "`..` patterns are not allowed here")
.note("only allowed in tuple, tuple struct, and slice patterns")
.emit();
// We're not in a list context so `..` can be reasonably treated
// as `_` because it should always be valid and roughly matches the
// intent of `..` (notice that the rest of a single slot is that slot).
hir::PatKind::Wild
}
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd { fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
match *e { match *e {
RangeEnd::Included(_) => hir::RangeEnd::Included, RangeEnd::Included(_) => hir::RangeEnd::Included,

View File

@ -162,7 +162,7 @@ pub enum PatternKind<'tcx> {
/// Matches against a slice, checking the length and extracting elements. /// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
/// e.g., `&[ref xs..]`. /// e.g., `&[ref xs @ ..]`.
Slice { Slice {
prefix: Vec<Pattern<'tcx>>, prefix: Vec<Pattern<'tcx>>,
slice: Option<Pattern<'tcx>>, slice: Option<Pattern<'tcx>>,

View File

@ -287,7 +287,7 @@ impl<'a> AstValidator<'a> {
// ``` // ```
fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
match expr.node { match expr.node {
ExprKind::Lit(..) => {} ExprKind::Lit(..) | ExprKind::Err => {}
ExprKind::Path(..) if allow_paths => {} ExprKind::Path(..) if allow_paths => {}
ExprKind::Unary(UnOp::Neg, ref inner) ExprKind::Unary(UnOp::Neg, ref inner)
if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}

View File

@ -105,20 +105,34 @@ impl TargetDataLayout {
let mut dl = TargetDataLayout::default(); let mut dl = TargetDataLayout::default();
let mut i128_align_src = 64; let mut i128_align_src = 64;
for spec in target.data_layout.split('-') { for spec in target.data_layout.split('-') {
match spec.split(':').collect::<Vec<_>>()[..] { let spec_parts = spec.split(':').collect::<Vec<_>>();
match &*spec_parts {
["e"] => dl.endian = Endian::Little, ["e"] => dl.endian = Endian::Little,
["E"] => dl.endian = Endian::Big, ["E"] => dl.endian = Endian::Big,
[p] if p.starts_with("P") => { [p] if p.starts_with("P") => {
dl.instruction_address_space = parse_address_space(&p[1..], "P")? dl.instruction_address_space = parse_address_space(&p[1..], "P")?
} }
["a", ref a..] => dl.aggregate_align = align(a, "a")?, // FIXME: Ping cfg(bootstrap) -- Use `ref a @ ..` with new bootstrap compiler.
["f32", ref a..] => dl.f32_align = align(a, "f32")?, ["a", ..] => {
["f64", ref a..] => dl.f64_align = align(a, "f64")?, let a = &spec_parts[1..]; // FIXME inline into pattern.
[p @ "p", s, ref a..] | [p @ "p0", s, ref a..] => { dl.aggregate_align = align(a, "a")?
}
["f32", ..] => {
let a = &spec_parts[1..]; // FIXME inline into pattern.
dl.f32_align = align(a, "f32")?
}
["f64", ..] => {
let a = &spec_parts[1..]; // FIXME inline into pattern.
dl.f64_align = align(a, "f64")?
}
[p @ "p", s, ..] | [p @ "p0", s, ..] => {
let a = &spec_parts[2..]; // FIXME inline into pattern.
dl.pointer_size = size(s, p)?; dl.pointer_size = size(s, p)?;
dl.pointer_align = align(a, p)?; dl.pointer_align = align(a, p)?;
} }
[s, ref a..] if s.starts_with("i") => { [s, ..] if s.starts_with("i") => {
let a = &spec_parts[1..]; // FIXME inline into pattern.
let bits = match s[1..].parse::<u64>() { let bits = match s[1..].parse::<u64>() {
Ok(bits) => bits, Ok(bits) => bits,
Err(_) => { Err(_) => {
@ -142,7 +156,8 @@ impl TargetDataLayout {
dl.i128_align = a; dl.i128_align = a;
} }
} }
[s, ref a..] if s.starts_with("v") => { [s, ..] if s.starts_with("v") => {
let a = &spec_parts[1..]; // FIXME inline into pattern.
let v_size = size(&s[1..], "v")?; let v_size = size(&s[1..], "v")?;
let a = align(a, s)?; let a = align(a, s)?;
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {

View File

@ -196,7 +196,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rhs_ty = self.check_expr(end); let rhs_ty = self.check_expr(end);
// Check that both end-points are of numeric or char type. // Check that both end-points are of numeric or char type.
let numeric_or_char = |ty: Ty<'_>| ty.is_numeric() || ty.is_char(); let numeric_or_char = |ty: Ty<'_>| {
ty.is_numeric()
|| ty.is_char()
|| ty.references_error()
};
let lhs_compat = numeric_or_char(lhs_ty); let lhs_compat = numeric_or_char(lhs_ty);
let rhs_compat = numeric_or_char(rhs_ty); let rhs_compat = numeric_or_char(rhs_ty);

View File

@ -1818,7 +1818,9 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
); );
let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
err.span_label(sp, &msg); err.span_label(sp, &msg);
if let &[ref start.., ref end] = &variant_spans[..] { if let &[.., ref end] = &variant_spans[..] {
// FIXME: Ping cfg(bootstrap) -- Use `ref start @ ..` with new bootstrap compiler.
let start = &variant_spans[..variant_spans.len() - 1];
for variant_span in start { for variant_span in start {
err.span_label(*variant_span, ""); err.span_label(*variant_span, "");
} }

View File

@ -3497,8 +3497,8 @@ Example of erroneous code:
let r = &[1, 2]; let r = &[1, 2];
match r { match r {
&[a, b, c, rest..] => { // error: pattern requires at least 3 &[a, b, c, rest @ ..] => { // error: pattern requires at least 3
// elements but array has 2 // elements but array has 2
println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); println!("a={}, b={}, c={} rest={:?}", a, b, c, rest);
} }
} }
@ -3512,7 +3512,7 @@ requires. You can match an arbitrary number of remaining elements with `..`:
let r = &[1, 2, 3, 4, 5]; let r = &[1, 2, 3, 4, 5];
match r { match r {
&[a, b, c, rest..] => { // ok! &[a, b, c, rest @ ..] => { // ok!
// prints `a=1, b=2, c=3 rest=[4, 5]` // prints `a=1, b=2, c=3 rest=[4, 5]`
println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); println!("a={}, b={}, c={} rest={:?}", a, b, c, rest);
} }

View File

@ -519,21 +519,28 @@ impl fmt::Debug for Pat {
} }
impl Pat { impl Pat {
/// Attempt reparsing the pattern as a type.
/// This is intended for use by diagnostics.
pub(super) fn to_ty(&self) -> Option<P<Ty>> { pub(super) fn to_ty(&self) -> Option<P<Ty>> {
let node = match &self.node { let node = match &self.node {
// In a type expression `_` is an inference variable.
PatKind::Wild => TyKind::Infer, PatKind::Wild => TyKind::Infer,
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => { PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => {
TyKind::Path(None, Path::from_ident(*ident)) TyKind::Path(None, Path::from_ident(*ident))
} }
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
PatKind::Mac(mac) => TyKind::Mac(mac.clone()), PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
// `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
PatKind::Ref(pat, mutbl) => pat PatKind::Ref(pat, mutbl) => pat
.to_ty() .to_ty()
.map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?, .map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
PatKind::Slice(pats, None, _) if pats.len() == 1 => { // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
pats[0].to_ty().map(TyKind::Slice)? // when `P` can be reparsed as a type `T`.
} PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
PatKind::Tuple(pats, None) => { // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
// assuming `T0` to `Tn` are all syntactically valid as types.
PatKind::Tuple(pats) => {
let mut tys = Vec::with_capacity(pats.len()); let mut tys = Vec::with_capacity(pats.len());
// FIXME(#48994) - could just be collected into an Option<Vec> // FIXME(#48994) - could just be collected into an Option<Vec>
for pat in pats { for pat in pats {
@ -559,19 +566,15 @@ impl Pat {
return false; return false;
} }
match self.node { match &self.node {
PatKind::Ident(_, _, Some(ref p)) => p.walk(it), PatKind::Ident(_, _, Some(p)) => p.walk(it),
PatKind::Struct(_, ref fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)),
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
s.iter().all(|p| p.walk(it)) s.iter().all(|p| p.walk(it))
} }
PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => s.walk(it), PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
PatKind::Slice(ref before, ref slice, ref after) => {
before.iter().all(|p| p.walk(it))
&& slice.iter().all(|p| p.walk(it))
&& after.iter().all(|p| p.walk(it))
}
PatKind::Wild PatKind::Wild
| PatKind::Rest
| PatKind::Lit(_) | PatKind::Lit(_)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Ident(..) | PatKind::Ident(..)
@ -579,6 +582,14 @@ impl Pat {
| PatKind::Mac(_) => true, | PatKind::Mac(_) => true,
} }
} }
/// Is this a `..` pattern?
pub fn is_rest(&self) -> bool {
match self.node {
PatKind::Rest => true,
_ => false,
}
}
} }
/// A single field in a struct pattern /// A single field in a struct pattern
@ -630,9 +641,7 @@ pub enum PatKind {
Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool), Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool),
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`). /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. TupleStruct(Path, Vec<P<Pat>>),
/// `0 <= position <= subpats.len()`.
TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
/// A possibly qualified path pattern. /// A possibly qualified path pattern.
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
@ -641,9 +650,7 @@ pub enum PatKind {
Path(Option<QSelf>, Path), Path(Option<QSelf>, Path),
/// A tuple pattern (`(a, b)`). /// A tuple pattern (`(a, b)`).
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. Tuple(Vec<P<Pat>>),
/// `0 <= position <= subpats.len()`.
Tuple(Vec<P<Pat>>, Option<usize>),
/// A `box` pattern. /// A `box` pattern.
Box(P<Pat>), Box(P<Pat>),
@ -657,9 +664,22 @@ pub enum PatKind {
/// A range pattern (e.g., `1...2`, `1..=2` or `1..2`). /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
Range(P<Expr>, P<Expr>, Spanned<RangeEnd>), Range(P<Expr>, P<Expr>, Spanned<RangeEnd>),
/// `[a, b, ..i, y, z]` is represented as: /// A slice pattern `[a, b, c]`.
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])` Slice(Vec<P<Pat>>),
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
/// A rest pattern `..`.
///
/// Syntactically it is valid anywhere.
///
/// Semantically however, it only has meaning immediately inside:
/// - a slice pattern: `[a, .., b]`,
/// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`,
/// - a tuple pattern: `(a, .., b)`,
/// - a tuple struct/variant pattern: `$path(a, .., b)`.
///
/// In all of these cases, an additional restriction applies,
/// only one rest pattern may occur in the pattern sequences.
Rest,
/// Parentheses in patterns used for grouping (i.e., `(PAT)`). /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
Paren(P<Pat>), Paren(P<Pat>),

View File

@ -840,14 +840,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
} }
fn pat_tuple_struct(&self, span: Span, path: ast::Path, fn pat_tuple_struct(&self, span: Span, path: ast::Path,
subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> { subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::TupleStruct(path, subpats, None)) self.pat(span, PatKind::TupleStruct(path, subpats))
} }
fn pat_struct(&self, span: Span, path: ast::Path, fn pat_struct(&self, span: Span, path: ast::Path,
field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> { field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Struct(path, field_pats, false)) self.pat(span, PatKind::Struct(path, field_pats, false))
} }
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> { fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Tuple(pats, None)) self.pat(span, PatKind::Tuple(pats))
} }
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {

View File

@ -2151,11 +2151,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
} }
fn visit_pat(&mut self, pattern: &'a ast::Pat) { fn visit_pat(&mut self, pattern: &'a ast::Pat) {
match pattern.node { match &pattern.node {
PatKind::Slice(_, Some(ref subslice), _) => { PatKind::Slice(pats) => {
gate_feature_post!(&self, slice_patterns, for pat in &*pats {
subslice.span, let span = pat.span;
"syntax for subslices in slice patterns is not yet stabilized"); let inner_pat = match &pat.node {
PatKind::Ident(.., Some(pat)) => pat,
_ => pat,
};
if inner_pat.is_rest() {
gate_feature_post!(
&self,
slice_patterns,
span,
"subslice patterns are unstable"
);
}
}
} }
PatKind::Box(..) => { PatKind::Box(..) => {
gate_feature_post!(&self, box_patterns, gate_feature_post!(&self, box_patterns,

View File

@ -1020,15 +1020,15 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
let Pat { id, node, span } = pat.deref_mut(); let Pat { id, node, span } = pat.deref_mut();
vis.visit_id(id); vis.visit_id(id);
match node { match node {
PatKind::Wild => {} PatKind::Wild | PatKind::Rest => {}
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));
} }
PatKind::Lit(e) => vis.visit_expr(e), PatKind::Lit(e) => vis.visit_expr(e),
PatKind::TupleStruct(path, pats, _ddpos) => { PatKind::TupleStruct(path, elems) => {
vis.visit_path(path); vis.visit_path(path);
visit_vec(pats, |pat| vis.visit_pat(pat)); visit_vec(elems, |elem| vis.visit_pat(elem));
} }
PatKind::Path(qself, path) => { PatKind::Path(qself, path) => {
vis.visit_qself(qself); vis.visit_qself(qself);
@ -1043,7 +1043,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
vis.visit_span(span); vis.visit_span(span);
}; };
} }
PatKind::Tuple(elts, _ddpos) => visit_vec(elts, |elt| vis.visit_pat(elt)), PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Box(inner) => vis.visit_pat(inner),
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
@ -1051,11 +1051,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
vis.visit_expr(e2); vis.visit_expr(e2);
vis.visit_span(span); vis.visit_span(span);
} }
PatKind::Slice(before, slice, after) => { PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
visit_vec(before, |pat| vis.visit_pat(pat));
visit_opt(slice, |slice| vis.visit_pat(slice));
visit_vec(after, |pat| vis.visit_pat(pat));
}
PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::Paren(inner) => vis.visit_pat(inner),
PatKind::Mac(mac) => vis.visit_mac(mac), PatKind::Mac(mac) => vis.visit_mac(mac),
} }

View File

@ -890,14 +890,13 @@ impl<'a> Parser<'a> {
/// Parses a sequence, including the closing delimiter. The function /// Parses a sequence, including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or /// `f` must consume tokens until reaching the next separator or
/// closing bracket. /// closing bracket.
pub fn parse_seq_to_end<T, F>(&mut self, pub fn parse_seq_to_end<T>(
ket: &TokenKind, &mut self,
sep: SeqSep, ket: &TokenKind,
f: F) sep: SeqSep,
-> PResult<'a, Vec<T>> where f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, Vec<T>> {
{ let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
if !recovered { if !recovered {
self.bump(); self.bump();
} }
@ -907,39 +906,39 @@ impl<'a> Parser<'a> {
/// Parses a sequence, not including the closing delimiter. The function /// Parses a sequence, not including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or /// `f` must consume tokens until reaching the next separator or
/// closing bracket. /// closing bracket.
pub fn parse_seq_to_before_end<T, F>( pub fn parse_seq_to_before_end<T>(
&mut self, &mut self,
ket: &TokenKind, ket: &TokenKind,
sep: SeqSep, sep: SeqSep,
f: F, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (Vec<T>, bool)> ) -> PResult<'a, (Vec<T>, bool, bool)> {
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
} }
crate fn parse_seq_to_before_tokens<T, F>( fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
kets.iter().any(|k| {
match expect {
TokenExpectType::Expect => self.check(k),
TokenExpectType::NoExpect => self.token == **k,
}
})
}
crate fn parse_seq_to_before_tokens<T>(
&mut self, &mut self,
kets: &[&TokenKind], kets: &[&TokenKind],
sep: SeqSep, sep: SeqSep,
expect: TokenExpectType, expect: TokenExpectType,
mut f: F, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (Vec<T>, bool /* recovered */)> ) -> PResult<'a, (Vec<T>, bool /* trailing */, bool /* recovered */)> {
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
{
let mut first = true; let mut first = true;
let mut recovered = false; let mut recovered = false;
let mut trailing = false;
let mut v = vec![]; let mut v = vec![];
while !kets.iter().any(|k| { while !self.expect_any_with_type(kets, expect) {
match expect { if let token::CloseDelim(..) | token::Eof = self.token.kind {
TokenExpectType::Expect => self.check(k), break
TokenExpectType::NoExpect => self.token == **k, }
}
}) {
match self.token.kind {
token::CloseDelim(..) | token::Eof => break,
_ => {}
};
if let Some(ref t) = sep.sep { if let Some(ref t) = sep.sep {
if first { if first {
first = false; first = false;
@ -973,12 +972,8 @@ impl<'a> Parser<'a> {
} }
} }
} }
if sep.trailing_sep_allowed && kets.iter().any(|k| { if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
match expect { trailing = true;
TokenExpectType::Expect => self.check(k),
TokenExpectType::NoExpect => self.token == **k,
}
}) {
break; break;
} }
@ -986,27 +981,45 @@ impl<'a> Parser<'a> {
v.push(t); v.push(t);
} }
Ok((v, recovered)) Ok((v, trailing, recovered))
} }
/// Parses a sequence, including the closing delimiter. The function /// Parses a sequence, including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or /// `f` must consume tokens until reaching the next separator or
/// closing bracket. /// closing bracket.
fn parse_unspanned_seq<T, F>( fn parse_unspanned_seq<T>(
&mut self, &mut self,
bra: &TokenKind, bra: &TokenKind,
ket: &TokenKind, ket: &TokenKind,
sep: SeqSep, sep: SeqSep,
f: F, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, Vec<T>> where ) -> PResult<'a, (Vec<T>, bool)> {
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
self.expect(bra)?; self.expect(bra)?;
let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
if !recovered { if !recovered {
self.eat(ket); self.eat(ket);
} }
Ok(result) Ok((result, trailing))
}
fn parse_delim_comma_seq<T>(
&mut self,
delim: DelimToken,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (Vec<T>, bool)> {
self.parse_unspanned_seq(
&token::OpenDelim(delim),
&token::CloseDelim(delim),
SeqSep::trailing_allowed(token::Comma),
f,
)
}
fn parse_paren_comma_seq<T>(
&mut self,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (Vec<T>, bool)> {
self.parse_delim_comma_seq(token::Paren, f)
} }
/// Advance the parser by one token /// Advance the parser by one token
@ -1804,15 +1817,7 @@ impl<'a> Parser<'a> {
AngleBracketedArgs { args, constraints, span }.into() AngleBracketedArgs { args, constraints, span }.into()
} else { } else {
// `(T, U) -> R` // `(T, U) -> R`
self.bump(); // `(` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let (inputs, recovered) = self.parse_seq_to_before_tokens(
&[&token::CloseDelim(token::Paren)],
SeqSep::trailing_allowed(token::Comma),
TokenExpectType::Expect,
|p| p.parse_ty())?;
if !recovered {
self.bump(); // `)`
}
let span = lo.to(self.prev_span); let span = lo.to(self.prev_span);
let output = if self.eat(&token::RArrow) { let output = if self.eat(&token::RArrow) {
Some(self.parse_ty_common(false, false, false)?) Some(self.parse_ty_common(false, false, false)?)
@ -2516,12 +2521,7 @@ impl<'a> Parser<'a> {
Ok(match self.token.kind { Ok(match self.token.kind {
token::OpenDelim(token::Paren) => { token::OpenDelim(token::Paren) => {
// Method call `expr.f()` // Method call `expr.f()`
let mut args = self.parse_unspanned_seq( let mut args = self.parse_paren_expr_seq()?;
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| Ok(p.parse_expr()?)
)?;
args.insert(0, self_arg); args.insert(0, self_arg);
let span = lo.to(self.prev_span); let span = lo.to(self.prev_span);
@ -2606,12 +2606,7 @@ impl<'a> Parser<'a> {
match self.token.kind { match self.token.kind {
// expr(...) // expr(...)
token::OpenDelim(token::Paren) => { token::OpenDelim(token::Paren) => {
let seq = self.parse_unspanned_seq( let seq = self.parse_paren_expr_seq().map(|es| {
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| Ok(p.parse_expr()?)
).map(|es| {
let nd = self.mk_call(e, es); let nd = self.mk_call(e, es);
let hi = self.prev_span; let hi = self.prev_span;
self.mk_expr(lo.to(hi), nd, ThinVec::new()) self.mk_expr(lo.to(hi), nd, ThinVec::new())
@ -2635,6 +2630,10 @@ impl<'a> Parser<'a> {
return Ok(e); return Ok(e);
} }
fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec<P<Expr>>> {
self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r)
}
crate fn process_potential_macro_variable(&mut self) { crate fn process_potential_macro_variable(&mut self) {
self.token = match self.token.kind { self.token = match self.token.kind {
token::Dollar if self.token.span.ctxt() != SyntaxContext::empty() && token::Dollar if self.token.span.ctxt() != SyntaxContext::empty() &&
@ -3536,122 +3535,6 @@ impl<'a> Parser<'a> {
}; };
} }
// Parses a parenthesized list of patterns like
// `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
// - a vector of the patterns that were parsed
// - 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))?;
let result = match self.parse_pat_list() {
Ok(result) => result,
Err(mut err) => { // recover from parse error in tuple pattern list
err.emit();
self.consume_block(token::Paren);
return Ok((vec![], Some(0), false));
}
};
self.expect(&token::CloseDelim(token::Paren))?;
Ok(result)
}
fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
let mut fields = Vec::new();
let mut ddpos = None;
let mut prev_dd_sp = None;
let mut trailing_comma = false;
loop {
if self.eat(&token::DotDot) {
if ddpos.is_none() {
ddpos = Some(fields.len());
prev_dd_sp = Some(self.prev_span);
} else {
// Emit a friendly error, ignore `..` and continue parsing
let mut err = self.struct_span_err(
self.prev_span,
"`..` can only be used once per tuple or tuple struct pattern",
);
err.span_label(self.prev_span, "can only be used once per pattern");
if let Some(sp) = prev_dd_sp {
err.span_label(sp, "previously present here");
}
err.emit();
}
} else if !self.check(&token::CloseDelim(token::Paren)) {
fields.push(self.parse_pat(None)?);
} else {
break
}
trailing_comma = self.eat(&token::Comma);
if !trailing_comma {
break
}
}
if ddpos == Some(fields.len()) && trailing_comma {
// `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
let msg = "trailing comma is not permitted after `..`";
self.struct_span_err(self.prev_span, msg)
.span_label(self.prev_span, msg)
.emit();
}
Ok((fields, ddpos, trailing_comma))
}
fn parse_pat_vec_elements(
&mut self,
) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> {
let mut before = Vec::new();
let mut slice = None;
let mut after = Vec::new();
let mut first = true;
let mut before_slice = true;
while self.token != token::CloseDelim(token::Bracket) {
if first {
first = false;
} else {
self.expect(&token::Comma)?;
if self.token == token::CloseDelim(token::Bracket)
&& (before_slice || !after.is_empty()) {
break
}
}
if before_slice {
if self.eat(&token::DotDot) {
if self.check(&token::Comma) ||
self.check(&token::CloseDelim(token::Bracket)) {
slice = Some(P(Pat {
id: ast::DUMMY_NODE_ID,
node: PatKind::Wild,
span: self.prev_span,
}));
before_slice = false;
}
continue
}
}
let subpat = self.parse_pat(None)?;
if before_slice && self.eat(&token::DotDot) {
slice = Some(subpat);
before_slice = false;
} else if before_slice {
before.push(subpat);
} else {
after.push(subpat);
}
}
Ok((before, slice, after))
}
fn parse_pat_field( fn parse_pat_field(
&mut self, &mut self,
lo: Span, lo: Span,
@ -3847,20 +3730,34 @@ impl<'a> Parser<'a> {
} }
} }
// helper function to decide whether to parse as ident binding or to try to do /// Is the current token suitable as the start of a range patterns end?
// something more complex like range patterns fn is_pat_range_end_start(&self) -> bool {
self.token.is_path_start() // e.g. `MY_CONST`;
|| self.token == token::Dot // e.g. `.5` for recovery;
|| self.token.can_begin_literal_or_bool() // e.g. `42`.
}
// Helper function to decide whether to parse as ident binding
// or to try to do something more complex like range patterns.
fn parse_as_ident(&mut self) -> bool { fn parse_as_ident(&mut self) -> bool {
self.look_ahead(1, |t| match t.kind { self.look_ahead(1, |t| match t.kind {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), token::DotDotDot | token::DotDotEq | token::DotDot |
// ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the token::ModSep | token::Not => false,
// range pattern branch _ => true,
token::DotDot => None, })
_ => Some(true), }
}).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind {
token::Comma | token::CloseDelim(token::Bracket) => true, /// Parse and throw away a parentesized comma separated
_ => false, /// sequence of patterns until `)` is reached.
})) fn skip_pat_list(&mut self) -> PResult<'a, ()> {
while !self.check(&token::CloseDelim(token::Paren)) {
self.parse_pat(None)?;
if !self.eat(&token::Comma) {
return Ok(())
}
}
Ok(())
} }
/// A wrapper around `parse_pat` with some special error handling for the /// A wrapper around `parse_pat` with some special error handling for the
@ -3876,7 +3773,7 @@ impl<'a> Parser<'a> {
// later. // later.
let comma_span = self.token.span; let comma_span = self.token.span;
self.bump(); self.bump();
if let Err(mut err) = self.parse_pat_list() { if let Err(mut err) = self.skip_pat_list() {
// We didn't expect this to work anyway; we just wanted // We didn't expect this to work anyway; we just wanted
// to advance to the end of the comma-sequence so we know // to advance to the end of the comma-sequence so we know
// the span to suggest parenthesizing // the span to suggest parenthesizing
@ -3908,6 +3805,53 @@ impl<'a> Parser<'a> {
self.parse_pat_with_range_pat(true, expected) self.parse_pat_with_range_pat(true, expected)
} }
/// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery.
fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> {
let lo = self.prev_span;
let end = self.parse_pat_range_end()?;
let range_span = lo.to(end.span);
let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new());
self.diagnostic()
.struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
.span_suggestion(
range_span,
"try using the minimum value for the type",
format!("MIN{}{}", form, pprust::expr_to_string(&end)),
Applicability::HasPlaceholders,
)
.emit();
Ok(PatKind::Range(begin, end, respan(lo, re)))
}
/// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover
/// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
if self.is_pat_range_end_start() {
// Parsing e.g. `X..=Y`.
self.parse_pat_range_end()
} else {
// Parsing e.g. `X..`.
let range_span = begin.span.to(self.prev_span);
self.diagnostic()
.struct_span_err(
range_span,
&format!("`X{}` range patterns are not supported", form),
)
.span_suggestion(
range_span,
"try using the maximum value for the type",
format!("{}{}MAX", pprust::expr_to_string(&begin), form),
Applicability::HasPlaceholders,
)
.emit();
Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
}
}
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed). /// allowed).
fn parse_pat_with_range_pat( fn parse_pat_with_range_pat(
@ -3934,20 +3878,41 @@ impl<'a> Parser<'a> {
pat = PatKind::Ref(subpat, mutbl); pat = PatKind::Ref(subpat, mutbl);
} }
token::OpenDelim(token::Paren) => { token::OpenDelim(token::Paren) => {
// Parse (pat,pat,pat,...) as tuple pattern // Parse a tuple or parenthesis pattern.
let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?; let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
// Here, `(pat,)` is a tuple pattern.
// For backward compatibility, `(..)` is a tuple pattern as well.
pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
PatKind::Paren(fields.into_iter().nth(0).unwrap()) PatKind::Paren(fields.into_iter().nth(0).unwrap())
} else { } else {
PatKind::Tuple(fields, ddpos) PatKind::Tuple(fields)
}; };
} }
token::OpenDelim(token::Bracket) => { token::OpenDelim(token::Bracket) => {
// Parse [pat,pat,...] as slice pattern // Parse `[pat, pat,...]` as a slice pattern.
let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
pat = PatKind::Slice(slice);
}
token::DotDot => {
self.bump(); self.bump();
let (before, slice, after) = self.parse_pat_vec_elements()?; pat = if self.is_pat_range_end_start() {
self.expect(&token::CloseDelim(token::Bracket))?; // Parse `..42` for recovery.
pat = PatKind::Slice(before, slice, after); self.parse_pat_range_to(RangeEnd::Excluded, "..")?
} else {
// A rest pattern `..`.
PatKind::Rest
};
}
token::DotDotEq => {
// Parse `..=42` for recovery.
self.bump();
pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?;
}
token::DotDotDot => {
// Parse `...42` for recovery.
self.bump();
pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?;
} }
// At this point, token != &, &&, (, [ // At this point, token != &, &&, (, [
_ => if self.eat_keyword(kw::Underscore) { _ => if self.eat_keyword(kw::Underscore) {
@ -4004,10 +3969,10 @@ impl<'a> Parser<'a> {
pat = PatKind::Mac(mac); pat = PatKind::Mac(mac);
} }
token::DotDotDot | token::DotDotEq | token::DotDot => { token::DotDotDot | token::DotDotEq | token::DotDot => {
let end_kind = match self.token.kind { let (end_kind, form) = match self.token.kind {
token::DotDot => RangeEnd::Excluded, token::DotDot => (RangeEnd::Excluded, ".."),
token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
_ => panic!("can only parse `..`/`...`/`..=` for ranges \ _ => panic!("can only parse `..`/`...`/`..=` for ranges \
(checked above)"), (checked above)"),
}; };
@ -4016,9 +3981,8 @@ impl<'a> Parser<'a> {
let span = lo.to(self.prev_span); let span = lo.to(self.prev_span);
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
self.bump(); self.bump();
let end = self.parse_pat_range_end()?; let end = self.parse_pat_range_end_opt(&begin, form)?;
let op = Spanned { span: op_span, node: end_kind }; pat = PatKind::Range(begin, end, respan(op_span, end_kind));
pat = PatKind::Range(begin, end, op);
} }
token::OpenDelim(token::Brace) => { token::OpenDelim(token::Brace) => {
if qself.is_some() { if qself.is_some() {
@ -4045,8 +4009,8 @@ impl<'a> Parser<'a> {
return Err(err); return Err(err);
} }
// Parse tuple struct or enum pattern // Parse tuple struct or enum pattern
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
pat = PatKind::TupleStruct(path, fields, ddpos) pat = PatKind::TupleStruct(path, fields)
} }
_ => pat = PatKind::Path(qself, path), _ => pat = PatKind::Path(qself, path),
} }
@ -4057,19 +4021,18 @@ impl<'a> Parser<'a> {
let op_span = self.token.span; let op_span = self.token.span;
if self.check(&token::DotDot) || self.check(&token::DotDotEq) || if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
self.check(&token::DotDotDot) { self.check(&token::DotDotDot) {
let end_kind = if self.eat(&token::DotDotDot) { let (end_kind, form) = if self.eat(&token::DotDotDot) {
RangeEnd::Included(RangeSyntax::DotDotDot) (RangeEnd::Included(RangeSyntax::DotDotDot), "...")
} else if self.eat(&token::DotDotEq) { } else if self.eat(&token::DotDotEq) {
RangeEnd::Included(RangeSyntax::DotDotEq) (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
} else if self.eat(&token::DotDot) { } else if self.eat(&token::DotDot) {
RangeEnd::Excluded (RangeEnd::Excluded, "..")
} else { } else {
panic!("impossible case: we already matched \ panic!("impossible case: we already matched \
on a range-operator token") on a range-operator token")
}; };
let end = self.parse_pat_range_end()?; let end = self.parse_pat_range_end_opt(&begin, form)?;
let op = Spanned { span: op_span, node: end_kind }; pat = PatKind::Range(begin, end, respan(op_span, end_kind))
pat = PatKind::Range(begin, end, op);
} else { } else {
pat = PatKind::Lit(begin); pat = PatKind::Lit(begin);
} }
@ -5359,59 +5322,48 @@ impl<'a> Parser<'a> {
fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool) fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool)
-> PResult<'a, (Vec<Arg> , bool)> { -> PResult<'a, (Vec<Arg> , bool)> {
self.expect(&token::OpenDelim(token::Paren))?;
let sp = self.token.span; let sp = self.token.span;
let mut c_variadic = false; let mut c_variadic = false;
let (args, recovered): (Vec<Option<Arg>>, bool) = let (args, _): (Vec<Option<Arg>>, _) = self.parse_paren_comma_seq(|p| {
self.parse_seq_to_before_end( let do_not_enforce_named_arguments_for_c_variadic =
&token::CloseDelim(token::Paren), |token: &token::Token| -> bool {
SeqSep::trailing_allowed(token::Comma), if token == &token::DotDotDot {
|p| { false
let do_not_enforce_named_arguments_for_c_variadic = } else {
|token: &token::Token| -> bool { named_args
if token == &token::DotDotDot {
false
} else {
named_args
}
};
match p.parse_arg_general(
false,
allow_c_variadic,
do_not_enforce_named_arguments_for_c_variadic
) {
Ok(arg) => {
if let TyKind::CVarArgs = arg.ty.node {
c_variadic = true;
if p.token != token::CloseDelim(token::Paren) {
let span = p.token.span;
p.span_err(span,
"`...` must be the last argument of a C-variadic function");
Ok(None)
} else {
Ok(Some(arg))
}
} else {
Ok(Some(arg))
}
},
Err(mut e) => {
e.emit();
let lo = p.prev_span;
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
let span = lo.to(p.prev_span);
Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
}
} }
};
match p.parse_arg_general(
false,
allow_c_variadic,
do_not_enforce_named_arguments_for_c_variadic
) {
Ok(arg) => {
if let TyKind::CVarArgs = arg.ty.node {
c_variadic = true;
if p.token != token::CloseDelim(token::Paren) {
let span = p.token.span;
p.span_err(span,
"`...` must be the last argument of a C-variadic function");
Ok(None)
} else {
Ok(Some(arg))
}
} else {
Ok(Some(arg))
}
},
Err(mut e) => {
e.emit();
let lo = p.prev_span;
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
let span = lo.to(p.prev_span);
Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
} }
)?; }
})?;
if !recovered {
self.eat(&token::CloseDelim(token::Paren));
}
let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); let args: Vec<_> = args.into_iter().filter_map(|x| x).collect();
@ -5573,7 +5525,7 @@ impl<'a> Parser<'a> {
(vec![self_arg], false) (vec![self_arg], false)
} else if self.eat(&token::Comma) { } else if self.eat(&token::Comma) {
let mut fn_inputs = vec![self_arg]; let mut fn_inputs = vec![self_arg];
let (mut input, recovered) = self.parse_seq_to_before_end( let (mut input, _, recovered) = self.parse_seq_to_before_end(
&token::CloseDelim(token::Paren), sep, parse_arg_fn)?; &token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
fn_inputs.append(&mut input); fn_inputs.append(&mut input);
(fn_inputs, recovered) (fn_inputs, recovered)
@ -5584,7 +5536,9 @@ impl<'a> Parser<'a> {
} }
} }
} else { } else {
self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? let (input, _, recovered) =
self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
(input, recovered)
}; };
if !recovered { if !recovered {
@ -6185,26 +6139,20 @@ impl<'a> Parser<'a> {
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> { fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;` // This is the case where we find `struct Foo<T>(T) where T: Copy;`
// Unit like structs are handled in parse_item_struct function // Unit like structs are handled in parse_item_struct function
let fields = self.parse_unspanned_seq( self.parse_paren_comma_seq(|p| {
&token::OpenDelim(token::Paren), let attrs = p.parse_outer_attributes()?;
&token::CloseDelim(token::Paren), let lo = p.token.span;
SeqSep::trailing_allowed(token::Comma), let vis = p.parse_visibility(true)?;
|p| { let ty = p.parse_ty()?;
let attrs = p.parse_outer_attributes()?; Ok(StructField {
let lo = p.token.span; span: lo.to(ty.span),
let vis = p.parse_visibility(true)?; vis,
let ty = p.parse_ty()?; ident: None,
Ok(StructField { id: ast::DUMMY_NODE_ID,
span: lo.to(ty.span), ty,
vis, attrs,
ident: None, })
id: ast::DUMMY_NODE_ID, }).map(|(r, _)| r)
ty,
attrs,
})
})?;
Ok(fields)
} }
/// Parses a structure field declaration. /// Parses a structure field declaration.
@ -7786,11 +7734,8 @@ impl<'a> Parser<'a> {
/// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
/// ``` /// ```
fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
self.parse_unspanned_seq(&token::OpenDelim(token::Brace), self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID)))
&token::CloseDelim(token::Brace), .map(|(r, _)| r)
SeqSep::trailing_allowed(token::Comma), |this| {
Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID))
})
} }
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> { fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {

View File

@ -2368,22 +2368,10 @@ impl<'a> State<'a> {
self.print_pat(p); self.print_pat(p);
} }
} }
PatKind::TupleStruct(ref path, ref elts, ddpos) => { PatKind::TupleStruct(ref path, ref elts) => {
self.print_path(path, true, 0); self.print_path(path, true, 0);
self.popen(); self.popen();
if let Some(ddpos) = ddpos { self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
if ddpos != 0 {
self.word_space(",");
}
self.s.word("..");
if ddpos != elts.len() {
self.s.word(",");
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
}
} else {
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
}
self.pclose(); self.pclose();
} }
PatKind::Path(None, ref path) => { PatKind::Path(None, ref path) => {
@ -2415,23 +2403,11 @@ impl<'a> State<'a> {
self.s.space(); self.s.space();
self.s.word("}"); self.s.word("}");
} }
PatKind::Tuple(ref elts, ddpos) => { PatKind::Tuple(ref elts) => {
self.popen(); self.popen();
if let Some(ddpos) = ddpos { self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if elts.len() == 1 {
if ddpos != 0 { self.s.word(",");
self.word_space(",");
}
self.s.word("..");
if ddpos != elts.len() {
self.s.word(",");
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
}
} else {
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
if elts.len() == 1 {
self.s.word(",");
}
} }
self.pclose(); self.pclose();
} }
@ -2457,26 +2433,12 @@ impl<'a> State<'a> {
} }
self.print_expr(end); self.print_expr(end);
} }
PatKind::Slice(ref before, ref slice, ref after) => { PatKind::Slice(ref elts) => {
self.s.word("["); self.s.word("[");
self.commasep(Inconsistent, self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
&before[..],
|s, p| s.print_pat(p));
if let Some(ref p) = *slice {
if !before.is_empty() { self.word_space(","); }
if let PatKind::Wild = p.node {
// Print nothing
} else {
self.print_pat(p);
}
self.s.word("..");
if !after.is_empty() { self.word_space(","); }
}
self.commasep(Inconsistent,
&after[..],
|s, p| s.print_pat(p));
self.s.word("]"); self.s.word("]");
} }
PatKind::Rest => self.s.word(".."),
PatKind::Paren(ref inner) => { PatKind::Paren(ref inner) => {
self.popen(); self.popen();
self.print_pat(inner); self.print_pat(inner);

View File

@ -428,9 +428,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V,
pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
match pattern.node { match pattern.node {
PatKind::TupleStruct(ref path, ref children, _) => { PatKind::TupleStruct(ref path, ref elems) => {
visitor.visit_path(path, pattern.id); visitor.visit_path(path, pattern.id);
walk_list!(visitor, visit_pat, children); walk_list!(visitor, visit_pat, elems);
} }
PatKind::Path(ref opt_qself, ref path) => { PatKind::Path(ref opt_qself, ref path) => {
if let Some(ref qself) = *opt_qself { if let Some(ref qself) = *opt_qself {
@ -446,8 +446,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
visitor.visit_pat(&field.node.pat) visitor.visit_pat(&field.node.pat)
} }
} }
PatKind::Tuple(ref tuple_elements, _) => { PatKind::Tuple(ref elems) => {
walk_list!(visitor, visit_pat, tuple_elements); walk_list!(visitor, visit_pat, elems);
} }
PatKind::Box(ref subpattern) | PatKind::Box(ref subpattern) |
PatKind::Ref(ref subpattern, _) | PatKind::Ref(ref subpattern, _) |
@ -463,11 +463,9 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
visitor.visit_expr(lower_bound); visitor.visit_expr(lower_bound);
visitor.visit_expr(upper_bound); visitor.visit_expr(upper_bound);
} }
PatKind::Wild => (), PatKind::Wild | PatKind::Rest => {},
PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => { PatKind::Slice(ref elems) => {
walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, elems);
walk_list!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
} }
PatKind::Mac(ref mac) => visitor.visit_mac(mac), PatKind::Mac(ref mac) => visitor.visit_mac(mac),
} }

View File

@ -8,7 +8,7 @@ fn move_out_from_end() {
fn move_out_by_subslice() { fn move_out_by_subslice() {
let a = [box 1, box 2]; let a = [box 1, box 2];
let [_y..] = a; let [_y @ ..] = a;
} }
fn main() { fn main() {

View File

@ -11,7 +11,7 @@ fn foldl<T, U, F>(values: &[T],
U: Clone+Debug, T:Debug, U: Clone+Debug, T:Debug,
F: FnMut(U, &T) -> U, F: FnMut(U, &T) -> U,
{ match values { { match values {
&[ref head, ref tail..] => &[ref head, ref tail @ ..] =>
foldl(tail, function(initial, head), function), foldl(tail, function(initial, head), function),
&[] => { &[] => {
// FIXME: call guards // FIXME: call guards
@ -28,7 +28,7 @@ fn foldr<T, U, F>(values: &[T],
F: FnMut(&T, U) -> U, F: FnMut(&T, U) -> U,
{ {
match values { match values {
&[ref head.., ref tail] => &[ref head @ .., ref tail] =>
foldr(head, function(tail, initial), function), foldr(head, function(tail, initial), function),
&[] => { &[] => {
// FIXME: call guards // FIXME: call guards

View File

@ -8,7 +8,7 @@ pub fn main() {
let x: &[isize] = &[1, 2, 3, 4, 5]; let x: &[isize] = &[1, 2, 3, 4, 5];
if !x.is_empty() { if !x.is_empty() {
let el = match x { let el = match x {
&[1, ref tail..] => &tail[0], &[1, ref tail @ ..] => &tail[0],
_ => unreachable!() _ => unreachable!()
}; };
println!("{}", *el); println!("{}", *el);

View File

@ -14,7 +14,7 @@ fn a() {
fn b() { fn b() {
let x = [1, 2, 3]; let x = [1, 2, 3];
match x { match x {
[a, b, c..] => { [a, b, c @ ..] => {
assert_eq!(a, 1); assert_eq!(a, 1);
assert_eq!(b, 2); assert_eq!(b, 2);
let expected: &[_] = &[3]; let expected: &[_] = &[3];
@ -22,7 +22,7 @@ fn b() {
} }
} }
match x { match x {
[a.., b, c] => { [a @ .., b, c] => {
let expected: &[_] = &[1]; let expected: &[_] = &[1];
assert_eq!(a, expected); assert_eq!(a, expected);
assert_eq!(b, 2); assert_eq!(b, 2);
@ -30,7 +30,7 @@ fn b() {
} }
} }
match x { match x {
[a, b.., c] => { [a, b @ .., c] => {
assert_eq!(a, 1); assert_eq!(a, 1);
let expected: &[_] = &[2]; let expected: &[_] = &[2];
assert_eq!(b, expected); assert_eq!(b, expected);
@ -50,7 +50,7 @@ fn b() {
fn b_slice() { fn b_slice() {
let x : &[_] = &[1, 2, 3]; let x : &[_] = &[1, 2, 3];
match x { match x {
&[a, b, ref c..] => { &[a, b, ref c @ ..] => {
assert_eq!(a, 1); assert_eq!(a, 1);
assert_eq!(b, 2); assert_eq!(b, 2);
let expected: &[_] = &[3]; let expected: &[_] = &[3];
@ -59,7 +59,7 @@ fn b_slice() {
_ => unreachable!() _ => unreachable!()
} }
match x { match x {
&[ref a.., b, c] => { &[ref a @ .., b, c] => {
let expected: &[_] = &[1]; let expected: &[_] = &[1];
assert_eq!(a, expected); assert_eq!(a, expected);
assert_eq!(b, 2); assert_eq!(b, 2);
@ -68,7 +68,7 @@ fn b_slice() {
_ => unreachable!() _ => unreachable!()
} }
match x { match x {
&[a, ref b.., c] => { &[a, ref b @ .., c] => {
assert_eq!(a, 1); assert_eq!(a, 1);
let expected: &[_] = &[2]; let expected: &[_] = &[2];
assert_eq!(b, expected); assert_eq!(b, expected);
@ -134,20 +134,6 @@ fn e() {
assert_eq!(c, 1); assert_eq!(c, 1);
} }
fn f() {
let x = &[1, 2, 3, 4, 5];
let [a, [b, [c, ..].., d].., e] = *x;
assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5));
let x: &[isize] = x;
let (a, b, c, d, e) = match *x {
[a, [b, [c, ..].., d].., e] => (a, b, c, d, e),
_ => unimplemented!()
};
assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5));
}
pub fn main() { pub fn main() {
a(); a();
b(); b();
@ -155,5 +141,4 @@ pub fn main() {
c(); c();
d(); d();
e(); e();
f();
} }

View File

@ -13,14 +13,14 @@ pub fn main() {
Foo { string: "baz" } Foo { string: "baz" }
]; ];
match x { match x {
[ref first, ref tail..] => { [ref first, ref tail @ ..] => {
assert_eq!(first.string, "foo"); assert_eq!(first.string, "foo");
assert_eq!(tail.len(), 2); assert_eq!(tail.len(), 2);
assert_eq!(tail[0].string, "bar"); assert_eq!(tail[0].string, "bar");
assert_eq!(tail[1].string, "baz"); assert_eq!(tail[1].string, "baz");
match *(tail as &[_]) { match *(tail as &[_]) {
[Foo { .. }, _, Foo { .. }, ref _tail..] => { [Foo { .. }, _, Foo { .. }, ref _tail @ ..] => {
unreachable!(); unreachable!();
} }
[Foo { string: ref a }, Foo { string: ref b }] => { [Foo { string: ref a }, Foo { string: ref b }] => {

View File

@ -5,6 +5,5 @@ fn main() {
let _ = <<A>::B>::C; //~ ERROR cannot find type `A` in this scope let _ = <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
let <<A>::B>::C; //~ ERROR cannot find type `A` in this scope let <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
let 0 ..= <<A>::B>::C; //~ ERROR cannot find type `A` in this scope let 0 ..= <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
//~^ ERROR only char and numeric types are allowed in range patterns
<<A>::B>::C; //~ ERROR cannot find type `A` in this scope <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
} }

View File

@ -23,21 +23,11 @@ LL | let 0 ..= <<A>::B>::C;
| ^ not found in this scope | ^ not found in this scope
error[E0412]: cannot find type `A` in this scope error[E0412]: cannot find type `A` in this scope
--> $DIR/associated-path-shl.rs:9:7 --> $DIR/associated-path-shl.rs:8:7
| |
LL | <<A>::B>::C; LL | <<A>::B>::C;
| ^ not found in this scope | ^ not found in this scope
error[E0029]: only char and numeric types are allowed in range patterns error: aborting due to 5 previous errors
--> $DIR/associated-path-shl.rs:7:15
|
LL | let 0 ..= <<A>::B>::C;
| ^^^^^^^^^^^ ranges require char or numeric types
|
= note: start type: {integer}
= note: end type: [type error]
error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0412`.
Some errors have detailed explanations: E0029, E0412.
For more information about an error, try `rustc --explain E0029`.

View File

@ -4,7 +4,7 @@
#![feature(slice_patterns)] #![feature(slice_patterns)]
fn foo(s: &[i32]) -> &[i32] { fn foo(s: &[i32]) -> &[i32] {
let &[ref xs..] = s; let &[ref xs @ ..] = s;
xs xs
} }

View File

@ -7,6 +7,6 @@ fn main() {
// The subslice used to go out of bounds for zero-sized array items, check that this doesn't // The subslice used to go out of bounds for zero-sized array items, check that this doesn't
// happen anymore // happen anymore
match x { match x {
[_, ref y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ()) [_, ref y @ ..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
} }
} }

View File

@ -192,8 +192,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
LL | match v { LL | match v {
LL | &[x..] => println!("{:?}", x), LL | &[x @ ..] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -204,8 +204,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[_, x..] => println!("{:?}", x), LL | &[_, x @ ..] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -216,8 +216,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[x.., _] => println!("{:?}", x), LL | &[x @ .., _] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -228,8 +228,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[_, x.., _] => println!("{:?}", x), LL | &[_, x @ .., _] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here

View File

@ -140,22 +140,22 @@ fn main() {
let mut v = &[1, 2, 3, 4, 5]; let mut v = &[1, 2, 3, 4, 5];
let x = &mut v; let x = &mut v;
match v { match v {
&[x..] => println!("{:?}", x), &[x @ ..] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed //~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"), _ => panic!("other case"),
} }
match v { match v {
&[_, x..] => println!("{:?}", x), &[_, x @ ..] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed //~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"), _ => panic!("other case"),
} }
match v { match v {
&[x.., _] => println!("{:?}", x), &[x @ .., _] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed //~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"), _ => panic!("other case"),
} }
match v { match v {
&[_, x.., _] => println!("{:?}", x), &[_, x @ .., _] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed //~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"), _ => panic!("other case"),
} }

View File

@ -192,8 +192,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
LL | match v { LL | match v {
LL | &[x..] => println!("{:?}", x), LL | &[x @ ..] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -204,8 +204,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[_, x..] => println!("{:?}", x), LL | &[_, x @ ..] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -216,8 +216,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[x.., _] => println!("{:?}", x), LL | &[x @ .., _] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here
@ -228,8 +228,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
LL | let x = &mut v; LL | let x = &mut v;
| ------ borrow of `v` occurs here | ------ borrow of `v` occurs here
... ...
LL | &[_, x.., _] => println!("{:?}", x), LL | &[_, x @ .., _] => println!("{:?}", x),
| ^ use of borrowed `v` | ^^^^^^ use of borrowed `v`
... ...
LL | drop(x); LL | drop(x);
| - borrow later used here | - borrow later used here

View File

@ -10,7 +10,7 @@ fn move_out_from_begin_and_end() {
fn move_out_by_const_index_and_subslice() { fn move_out_by_const_index_and_subslice() {
let a = [box 1, box 2]; let a = [box 1, box 2];
let [_x, _] = a; let [_x, _] = a;
let [_y..] = a; //~ ERROR [E0382] let [_y @ ..] = a; //~ ERROR [E0382]
} }
fn main() {} fn main() {}

View File

@ -13,8 +13,8 @@ error[E0382]: use of moved value: `a[..]`
| |
LL | let [_x, _] = a; LL | let [_x, _] = a;
| -- value moved here | -- value moved here
LL | let [_y..] = a; LL | let [_y @ ..] = a;
| ^^ value used here after move | ^^^^^^^ value used here after move
| |
= note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait = note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait

View File

@ -15,7 +15,7 @@ pub fn main() {
]; ];
let x: &[Foo] = &x; let x: &[Foo] = &x;
match *x { match *x {
[_, ref tail..] => { [_, ref tail @ ..] => {
match tail { match tail {
//~^ ERROR cannot move out of type `[Foo]` //~^ ERROR cannot move out of type `[Foo]`
&[Foo { string: a }, &[Foo { string: a },

View File

@ -5,7 +5,7 @@
fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> { fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> {
match *v { match *v {
[ref mut head, ref mut tail..] => { [ref mut head, ref mut tail @ ..] => {
Some((head, tail)) Some((head, tail))
} }
[] => None [] => None

View File

@ -70,7 +70,7 @@ fn const_index_mixed(s: &mut [i32]) {
fn const_index_and_subslice_ok(s: &mut [i32]) { fn const_index_and_subslice_ok(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s { if let [ref first, ref second, ..] = *s {
if let [_, _, ref mut tail..] = *s { if let [_, _, ref mut tail @ ..] = *s {
nop(&[first, second]); nop(&[first, second]);
nop_subslice(tail); nop_subslice(tail);
} }
@ -79,7 +79,7 @@ fn const_index_and_subslice_ok(s: &mut [i32]) {
fn const_index_and_subslice_err(s: &mut [i32]) { fn const_index_and_subslice_err(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s { if let [ref first, ref second, ..] = *s {
if let [_, ref mut tail..] = *s { //~ERROR if let [_, ref mut tail @ ..] = *s { //~ERROR
nop(&[first, second]); nop(&[first, second]);
nop_subslice(tail); nop_subslice(tail);
} }
@ -88,7 +88,7 @@ fn const_index_and_subslice_err(s: &mut [i32]) {
fn const_index_and_subslice_from_end_ok(s: &mut [i32]) { fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
if let [.., ref second, ref first] = *s { if let [.., ref second, ref first] = *s {
if let [ref mut tail.., _, _] = *s { if let [ref mut tail @ .., _, _] = *s {
nop(&[first, second]); nop(&[first, second]);
nop_subslice(tail); nop_subslice(tail);
} }
@ -97,7 +97,7 @@ fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
fn const_index_and_subslice_from_end_err(s: &mut [i32]) { fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
if let [.., ref second, ref first] = *s { if let [.., ref second, ref first] = *s {
if let [ref mut tail.., _] = *s { //~ERROR if let [ref mut tail @ .., _] = *s { //~ERROR
nop(&[first, second]); nop(&[first, second]);
nop_subslice(tail); nop_subslice(tail);
} }
@ -105,8 +105,8 @@ fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
} }
fn subslices(s: &mut [i32]) { fn subslices(s: &mut [i32]) {
if let [_, _, _, ref s1..] = *s { if let [_, _, _, ref s1 @ ..] = *s {
if let [ref mut s2.., _, _, _] = *s { //~ERROR if let [ref mut s2 @ .., _, _, _] = *s { //~ERROR
nop_subslice(s1); nop_subslice(s1);
nop_subslice(s2); nop_subslice(s2);
} }

View File

@ -89,8 +89,8 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
| |
LL | if let [ref first, ref second, ..] = *s { LL | if let [ref first, ref second, ..] = *s {
| ---------- immutable borrow occurs here | ---------- immutable borrow occurs here
LL | if let [_, ref mut tail..] = *s { LL | if let [_, ref mut tail @ ..] = *s {
| ^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]); LL | nop(&[first, second]);
| ------ immutable borrow later used here | ------ immutable borrow later used here
@ -99,18 +99,18 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
| |
LL | if let [.., ref second, ref first] = *s { LL | if let [.., ref second, ref first] = *s {
| ---------- immutable borrow occurs here | ---------- immutable borrow occurs here
LL | if let [ref mut tail.., _] = *s { LL | if let [ref mut tail @ .., _] = *s {
| ^^^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]); LL | nop(&[first, second]);
| ------ immutable borrow later used here | ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:109:17 --> $DIR/borrowck-slice-pattern-element-loan.rs:109:17
| |
LL | if let [_, _, _, ref s1..] = *s { LL | if let [_, _, _, ref s1 @ ..] = *s {
| ------ immutable borrow occurs here | ----------- immutable borrow occurs here
LL | if let [ref mut s2.., _, _, _] = *s { LL | if let [ref mut s2 @ .., _, _, _] = *s {
| ^^^^^^^^^^ mutable borrow occurs here | ^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop_subslice(s1); LL | nop_subslice(s1);
| -- immutable borrow later used here | -- immutable borrow later used here

View File

@ -4,7 +4,7 @@ fn a<'a>() -> &'a [isize] {
let vec = vec![1, 2, 3, 4]; let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec; let vec: &[isize] = &vec;
let tail = match vec { let tail = match vec {
&[_, ref tail..] => tail, &[_, ref tail @ ..] => tail,
_ => panic!("a") _ => panic!("a")
}; };
tail //~ ERROR cannot return value referencing local variable `vec` tail //~ ERROR cannot return value referencing local variable `vec`
@ -14,7 +14,7 @@ fn b<'a>() -> &'a [isize] {
let vec = vec![1, 2, 3, 4]; let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec; let vec: &[isize] = &vec;
let init = match vec { let init = match vec {
&[ref init.., _] => init, &[ref init @ .., _] => init,
_ => panic!("b") _ => panic!("b")
}; };
init //~ ERROR cannot return value referencing local variable `vec` init //~ ERROR cannot return value referencing local variable `vec`
@ -24,7 +24,7 @@ fn c<'a>() -> &'a [isize] {
let vec = vec![1, 2, 3, 4]; let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec; let vec: &[isize] = &vec;
let slice = match vec { let slice = match vec {
&[_, ref slice.., _] => slice, &[_, ref slice @ .., _] => slice,
_ => panic!("c") _ => panic!("c")
}; };
slice //~ ERROR cannot return value referencing local variable `vec` slice //~ ERROR cannot return value referencing local variable `vec`

View File

@ -4,7 +4,7 @@ fn a() {
let mut v = vec![1, 2, 3]; let mut v = vec![1, 2, 3];
let vb: &mut [isize] = &mut v; let vb: &mut [isize] = &mut v;
match vb { match vb {
&mut [_a, ref tail..] => { &mut [_a, ref tail @ ..] => {
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
} }
_ => {} _ => {}

View File

@ -5,7 +5,7 @@
fn main() { fn main() {
let mut a = [1, 2, 3, 4]; let mut a = [1, 2, 3, 4];
let t = match a { let t = match a {
[1, 2, ref tail..] => tail, [1, 2, ref tail @ ..] => tail,
_ => unreachable!() _ => unreachable!()
}; };
println!("t[0]: {}", t[0]); println!("t[0]: {}", t[0]);

View File

@ -1,8 +1,8 @@
error[E0506]: cannot assign to `a[_]` because it is borrowed error[E0506]: cannot assign to `a[_]` because it is borrowed
--> $DIR/borrowck-vec-pattern-move-tail.rs:12:5 --> $DIR/borrowck-vec-pattern-move-tail.rs:12:5
| |
LL | [1, 2, ref tail..] => tail, LL | [1, 2, ref tail @ ..] => tail,
| -------- borrow of `a[_]` occurs here | ------------- borrow of `a[_]` occurs here
... ...
LL | a[2] = 0; LL | a[2] = 0;
| ^^^^^^^^ assignment to borrowed `a[_]` occurs here | ^^^^^^^^ assignment to borrowed `a[_]` occurs here

View File

@ -19,7 +19,7 @@ fn b() {
let mut vec = vec![box 1, box 2, box 3]; let mut vec = vec![box 1, box 2, box 3];
let vec: &mut [Box<isize>] = &mut vec; let vec: &mut [Box<isize>] = &mut vec;
match vec { match vec {
&mut [ref _b..] => { &mut [ref _b @ ..] => {
//~^ borrow of `vec[_]` occurs here //~^ borrow of `vec[_]` occurs here
vec[0] = box 4; //~ ERROR cannot assign vec[0] = box 4; //~ ERROR cannot assign
//~^ NOTE assignment to borrowed `vec[_]` occurs here //~^ NOTE assignment to borrowed `vec[_]` occurs here

View File

@ -13,8 +13,8 @@ LL | _a.use_ref();
error[E0506]: cannot assign to `vec[_]` because it is borrowed error[E0506]: cannot assign to `vec[_]` because it is borrowed
--> $DIR/borrowck-vec-pattern-nesting.rs:24:13 --> $DIR/borrowck-vec-pattern-nesting.rs:24:13
| |
LL | &mut [ref _b..] => { LL | &mut [ref _b @ ..] => {
| ------ borrow of `vec[_]` occurs here | ----------- borrow of `vec[_]` occurs here
LL | LL |
LL | vec[0] = box 4; LL | vec[0] = box 4;
| ^^^^^^ assignment to borrowed `vec[_]` occurs here | ^^^^^^ assignment to borrowed `vec[_]` occurs here

View File

@ -4,7 +4,7 @@ fn a<'a>() -> &'a isize {
let vec = vec![1, 2, 3, 4]; let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec; let vec: &[isize] = &vec;
let tail = match vec { let tail = match vec {
&[_a, ref tail..] => &tail[0], &[_a, ref tail @ ..] => &tail[0],
_ => panic!("foo") _ => panic!("foo")
}; };
tail //~ ERROR cannot return value referencing local variable `vec` tail //~ ERROR cannot return value referencing local variable `vec`

View File

@ -217,7 +217,7 @@ async fn subslice_pattern_from_end_with_drop(a: Rc<Allocator>, arg: bool, arg2:
if arg { if arg {
let [.., _x, _] = arr; let [.., _x, _] = arr;
} else { } else {
let [_, _y..] = arr; let [_, _y @ ..] = arr;
} }
a.alloc().await; a.alloc().await;
} }
@ -226,7 +226,7 @@ async fn subslice_pattern_reassign(a: Rc<Allocator>) {
let mut ar = [a.alloc().await, a.alloc().await, a.alloc().await]; let mut ar = [a.alloc().await, a.alloc().await, a.alloc().await];
let [_, _, _x] = ar; let [_, _, _x] = ar;
ar = [a.alloc().await, a.alloc().await, a.alloc().await]; ar = [a.alloc().await, a.alloc().await, a.alloc().await];
let [_, _y..] = ar; let [_, _y @ ..] = ar;
a.alloc().await; a.alloc().await;
} }

View File

@ -237,7 +237,7 @@ fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
if arg { if arg {
let[.., _x, _] = a; let[.., _x, _] = a;
} else { } else {
let[_, _y..] = a; let[_, _y @ ..] = a;
} }
} }
@ -251,7 +251,7 @@ fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
if arg { if arg {
let[.., _x, _] = a; let[.., _x, _] = a;
} else { } else {
let[_, _y..] = a; let[_, _y @ ..] = a;
} }
} }
@ -266,7 +266,7 @@ fn subslice_pattern_reassign(a: &Allocator) {
let mut ar = [a.alloc(), a.alloc(), a.alloc()]; let mut ar = [a.alloc(), a.alloc(), a.alloc()];
let[_, _, _x] = ar; let[_, _, _x] = ar;
ar = [a.alloc(), a.alloc(), a.alloc()]; ar = [a.alloc(), a.alloc(), a.alloc()];
let[_, _y..] = ar; let[_, _y @ ..] = ar;
} }
fn panic_after_return(a: &Allocator) -> Ptr<'_> { fn panic_after_return(a: &Allocator) -> Ptr<'_> {

View File

@ -3,7 +3,7 @@
fn main() { fn main() {
let r = &[1, 2]; let r = &[1, 2];
match r { match r {
&[a, b, c, rest..] => { &[a, b, c, rest @ ..] => {
//~^ ERROR E0528 //~^ ERROR E0528
} }
} }

View File

@ -1,8 +1,8 @@
error[E0528]: pattern requires at least 3 elements but array has 2 error[E0528]: pattern requires at least 3 elements but array has 2
--> $DIR/E0528.rs:6:10 --> $DIR/E0528.rs:6:10
| |
LL | &[a, b, c, rest..] => { LL | &[a, b, c, rest @ ..] => {
| ^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,9 @@
fn main() { fn main() {
match [5..4, 99..105, 43..44] { match [5..4, 99..105, 43..44] {
[_, 99.., _] => {}, //~ ERROR unexpected token: `,` [_, 99.., _] => {},
//~^ ERROR `X..` range patterns are not supported
//~| ERROR mismatched types
_ => {}, _ => {},
} }
} }

View File

@ -1,8 +1,20 @@
error: unexpected token: `,` error: `X..` range patterns are not supported
--> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17 --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
| |
LL | [_, 99.., _] => {}, LL | [_, 99.., _] => {},
| ^ | ^^^^ help: try using the maximum value for the type: `99..MAX`
error: aborting due to previous error error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
|
LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>`
LL | [_, 99.., _] => {},
| ^^^^ expected struct `std::ops::Range`, found integer
|
= note: expected type `std::ops::Range<{integer}>`
found type `{integer}`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -2,7 +2,10 @@
fn main() { fn main() {
match [5..4, 99..105, 43..44] { match [5..4, 99..105, 43..44] {
[_, 99..] => {}, //~ ERROR unexpected token: `]` [_, 99..] => {},
//~^ ERROR `X..` range patterns are not supported
//~| ERROR pattern requires 2 elements but array has 3
//~| ERROR mismatched types
_ => {}, _ => {},
} }
} }

View File

@ -1,8 +1,27 @@
error: unexpected token: `]` error: `X..` range patterns are not supported
--> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17 --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
| |
LL | [_, 99..] => {}, LL | [_, 99..] => {},
| ^ | ^^^^ help: try using the maximum value for the type: `99..MAX`
error: aborting due to previous error error[E0527]: pattern requires 2 elements but array has 3
--> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:9
|
LL | [_, 99..] => {},
| ^^^^^^^^^ expected 3 elements
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
|
LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>`
LL | [_, 99..] => {},
| ^^^^ expected struct `std::ops::Range`, found integer
|
= note: expected type `std::ops::Range<{integer}>`
found type `{integer}`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0527.
For more information about an error, try `rustc --explain E0308`.

View File

@ -2,7 +2,10 @@
fn main() { fn main() {
match [5..4, 99..105, 43..44] { match [5..4, 99..105, 43..44] {
[..9, 99..100, _] => {}, //~ ERROR expected one of `,` or `]`, found `9` [..9, 99..100, _] => {},
//~^ ERROR `..X` range patterns are not supported
//~| ERROR mismatched types
//~| ERROR mismatched types
_ => {}, _ => {},
} }
} }

View File

@ -1,8 +1,31 @@
error: expected one of `,` or `]`, found `9` error: `..X` range patterns are not supported
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10
| |
LL | [..9, 99..100, _] => {}, LL | [..9, 99..100, _] => {},
| ^ expected one of `,` or `]` here | ^^^ help: try using the minimum value for the type: `MIN..9`
error: aborting due to previous error error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10
|
LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>`
LL | [..9, 99..100, _] => {},
| ^^^ expected struct `std::ops::Range`, found integer
|
= note: expected type `std::ops::Range<{integer}>`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15
|
LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>`
LL | [..9, 99..100, _] => {},
| ^^^^^^^ expected struct `std::ops::Range`, found integer
|
= note: expected type `std::ops::Range<{integer}>`
found type `{integer}`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -3,15 +3,15 @@
fn main() { fn main() {
let x = [1, 2, 3, 4, 5]; let x = [1, 2, 3, 4, 5];
match x { match x {
[1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [1, 2, ..] => {} //~ ERROR subslice patterns are unstable
[1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [1, .., 5] => {} //~ ERROR subslice patterns are unstable
[.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [.., 4, 5] => {} //~ ERROR subslice patterns are unstable
} }
let x = [ 1, 2, 3, 4, 5 ]; let x = [ 1, 2, 3, 4, 5 ];
match x { match x {
[ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [ xs @ .., 4, 5 ] => {} //~ ERROR subslice patterns are unstable
[ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [ 1, xs @ .., 5 ] => {} //~ ERROR subslice patterns are unstable
[ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized [ 1, 2, xs @ .. ] => {} //~ ERROR subslice patterns are unstable
} }
} }

View File

@ -1,4 +1,4 @@
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:6:16 --> $DIR/feature-gate-slice-patterns.rs:6:16
| |
LL | [1, 2, ..] => {} LL | [1, 2, ..] => {}
@ -7,7 +7,7 @@ LL | [1, 2, ..] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:7:13 --> $DIR/feature-gate-slice-patterns.rs:7:13
| |
LL | [1, .., 5] => {} LL | [1, .., 5] => {}
@ -16,7 +16,7 @@ LL | [1, .., 5] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:8:10 --> $DIR/feature-gate-slice-patterns.rs:8:10
| |
LL | [.., 4, 5] => {} LL | [.., 4, 5] => {}
@ -25,29 +25,29 @@ LL | [.., 4, 5] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:13:11 --> $DIR/feature-gate-slice-patterns.rs:13:11
| |
LL | [ xs.., 4, 5 ] => {} LL | [ xs @ .., 4, 5 ] => {}
| ^^ | ^^^^^^^
| |
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:14:14 --> $DIR/feature-gate-slice-patterns.rs:14:14
| |
LL | [ 1, xs.., 5 ] => {} LL | [ 1, xs @ .., 5 ] => {}
| ^^ | ^^^^^^^
| |
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: syntax for subslices in slice patterns is not yet stabilized error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:15:17 --> $DIR/feature-gate-slice-patterns.rs:15:17
| |
LL | [ 1, 2, xs.. ] => {} LL | [ 1, 2, xs @ .. ] => {}
| ^^ | ^^^^^^^
| |
= note: for more information, see https://github.com/rust-lang/rust/issues/62254 = note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable = help: add `#![feature(slice_patterns)]` to the crate attributes to enable

View File

@ -6,7 +6,7 @@ fn main() {
let v: isize = match &*sl { let v: isize = match &*sl {
&[] => 0, &[] => 0,
&[a,b,c] => 3, &[a,b,c] => 3,
&[a, ref rest..] => a, &[a, ref rest @ ..] => a,
&[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern
}; };
} }

View File

@ -1,8 +1,8 @@
error: unreachable pattern error: unreachable pattern
--> $DIR/issue-12369.rs:10:9 --> $DIR/issue-12369.rs:10:9
| |
LL | &[10,a, ref rest..] => 10 LL | &[10,a, ref rest @ ..] => 10
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
| |
note: lint level defined here note: lint level defined here
--> $DIR/issue-12369.rs:2:9 --> $DIR/issue-12369.rs:2:9

View File

@ -7,11 +7,11 @@ fn main() {
let mut result = vec![]; let mut result = vec![];
loop { loop {
x = match *x { x = match *x {
[1, n, 3, ref rest..] => { [1, n, 3, ref rest @ ..] => {
result.push(n); result.push(n);
rest rest
} }
[n, ref rest..] => { [n, ref rest @ ..] => {
result.push(n); result.push(n);
rest rest
} }

View File

@ -9,6 +9,6 @@ fn count_members(v: &[usize]) -> usize {
match *v { match *v {
[] => 0, [] => 0,
[_] => 1, [_] => 1,
[_, ref xs..] => 1 + count_members(xs) [_, ref xs @ ..] => 1 + count_members(xs)
} }
} }

View File

@ -7,8 +7,8 @@ fn main() {
}, 42_usize); }, 42_usize);
assert_eq!(match [0u8; 1024] { assert_eq!(match [0u8; 1024] {
[1, _..] => 0_usize, [1, ..] => 0_usize,
[0, _..] => 1_usize, [0, ..] => 1_usize,
_ => 2_usize _ => 2_usize
}, 1_usize); }, 1_usize);
} }

View File

@ -1,6 +0,0 @@
#![feature(slice_patterns)]
fn main() {
let x: &[u32] = &[];
let &[[ref _a, ref _b..]..] = x; //~ ERROR refutable pattern
}

View File

@ -1,9 +0,0 @@
error[E0005]: refutable pattern in local binding: `&[]` not covered
--> $DIR/issue-26158.rs:5:9
|
LL | let &[[ref _a, ref _b..]..] = x;
| ^^^^^^^^^^^^^^^^^^^^^^^ pattern `&[]` not covered
error: aborting due to previous error
For more information about this error, try `rustc --explain E0005`.

View File

@ -1,11 +1,10 @@
// build-pass (FIXME(62277): could be check-pass?) // check-pass
#![allow(dead_code)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
fn check(list: &[u8]) { fn check(list: &[u8]) {
match list { match list {
&[] => {}, &[] => {},
&[_u1, _u2, ref _next..] => {}, &[_u1, _u2, ref _next @ ..] => {},
&[_u1] => {}, &[_u1] => {},
} }
} }

View File

@ -24,7 +24,7 @@ fn main() {
assert_eq!(d, "baz"); assert_eq!(d, "baz");
let out = bar("baz", "foo"); let out = bar("baz", "foo");
let [a, xs.., d] = out; let [a, xs @ .., d] = out;
assert_eq!(a, "baz"); assert_eq!(a, "baz");
assert_eq!(xs, ["foo", "foo"]); assert_eq!(xs, ["foo", "foo"]);
assert_eq!(d, "baz"); assert_eq!(d, "baz");

View File

@ -19,10 +19,10 @@ fn main() {
match [0, 1, 2] { match [0, 1, 2] {
[0] => {}, //~ ERROR pattern requires [0] => {}, //~ ERROR pattern requires
[0, 1, x..] => { [0, 1, x @ ..] => {
let a: [_; 1] = x; let a: [_; 1] = x;
} }
[0, 1, 2, 3, x..] => {} //~ ERROR pattern requires [0, 1, 2, 3, x @ ..] => {} //~ ERROR pattern requires
}; };
match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope

View File

@ -19,8 +19,8 @@ LL | [0] => {},
error[E0528]: pattern requires at least 4 elements but array has 3 error[E0528]: pattern requires at least 4 elements but array has 3
--> $DIR/match-vec-mismatch.rs:25:9 --> $DIR/match-vec-mismatch.rs:25:9
| |
LL | [0, 1, 2, 3, x..] => {} LL | [0, 1, 2, 3, x @ ..] => {}
| ^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements
error[E0282]: type annotations needed error[E0282]: type annotations needed
--> $DIR/match-vec-mismatch.rs:36:9 --> $DIR/match-vec-mismatch.rs:36:9

View File

@ -23,7 +23,7 @@ fn main() {
let x: Vec<char> = vec!['a', 'b', 'c']; let x: Vec<char> = vec!['a', 'b', 'c'];
let x: &[char] = &x; let x: &[char] = &x;
match *x { match *x {
['a', 'b', 'c', ref _tail..] => {} ['a', 'b', 'c', ref _tail @ ..] => {}
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
_ => {} _ => {}
} }

View File

@ -32,14 +32,14 @@ fn main() {
let vec = vec![Some(42), None, Some(21)]; let vec = vec![Some(42), None, Some(21)];
let vec: &[Option<isize>] = &vec; let vec: &[Option<isize>] = &vec;
match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
[Some(..), None, ref tail..] => {} [Some(..), None, ref tail @ ..] => {}
[Some(..), Some(..), ref tail..] => {} [Some(..), Some(..), ref tail @ ..] => {}
[None] => {} [None] => {}
} }
let vec = vec![1]; let vec = vec![1];
let vec: &[isize] = &vec; let vec: &[isize] = &vec;
match *vec { match *vec {
[_, ref tail..] => (), [_, ref tail @ ..] => (),
[] => () [] => ()
} }
let vec = vec![0.5f32]; let vec = vec![0.5f32];
@ -53,10 +53,10 @@ fn main() {
let vec = vec![Some(42), None, Some(21)]; let vec = vec![Some(42), None, Some(21)];
let vec: &[Option<isize>] = &vec; let vec: &[Option<isize>] = &vec;
match *vec { match *vec {
[Some(..), None, ref tail..] => {} [Some(..), None, ref tail @ ..] => {}
[Some(..), Some(..), ref tail..] => {} [Some(..), Some(..), ref tail @ ..] => {}
[None, None, ref tail..] => {} [None, None, ref tail @ ..] => {}
[None, Some(..), ref tail..] => {} [None, Some(..), ref tail @ ..] => {}
[Some(_)] => {} [Some(_)] => {}
[None] => {} [None] => {}
[] => {} [] => {}

View File

@ -77,7 +77,7 @@ fn vectors_with_nested_enums() {
[Enum::Second(true), Enum::First] => (), [Enum::Second(true), Enum::First] => (),
[Enum::Second(true), Enum::Second(true)] => (), [Enum::Second(true), Enum::Second(true)] => (),
[Enum::Second(false), _] => (), [Enum::Second(false), _] => (),
[_, _, ref tail.., _] => () [_, _, ref tail @ .., _] => ()
} }
} }

View File

@ -1,7 +1,13 @@
fn main() { fn main() {
let a = Vec::new(); let a: &[u8] = &[];
match a { match a {
[1, tail.., tail..] => {}, //~ ERROR: expected one of `,` or `@`, found `..` [1, tail @ .., tail @ ..] => {},
//~^ ERROR identifier `tail` is bound more than once in the same pattern
//~| ERROR subslice patterns are unstable
//~| ERROR subslice patterns are unstable
//~| ERROR `..` can only be used once per slice pattern
_ => () _ => ()
} }
} }
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types

View File

@ -1,8 +1,45 @@
error: expected one of `,` or `@`, found `..` error[E0416]: identifier `tail` is bound more than once in the same pattern
--> $DIR/match-vec-invalid.rs:4:25 --> $DIR/match-vec-invalid.rs:4:24
| |
LL | [1, tail.., tail..] => {}, LL | [1, tail @ .., tail @ ..] => {},
| ^^ expected one of `,` or `@` here | ^^^^ used in a pattern more than once
error: aborting due to previous error error[E0658]: subslice patterns are unstable
--> $DIR/match-vec-invalid.rs:4:13
|
LL | [1, tail @ .., tail @ ..] => {},
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0658]: subslice patterns are unstable
--> $DIR/match-vec-invalid.rs:4:24
|
LL | [1, tail @ .., tail @ ..] => {},
| ^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error: `..` can only be used once per slice pattern
--> $DIR/match-vec-invalid.rs:4:31
|
LL | [1, tail @ .., tail @ ..] => {},
| -- ^^ can only be used once per slice pattern
| |
| previously used here
error[E0308]: mismatched types
--> $DIR/match-vec-invalid.rs:13:30
|
LL | const RECOVERY_WITNESS: () = 0;
| ^ expected (), found integer
|
= note: expected type `()`
found type `{integer}`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0308, E0416, E0658.
For more information about an error, try `rustc --explain E0308`.

View File

@ -1,3 +1,9 @@
fn main() { fn main() {
struct Test(&'static u8, [u8; 0]);
let x = Test(&0, []);
let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[` let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
//~^ ERROR subslice patterns are unstable
} }
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types

View File

@ -1,8 +1,28 @@
error: expected one of `)`, `,`, or `@`, found `[` error: expected one of `)`, `,`, or `@`, found `[`
--> $DIR/pat-lt-bracket-6.rs:2:19 --> $DIR/pat-lt-bracket-6.rs:5:19
| |
LL | let Test(&desc[..]) = x; LL | let Test(&desc[..]) = x;
| ^ expected one of `)`, `,`, or `@` here | ^ expected one of `)`, `,`, or `@` here
error: aborting due to previous error error[E0658]: subslice patterns are unstable
--> $DIR/pat-lt-bracket-6.rs:5:20
|
LL | let Test(&desc[..]) = x;
| ^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
error[E0308]: mismatched types
--> $DIR/pat-lt-bracket-6.rs:9:30
|
LL | const RECOVERY_WITNESS: () = 0;
| ^ expected (), found integer
|
= note: expected type `()`
found type `{integer}`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.

View File

@ -1,3 +1,8 @@
fn main() { fn main() {
for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[` struct Thing(u8, [u8; 0]);
let foo = core::iter::empty();
for Thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
} }
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types

View File

@ -1,8 +1,18 @@
error: expected one of `)`, `,`, or `@`, found `[` error: expected one of `)`, `,`, or `@`, found `[`
--> $DIR/pat-lt-bracket-7.rs:2:16 --> $DIR/pat-lt-bracket-7.rs:5:16
| |
LL | for thing(x[]) in foo {} LL | for Thing(x[]) in foo {}
| ^ expected one of `)`, `,`, or `@` here | ^ expected one of `)`, `,`, or `@` here
error: aborting due to previous error error[E0308]: mismatched types
--> $DIR/pat-lt-bracket-7.rs:8:30
|
LL | const RECOVERY_WITNESS: () = 0;
| ^ expected (), found integer
|
= note: expected type `()`
found type `{integer}`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,6 +1,7 @@
// check-pass
fn main() { fn main() {
match (0, 1, 2) { match (0, 1, 2) {
(pat, ..,) => {} (pat, ..,) => {}
//~^ ERROR trailing comma is not permitted after `..`
} }
} }

View File

@ -1,8 +0,0 @@
error: trailing comma is not permitted after `..`
--> $DIR/pat-tuple-2.rs:3:17
|
LL | (pat, ..,) => {}
| ^ trailing comma is not permitted after `..`
error: aborting due to previous error

View File

@ -1,6 +1,6 @@
fn main() { fn main() {
match (0, 1, 2) { match (0, 1, 2) {
(.., pat, ..) => {} (.., pat, ..) => {}
//~^ ERROR `..` can only be used once per tuple or tuple struct pattern //~^ ERROR `..` can only be used once per tuple pattern
} }
} }

View File

@ -1,10 +1,10 @@
error: `..` can only be used once per tuple or tuple struct pattern error: `..` can only be used once per tuple pattern
--> $DIR/pat-tuple-3.rs:3:19 --> $DIR/pat-tuple-3.rs:3:19
| |
LL | (.., pat, ..) => {} LL | (.., pat, ..) => {}
| -- ^^ can only be used once per pattern | -- ^^ can only be used once per tuple pattern
| | | |
| previously present here | previously used here
error: aborting due to previous error error: aborting due to previous error

View File

@ -1,5 +1,11 @@
fn main() { fn main() {
const PAT: u8 = 0;
match 0 { match 0 {
(.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat` (.. PAT) => {}
//~^ ERROR `..X` range patterns are not supported
//~| ERROR exclusive range pattern syntax is experimental
} }
} }
const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types

View File

@ -1,8 +1,28 @@
error: expected one of `)` or `,`, found `pat` error: `..X` range patterns are not supported
--> $DIR/pat-tuple-4.rs:3:13 --> $DIR/pat-tuple-4.rs:5:10
| |
LL | (.. pat) => {} LL | (.. PAT) => {}
| ^^^ expected one of `)` or `,` here | ^^^^^^ help: try using the minimum value for the type: `MIN..PAT`
error: aborting due to previous error error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/pat-tuple-4.rs:5:10
|
LL | (.. PAT) => {}
| ^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/37854
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
error[E0308]: mismatched types
--> $DIR/pat-tuple-4.rs:11:30
|
LL | const RECOVERY_WITNESS: () = 0;
| ^ expected (), found integer
|
= note: expected type `()`
found type `{integer}`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.

View File

@ -1,5 +1,10 @@
fn main() { fn main() {
const PAT: u8 = 0;
match (0, 1) { match (0, 1) {
(pat ..) => {} //~ ERROR unexpected token: `)` (PAT ..) => {}
//~^ ERROR `X..` range patterns are not supported
//~| ERROR exclusive range pattern syntax is experimental
//~| ERROR mismatched types
} }
} }

View File

@ -1,8 +1,30 @@
error: unexpected token: `)` error: `X..` range patterns are not supported
--> $DIR/pat-tuple-5.rs:3:16 --> $DIR/pat-tuple-5.rs:5:10
| |
LL | (pat ..) => {} LL | (PAT ..) => {}
| ^ | ^^^^^^ help: try using the maximum value for the type: `PAT..MAX`
error: aborting due to previous error error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/pat-tuple-5.rs:5:10
|
LL | (PAT ..) => {}
| ^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/37854
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
error[E0308]: mismatched types
--> $DIR/pat-tuple-5.rs:5:10
|
LL | match (0, 1) {
| ------ this match expression has type `({integer}, {integer})`
LL | (PAT ..) => {}
| ^^^^^^ expected tuple, found u8
|
= note: expected type `({integer}, {integer})`
found type `u8`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.

View File

@ -0,0 +1,123 @@
// Here we test all kinds of range patterns in terms of parsing / recovery.
// We want to ensure that:
// 1. Things parse as they should.
// 2. Or at least we have parser recovery if they don't.
#![feature(exclusive_range_pattern)]
#![deny(ellipsis_inclusive_range_patterns)]
fn main() {}
const X: u8 = 0;
const Y: u8 = 3;
fn exclusive_from_to() {
if let 0..3 = 0 {} // OK.
if let 0..Y = 0 {} // OK.
if let X..3 = 0 {} // OK.
if let X..Y = 0 {} // OK.
if let true..Y = 0 {} //~ ERROR only char and numeric types
if let X..true = 0 {} //~ ERROR only char and numeric types
if let .0..Y = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
if let X.. .0 = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
}
fn inclusive_from_to() {
if let 0..=3 = 0 {} // OK.
if let 0..=Y = 0 {} // OK.
if let X..=3 = 0 {} // OK.
if let X..=Y = 0 {} // OK.
if let true..=Y = 0 {} //~ ERROR only char and numeric types
if let X..=true = 0 {} //~ ERROR only char and numeric types
if let .0..=Y = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
if let X..=.0 = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
}
fn inclusive2_from_to() {
if let 0...3 = 0 {} //~ ERROR `...` range patterns are deprecated
if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
if let true...Y = 0 {} //~ ERROR only char and numeric types
//~^ ERROR `...` range patterns are deprecated
if let X...true = 0 {} //~ ERROR only char and numeric types
//~^ ERROR `...` range patterns are deprecated
if let .0...Y = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
//~| ERROR `...` range patterns are deprecated
if let X... .0 = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
//~| ERROR `...` range patterns are deprecated
}
fn exclusive_from() {
if let 0.. = 0 {} //~ ERROR `X..` range patterns are not supported
if let X.. = 0 {} //~ ERROR `X..` range patterns are not supported
if let true.. = 0 {} //~ ERROR `X..` range patterns are not supported
//~^ ERROR only char and numeric types
if let .0.. = 0 {} //~ ERROR `X..` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
}
fn inclusive_from() {
if let 0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
if let X..= = 0 {} //~ ERROR `X..=` range patterns are not supported
if let true..= = 0 {} //~ ERROR `X..=` range patterns are not supported
//~| ERROR only char and numeric types
if let .0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
}
fn inclusive2_from() {
if let 0... = 0 {} //~ ERROR `X...` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
if let X... = 0 {} //~ ERROR `X...` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
if let true... = 0 {} //~ ERROR `X...` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
//~| ERROR only char and numeric types
if let .0... = 0 {} //~ ERROR `X...` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR `...` range patterns are deprecated
//~| ERROR mismatched types
}
fn exclusive_to() {
if let ..0 = 0 {} //~ ERROR `..X` range patterns are not supported
if let ..Y = 0 {} //~ ERROR `..X` range patterns are not supported
if let ..true = 0 {} //~ ERROR `..X` range patterns are not supported
//~| ERROR only char and numeric types
if let .. .0 = 0 {} //~ ERROR `..X` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
}
fn inclusive_to() {
if let ..=3 = 0 {} //~ ERROR `..=X` range patterns are not supported
if let ..=Y = 0 {} //~ ERROR `..=X` range patterns are not supported
if let ..=true = 0 {} //~ ERROR `..=X` range patterns are not supported
//~| ERROR only char and numeric types
if let ..=.0 = 0 {} //~ ERROR `..=X` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR mismatched types
}
fn inclusive2_to() {
if let ...3 = 0 {} //~ ERROR `...X` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
if let ...Y = 0 {} //~ ERROR `...X` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
if let ...true = 0 {} //~ ERROR `...X` range patterns are not supported
//~^ ERROR `...` range patterns are deprecated
//~| ERROR only char and numeric types
if let ....3 = 0 {} //~ ERROR `...X` range patterns are not supported
//~^ ERROR float literals must have an integer part
//~| ERROR `...` range patterns are deprecated
//~| ERROR mismatched types
}

View File

@ -0,0 +1,538 @@
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:21:12
|
LL | if let .0..Y = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:23:16
|
LL | if let X.. .0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:34:12
|
LL | if let .0..=Y = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:36:16
|
LL | if let X..=.0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:49:12
|
LL | if let .0...Y = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:52:17
|
LL | if let X... .0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `X..` range patterns are not supported
--> $DIR/recover-range-pats.rs:58:12
|
LL | if let 0.. = 0 {}
| ^^^ help: try using the maximum value for the type: `0..MAX`
error: `X..` range patterns are not supported
--> $DIR/recover-range-pats.rs:59:12
|
LL | if let X.. = 0 {}
| ^^^ help: try using the maximum value for the type: `X..MAX`
error: `X..` range patterns are not supported
--> $DIR/recover-range-pats.rs:60:12
|
LL | if let true.. = 0 {}
| ^^^^^^ help: try using the maximum value for the type: `true..MAX`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:62:12
|
LL | if let .0.. = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `X..` range patterns are not supported
--> $DIR/recover-range-pats.rs:62:12
|
LL | if let .0.. = 0 {}
| ^^^^ help: try using the maximum value for the type: `0.0..MAX`
error: `X..=` range patterns are not supported
--> $DIR/recover-range-pats.rs:68:12
|
LL | if let 0..= = 0 {}
| ^^^^ help: try using the maximum value for the type: `0..=MAX`
error: `X..=` range patterns are not supported
--> $DIR/recover-range-pats.rs:69:12
|
LL | if let X..= = 0 {}
| ^^^^ help: try using the maximum value for the type: `X..=MAX`
error: `X..=` range patterns are not supported
--> $DIR/recover-range-pats.rs:70:12
|
LL | if let true..= = 0 {}
| ^^^^^^^ help: try using the maximum value for the type: `true..=MAX`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:72:12
|
LL | if let .0..= = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `X..=` range patterns are not supported
--> $DIR/recover-range-pats.rs:72:12
|
LL | if let .0..= = 0 {}
| ^^^^^ help: try using the maximum value for the type: `0.0..=MAX`
error: `X...` range patterns are not supported
--> $DIR/recover-range-pats.rs:78:12
|
LL | if let 0... = 0 {}
| ^^^^ help: try using the maximum value for the type: `0...MAX`
error: `X...` range patterns are not supported
--> $DIR/recover-range-pats.rs:80:12
|
LL | if let X... = 0 {}
| ^^^^ help: try using the maximum value for the type: `X...MAX`
error: `X...` range patterns are not supported
--> $DIR/recover-range-pats.rs:82:12
|
LL | if let true... = 0 {}
| ^^^^^^^ help: try using the maximum value for the type: `true...MAX`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:85:12
|
LL | if let .0... = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `X...` range patterns are not supported
--> $DIR/recover-range-pats.rs:85:12
|
LL | if let .0... = 0 {}
| ^^^^^ help: try using the maximum value for the type: `0.0...MAX`
error: `..X` range patterns are not supported
--> $DIR/recover-range-pats.rs:92:12
|
LL | if let ..0 = 0 {}
| ^^^ help: try using the minimum value for the type: `MIN..0`
error: `..X` range patterns are not supported
--> $DIR/recover-range-pats.rs:93:12
|
LL | if let ..Y = 0 {}
| ^^^ help: try using the minimum value for the type: `MIN..Y`
error: `..X` range patterns are not supported
--> $DIR/recover-range-pats.rs:94:12
|
LL | if let ..true = 0 {}
| ^^^^^^ help: try using the minimum value for the type: `MIN..true`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:96:15
|
LL | if let .. .0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `..X` range patterns are not supported
--> $DIR/recover-range-pats.rs:96:12
|
LL | if let .. .0 = 0 {}
| ^^^^^ help: try using the minimum value for the type: `MIN..0.0`
error: `..=X` range patterns are not supported
--> $DIR/recover-range-pats.rs:102:12
|
LL | if let ..=3 = 0 {}
| ^^^^ help: try using the minimum value for the type: `MIN..=3`
error: `..=X` range patterns are not supported
--> $DIR/recover-range-pats.rs:103:12
|
LL | if let ..=Y = 0 {}
| ^^^^ help: try using the minimum value for the type: `MIN..=Y`
error: `..=X` range patterns are not supported
--> $DIR/recover-range-pats.rs:104:12
|
LL | if let ..=true = 0 {}
| ^^^^^^^ help: try using the minimum value for the type: `MIN..=true`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:106:15
|
LL | if let ..=.0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: `..=X` range patterns are not supported
--> $DIR/recover-range-pats.rs:106:12
|
LL | if let ..=.0 = 0 {}
| ^^^^^ help: try using the minimum value for the type: `MIN..=0.0`
error: `...X` range patterns are not supported
--> $DIR/recover-range-pats.rs:112:12
|
LL | if let ...3 = 0 {}
| ^^^^ help: try using the minimum value for the type: `MIN...3`
error: `...X` range patterns are not supported
--> $DIR/recover-range-pats.rs:114:12
|
LL | if let ...Y = 0 {}
| ^^^^ help: try using the minimum value for the type: `MIN...Y`
error: `...X` range patterns are not supported
--> $DIR/recover-range-pats.rs:116:12
|
LL | if let ...true = 0 {}
| ^^^^^^^ help: try using the minimum value for the type: `MIN...true`
error: float literals must have an integer part
--> $DIR/recover-range-pats.rs:119:15
|
LL | if let ....3 = 0 {}
| ^^ help: must have an integer part: `0.3`
error: `...X` range patterns are not supported
--> $DIR/recover-range-pats.rs:119:12
|
LL | if let ....3 = 0 {}
| ^^^^^ help: try using the minimum value for the type: `MIN...0.3`
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:41:13
|
LL | if let 0...3 = 0 {}
| ^^^ help: use `..=` for an inclusive range
|
note: lint level defined here
--> $DIR/recover-range-pats.rs:7:9
|
LL | #![deny(ellipsis_inclusive_range_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:42:13
|
LL | if let 0...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:43:13
|
LL | if let X...3 = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:44:13
|
LL | if let X...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:45:16
|
LL | if let true...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:47:13
|
LL | if let X...true = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:49:14
|
LL | if let .0...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:52:13
|
LL | if let X... .0 = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:78:13
|
LL | if let 0... = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:80:13
|
LL | if let X... = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:82:16
|
LL | if let true... = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:85:14
|
LL | if let .0... = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:112:12
|
LL | if let ...3 = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:114:12
|
LL | if let ...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:116:12
|
LL | if let ...true = 0 {}
| ^^^ help: use `..=` for an inclusive range
error: `...` range patterns are deprecated
--> $DIR/recover-range-pats.rs:119:12
|
LL | if let ....3 = 0 {}
| ^^^ help: use `..=` for an inclusive range
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:19:12
|
LL | if let true..Y = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: u8
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:20:15
|
LL | if let X..true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: u8
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:21:12
|
LL | if let .0..Y = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:23:12
|
LL | if let X.. .0 = 0 {}
| ^^^^^^ expected integer, found floating-point number
|
= note: expected type `u8`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:32:12
|
LL | if let true..=Y = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: u8
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:33:16
|
LL | if let X..=true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: u8
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:34:12
|
LL | if let .0..=Y = 0 {}
| ^^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:36:12
|
LL | if let X..=.0 = 0 {}
| ^^^^^^ expected integer, found floating-point number
|
= note: expected type `u8`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:45:12
|
LL | if let true...Y = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: u8
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:47:16
|
LL | if let X...true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: u8
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:49:12
|
LL | if let .0...Y = 0 {}
| ^^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:52:12
|
LL | if let X... .0 = 0 {}
| ^^^^^^^ expected integer, found floating-point number
|
= note: expected type `u8`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:60:12
|
LL | if let true.. = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: [type error]
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:62:12
|
LL | if let .0.. = 0 {}
| ^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:70:12
|
LL | if let true..= = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: [type error]
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:72:12
|
LL | if let .0..= = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:82:12
|
LL | if let true... = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: bool
= note: end type: [type error]
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:85:12
|
LL | if let .0... = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:94:14
|
LL | if let ..true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: [type error]
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:96:12
|
LL | if let .. .0 = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:104:15
|
LL | if let ..=true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: [type error]
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:106:12
|
LL | if let ..=.0 = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error[E0029]: only char and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:116:15
|
LL | if let ...true = 0 {}
| ^^^^ ranges require char or numeric types
|
= note: start type: [type error]
= note: end type: bool
error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:119:12
|
LL | if let ....3 = 0 {}
| ^^^^^ expected integer, found floating-point number
|
= note: expected type `{integer}`
found type `{float}`
error: aborting due to 76 previous errors
Some errors have detailed explanations: E0029, E0308.
For more information about an error, try `rustc --explain E0029`.

View File

@ -1,12 +1,12 @@
// NOTE: This doesn't recover anymore.
fn main() { fn main() {
let x = (1, 2, 3, 4); let x = (1, 2, 3, 4);
match x { match x {
(1, .., 4) => {} (1, .., 4) => {}
(1, .=., 4) => { let _: usize = ""; } (1, .=., 4) => { let _: usize = ""; }
//~^ ERROR expected pattern, found `.` //~^ ERROR expected pattern, found `.`
//~| ERROR mismatched types
(.=., 4) => {} (.=., 4) => {}
//~^ ERROR expected pattern, found `.`
(1, 2, 3, 4) => {} (1, 2, 3, 4) => {}
} }
} }

View File

@ -1,24 +1,8 @@
error: expected pattern, found `.` error: expected pattern, found `.`
--> $DIR/recover-tuple-pat.rs:5:13 --> $DIR/recover-tuple-pat.rs:7:13
| |
LL | (1, .=., 4) => { let _: usize = ""; } LL | (1, .=., 4) => { let _: usize = ""; }
| ^ expected pattern | ^ expected pattern
error: expected pattern, found `.` error: aborting due to previous error
--> $DIR/recover-tuple-pat.rs:8:10
|
LL | (.=., 4) => {}
| ^ expected pattern
error[E0308]: mismatched types
--> $DIR/recover-tuple-pat.rs:5:41
|
LL | (1, .=., 4) => { let _: usize = ""; }
| ^^ expected usize, found reference
|
= note: expected type `usize`
found type `&'static str`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -4,6 +4,6 @@ pub fn main() {
let sl: &[u8] = b"foo"; let sl: &[u8] = b"foo";
match sl { //~ ERROR non-exhaustive patterns match sl { //~ ERROR non-exhaustive patterns
[first, remainder..] => {}, [first, remainder @ ..] => {},
}; };
} }

View File

@ -5,7 +5,7 @@ fn slice_pat() {
let sl: &[u8] = b"foo"; let sl: &[u8] = b"foo";
match sl { match sl {
[first, remainder..] => { [first, remainder @ ..] => {
let _: &u8 = first; let _: &u8 = first;
assert_eq!(first, &b'f'); assert_eq!(first, &b'f');
assert_eq!(remainder, b"oo"); assert_eq!(remainder, b"oo");

View File

@ -25,7 +25,7 @@ pub fn main() {
let (_, _,) = (1, 1,); let (_, _,) = (1, 1,);
let [_, _,] = [1, 1,]; let [_, _,] = [1, 1,];
let [_, _, .., _,] = [1, 1, 1, 1,]; let [_, _, .., _,] = [1, 1, 1, 1,];
let [_, _, _.., _,] = [1, 1, 1, 1,]; let [_, _, _, ..,] = [1, 1, 1, 1,];
let x: Foo<isize,> = Foo::<isize,>(1); let x: Foo<isize,> = Foo::<isize,>(1);