diff --git a/src/doc/unstable-book/src/language-features/slice-patterns.md b/src/doc/unstable-book/src/language-features/slice-patterns.md index 00c81f03ba173..cdb74495884a8 100644 --- a/src/doc/unstable-book/src/language-features/slice-patterns.md +++ b/src/doc/unstable-book/src/language-features/slice-patterns.md @@ -17,7 +17,7 @@ matched against that pattern. For example: fn is_symmetric(list: &[u32]) -> bool { match list { &[] | &[_] => true, - &[x, ref inside.., y] if x == y => is_symmetric(inside), + &[x, ref inside @ .., y] if x == y => is_symmetric(inside), &[..] => false, } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 639994ed14d86..bc2c835e21050 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -58,6 +58,7 @@ use std::mem; use smallvec::SmallVec; use syntax::attr; use syntax::ast; +use syntax::ptr::P as AstP; use syntax::ast::*; use syntax::errors; use syntax::ext::hygiene::ExpnId; @@ -468,7 +469,7 @@ impl<'a> LoweringContext<'a> { fn visit_pat(&mut self, p: &'tcx Pat) { match p.node { // Doesn't generate a HIR node - PatKind::Paren(..) => {}, + PatKind::Paren(..) | PatKind::Rest => {}, _ => { if let Some(owner) = self.hir_id_owner { self.lctx.lower_node_id_with_owner(p.id, owner); @@ -1157,7 +1158,7 @@ impl<'a> LoweringContext<'a> { &mut self, capture_clause: CaptureBy, closure_node_id: NodeId, - ret_ty: Option>, + ret_ty: Option>, span: Span, body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, ) -> hir::ExprKind { @@ -4172,33 +4173,11 @@ impl<'a> LoweringContext<'a> { let node = match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, ident, ref sub) => { - 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, - 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)], - }), - )), - } + let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x)); + self.lower_pat_ident(p, binding_mode, ident, lower_sub) } 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( p.id, &None, @@ -4206,11 +4185,8 @@ impl<'a> LoweringContext<'a> { ParamMode::Optional, ImplTraitContext::disallowed(), ); - hir::PatKind::TupleStruct( - qpath, - pats.iter().map(|x| self.lower_pat(x)).collect(), - ddpos, - ) + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); + hir::PatKind::TupleStruct(qpath, pats, ddpos) } PatKind::Path(ref qself, ref path) => { let qpath = self.lower_qpath( @@ -4247,8 +4223,9 @@ impl<'a> LoweringContext<'a> { .collect(); hir::PatKind::Struct(qpath, fs, etc) } - PatKind::Tuple(ref elts, ddpos) => { - hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos) + PatKind::Tuple(ref pats) => { + 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::Ref(ref inner, mutbl) => { @@ -4259,15 +4236,138 @@ impl<'a> LoweringContext<'a> { P(self.lower_expr(e2)), self.lower_range_end(end), ), - PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice( - before.iter().map(|x| self.lower_pat(x)).collect(), - slice.as_ref().map(|x| self.lower_pat(x)), - after.iter().map(|x| self.lower_pat(x)).collect(), - ), + PatKind::Slice(ref pats) => self.lower_pat_slice(pats), + PatKind::Rest => { + // If we reach here the `..` pattern is not semantically allowed. + self.ban_illegal_rest_pat(p.span) + } PatKind::Paren(ref inner) => return self.lower_pat(inner), PatKind::Mac(_) => panic!("Shouldn't exist here"), }; + self.pat_with_node_id_of(p, node) + } + + fn lower_pat_tuple( + &mut self, + pats: &[AstP], + ctx: &str, + ) -> (HirVec>, Option) { + 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]) -> 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>, + ) -> 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 { + 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 { P(hir::Pat { hir_id: self.lower_node_id(p.id), node, @@ -4275,6 +4375,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 { match *e { RangeEnd::Included(_) => hir::RangeEnd::Included, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 1baeda41498ed..f759ec7f219d1 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -162,7 +162,7 @@ pub enum PatternKind<'tcx> { /// Matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. - /// e.g., `&[ref xs..]`. + /// e.g., `&[ref xs @ ..]`. Slice { prefix: Vec>, slice: Option>, diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index b550029d9786d..473ba21c77b6d 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -287,7 +287,7 @@ impl<'a> AstValidator<'a> { // ``` fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { match expr.node { - ExprKind::Lit(..) => {} + ExprKind::Lit(..) | ExprKind::Err => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 4a4c6799c005e..80fcb45d0b9bc 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -105,20 +105,34 @@ impl TargetDataLayout { let mut dl = TargetDataLayout::default(); let mut i128_align_src = 64; for spec in target.data_layout.split('-') { - match spec.split(':').collect::>()[..] { + let spec_parts = spec.split(':').collect::>(); + + match &*spec_parts { ["e"] => dl.endian = Endian::Little, ["E"] => dl.endian = Endian::Big, [p] if p.starts_with("P") => { dl.instruction_address_space = parse_address_space(&p[1..], "P")? } - ["a", ref a..] => dl.aggregate_align = align(a, "a")?, - ["f32", ref a..] => dl.f32_align = align(a, "f32")?, - ["f64", ref a..] => dl.f64_align = align(a, "f64")?, - [p @ "p", s, ref a..] | [p @ "p0", s, ref a..] => { + // FIXME: Ping cfg(bootstrap) -- Use `ref a @ ..` with new bootstrap compiler. + ["a", ..] => { + let a = &spec_parts[1..]; // FIXME inline into pattern. + 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_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::() { Ok(bits) => bits, Err(_) => { @@ -142,7 +156,8 @@ impl TargetDataLayout { 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 a = align(a, s)?; if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 3f0604b84b7d7..defa6fe4ce15e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -196,7 +196,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rhs_ty = self.check_expr(end); // 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 rhs_compat = numeric_or_char(rhs_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 36977b878dd7e..66c726b2485d1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); 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 { err.span_label(*variant_span, ""); } diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 19d5e8b3e8447..b4c856921198e 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -3497,8 +3497,8 @@ Example of erroneous code: let r = &[1, 2]; match r { - &[a, b, c, rest..] => { // error: pattern requires at least 3 - // elements but array has 2 + &[a, b, c, rest @ ..] => { // error: pattern requires at least 3 + // elements but array has 2 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]; match r { - &[a, b, c, rest..] => { // ok! + &[a, b, c, rest @ ..] => { // ok! // prints `a=1, b=2, c=3 rest=[4, 5]` println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index dbfad3ef7f4de..a7453f4f9dac2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -519,21 +519,28 @@ impl fmt::Debug for Pat { } impl Pat { + /// Attempt reparsing the pattern as a type. + /// This is intended for use by diagnostics. pub(super) fn to_ty(&self) -> Option> { let node = match &self.node { + // In a type expression `_` is an inference variable. 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) => { TyKind::Path(None, Path::from_ident(*ident)) } PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.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 .to_ty() .map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?, - PatKind::Slice(pats, None, _) if pats.len() == 1 => { - pats[0].to_ty().map(TyKind::Slice)? - } - PatKind::Tuple(pats, None) => { + // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array, + // when `P` can be reparsed as a type `T`. + PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?, + // 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()); // FIXME(#48994) - could just be collected into an Option for pat in pats { @@ -559,19 +566,15 @@ impl Pat { return false; } - match self.node { - PatKind::Ident(_, _, Some(ref p)) => p.walk(it), - PatKind::Struct(_, ref fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), - PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { + match &self.node { + PatKind::Ident(_, _, Some(p)) => p.walk(it), + PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)), + PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => { s.iter().all(|p| p.walk(it)) } - PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref 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::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it), PatKind::Wild + | PatKind::Rest | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) @@ -579,6 +582,14 @@ impl Pat { | 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 @@ -630,9 +641,7 @@ pub enum PatKind { Struct(Path, Vec>, /* recovered */ bool), /// A tuple struct/variant pattern (`Variant(x, y, .., z)`). - /// If the `..` pattern fragment is present, then `Option` denotes its position. - /// `0 <= position <= subpats.len()`. - TupleStruct(Path, Vec>, Option), + TupleStruct(Path, Vec>), /// A possibly qualified path pattern. /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants @@ -641,9 +650,7 @@ pub enum PatKind { Path(Option, Path), /// A tuple pattern (`(a, b)`). - /// If the `..` pattern fragment is present, then `Option` denotes its position. - /// `0 <= position <= subpats.len()`. - Tuple(Vec>, Option), + Tuple(Vec>), /// A `box` pattern. Box(P), @@ -657,9 +664,22 @@ pub enum PatKind { /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`). Range(P, P, Spanned), - /// `[a, b, ..i, y, z]` is represented as: - /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` - Slice(Vec>, Option>, Vec>), + /// A slice pattern `[a, b, c]`. + Slice(Vec>), + + /// 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)`). Paren(P), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index baf1031de1e7c..528b27d6153df 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -840,14 +840,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_tuple_struct(&self, span: Span, path: ast::Path, subpats: Vec>) -> P { - self.pat(span, PatKind::TupleStruct(path, subpats, None)) + self.pat(span, PatKind::TupleStruct(path, subpats)) } fn pat_struct(&self, span: Span, path: ast::Path, field_pats: Vec>) -> P { self.pat(span, PatKind::Struct(path, field_pats, false)) } fn pat_tuple(&self, span: Span, pats: Vec>) -> P { - self.pat(span, PatKind::Tuple(pats, None)) + self.pat(span, PatKind::Tuple(pats)) } fn pat_some(&self, span: Span, pat: P) -> P { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 72184b0bd6400..384474b08f6ee 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -2151,11 +2151,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match pattern.node { - PatKind::Slice(_, Some(ref subslice), _) => { - gate_feature_post!(&self, slice_patterns, - subslice.span, - "syntax for subslices in slice patterns is not yet stabilized"); + match &pattern.node { + PatKind::Slice(pats) => { + for pat in &*pats { + let span = pat.span; + 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(..) => { gate_feature_post!(&self, box_patterns, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index dc656222fbc10..86525406718b6 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -1020,15 +1020,15 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { let Pat { id, node, span } = pat.deref_mut(); vis.visit_id(id); match node { - PatKind::Wild => {} + PatKind::Wild | PatKind::Rest => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); } PatKind::Lit(e) => vis.visit_expr(e), - PatKind::TupleStruct(path, pats, _ddpos) => { + PatKind::TupleStruct(path, elems) => { vis.visit_path(path); - visit_vec(pats, |pat| vis.visit_pat(pat)); + visit_vec(elems, |elem| vis.visit_pat(elem)); } PatKind::Path(qself, path) => { vis.visit_qself(qself); @@ -1043,7 +1043,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { 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::Ref(inner, _mutbl) => vis.visit_pat(inner), PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => { @@ -1051,11 +1051,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { vis.visit_expr(e2); vis.visit_span(span); } - PatKind::Slice(before, slice, after) => { - 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::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)), PatKind::Paren(inner) => vis.visit_pat(inner), PatKind::Mac(mac) => vis.visit_mac(mac), } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a5b6f0d683629..8f8ed4111808d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -890,14 +890,13 @@ impl<'a> Parser<'a> { /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_end(&mut self, - ket: &TokenKind, - sep: SeqSep, - f: F) - -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + pub fn parse_seq_to_end( + &mut self, + ket: &TokenKind, + sep: SeqSep, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, Vec> { + let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; if !recovered { self.bump(); } @@ -907,39 +906,39 @@ impl<'a> Parser<'a> { /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_before_end( + pub fn parse_seq_to_before_end( &mut self, ket: &TokenKind, sep: SeqSep, - f: F, - ) -> PResult<'a, (Vec, bool)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool, bool)> { self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } - crate fn parse_seq_to_before_tokens( + 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( &mut self, kets: &[&TokenKind], sep: SeqSep, expect: TokenExpectType, - mut f: F, - ) -> PResult<'a, (Vec, bool /* recovered */)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> - { + mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool /* trailing */, bool /* recovered */)> { let mut first = true; let mut recovered = false; + let mut trailing = false; let mut v = vec![]; - while !kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { - match self.token.kind { - token::CloseDelim(..) | token::Eof => break, - _ => {} - }; + while !self.expect_any_with_type(kets, expect) { + if let token::CloseDelim(..) | token::Eof = self.token.kind { + break + } if let Some(ref t) = sep.sep { if first { first = false; @@ -973,12 +972,8 @@ impl<'a> Parser<'a> { } } } - if sep.trailing_sep_allowed && kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) { + if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { + trailing = true; break; } @@ -986,27 +981,45 @@ impl<'a> Parser<'a> { v.push(t); } - Ok((v, recovered)) + Ok((v, trailing, recovered)) } /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - fn parse_unspanned_seq( + fn parse_unspanned_seq( &mut self, bra: &TokenKind, ket: &TokenKind, sep: SeqSep, - f: F, - ) -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { 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 { self.eat(ket); } - Ok(result) + Ok((result, trailing)) + } + + fn parse_delim_comma_seq( + &mut self, + delim: DelimToken, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { + self.parse_unspanned_seq( + &token::OpenDelim(delim), + &token::CloseDelim(delim), + SeqSep::trailing_allowed(token::Comma), + f, + ) + } + + fn parse_paren_comma_seq( + &mut self, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { + self.parse_delim_comma_seq(token::Paren, f) } /// Advance the parser by one token @@ -1804,15 +1817,7 @@ impl<'a> Parser<'a> { AngleBracketedArgs { args, constraints, span }.into() } else { // `(T, U) -> R` - self.bump(); // `(` - 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 (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; let span = lo.to(self.prev_span); let output = if self.eat(&token::RArrow) { Some(self.parse_ty_common(false, false, false)?) @@ -2516,12 +2521,7 @@ impl<'a> Parser<'a> { Ok(match self.token.kind { token::OpenDelim(token::Paren) => { // Method call `expr.f()` - let mut args = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - )?; + let mut args = self.parse_paren_expr_seq()?; args.insert(0, self_arg); let span = lo.to(self.prev_span); @@ -2606,12 +2606,7 @@ impl<'a> Parser<'a> { match self.token.kind { // expr(...) token::OpenDelim(token::Paren) => { - let seq = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - ).map(|es| { + let seq = self.parse_paren_expr_seq().map(|es| { let nd = self.mk_call(e, es); let hi = self.prev_span; self.mk_expr(lo.to(hi), nd, ThinVec::new()) @@ -2635,6 +2630,10 @@ impl<'a> Parser<'a> { return Ok(e); } + fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { + self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r) + } + crate fn process_potential_macro_variable(&mut self) { self.token = match self.token.kind { 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>, Option, 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>, Option, 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>, Option>, Vec>)> { - 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( &mut self, 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 - // something more complex like range patterns + /// Is the current token suitable as the start of a range patterns end? + 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 { self.look_ahead(1, |t| match t.kind { token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), - // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the - // range pattern branch - token::DotDot => None, - _ => Some(true), - }).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind { - token::Comma | token::CloseDelim(token::Bracket) => true, - _ => false, - })) + token::DotDotDot | token::DotDotEq | token::DotDot | + token::ModSep | token::Not => false, + _ => true, + }) + } + + /// Parse and throw away a parentesized comma separated + /// 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 @@ -3876,7 +3773,7 @@ impl<'a> Parser<'a> { // later. let comma_span = self.token.span; 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 // to advance to the end of the comma-sequence so we know // the span to suggest parenthesizing @@ -3908,6 +3805,53 @@ impl<'a> Parser<'a> { 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> { + 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 /// allowed). fn parse_pat_with_range_pat( @@ -3934,20 +3878,41 @@ impl<'a> Parser<'a> { pat = PatKind::Ref(subpat, mutbl); } token::OpenDelim(token::Paren) => { - // Parse (pat,pat,pat,...) as tuple pattern - let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?; - pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma { + // Parse a tuple or parenthesis pattern. + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + + // 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()) } else { - PatKind::Tuple(fields, ddpos) + PatKind::Tuple(fields) }; } 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(); + pat = if self.is_pat_range_end_start() { + // Parse `..42` for recovery. + self.parse_pat_range_to(RangeEnd::Excluded, "..")? + } else { + // A rest pattern `..`. + PatKind::Rest + }; + } + token::DotDotEq => { + // Parse `..=42` for recovery. self.bump(); - let (before, slice, after) = self.parse_pat_vec_elements()?; - self.expect(&token::CloseDelim(token::Bracket))?; - pat = PatKind::Slice(before, slice, after); + 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 != &, &&, (, [ _ => if self.eat_keyword(kw::Underscore) { @@ -4004,10 +3969,10 @@ impl<'a> Parser<'a> { pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDotEq | token::DotDot => { - let end_kind = match self.token.kind { - token::DotDot => RangeEnd::Excluded, - token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), - token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), + let (end_kind, form) = match self.token.kind { + token::DotDot => (RangeEnd::Excluded, ".."), + token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."), + token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="), _ => panic!("can only parse `..`/`...`/`..=` for ranges \ (checked above)"), }; @@ -4016,9 +3981,8 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_span); let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); - let end = self.parse_pat_range_end()?; - let op = Spanned { span: op_span, node: end_kind }; - pat = PatKind::Range(begin, end, op); + let end = self.parse_pat_range_end_opt(&begin, form)?; + pat = PatKind::Range(begin, end, respan(op_span, end_kind)); } token::OpenDelim(token::Brace) => { if qself.is_some() { @@ -4045,8 +4009,8 @@ impl<'a> Parser<'a> { return Err(err); } // Parse tuple struct or enum pattern - let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; - pat = PatKind::TupleStruct(path, fields, ddpos) + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?; + pat = PatKind::TupleStruct(path, fields) } _ => pat = PatKind::Path(qself, path), } @@ -4057,19 +4021,18 @@ impl<'a> Parser<'a> { let op_span = self.token.span; if self.check(&token::DotDot) || self.check(&token::DotDotEq) || self.check(&token::DotDotDot) { - let end_kind = if self.eat(&token::DotDotDot) { - RangeEnd::Included(RangeSyntax::DotDotDot) + let (end_kind, form) = if self.eat(&token::DotDotDot) { + (RangeEnd::Included(RangeSyntax::DotDotDot), "...") } else if self.eat(&token::DotDotEq) { - RangeEnd::Included(RangeSyntax::DotDotEq) + (RangeEnd::Included(RangeSyntax::DotDotEq), "..=") } else if self.eat(&token::DotDot) { - RangeEnd::Excluded + (RangeEnd::Excluded, "..") } else { panic!("impossible case: we already matched \ on a range-operator token") }; - let end = self.parse_pat_range_end()?; - let op = Spanned { span: op_span, node: end_kind }; - pat = PatKind::Range(begin, end, op); + let end = self.parse_pat_range_end_opt(&begin, form)?; + pat = PatKind::Range(begin, end, respan(op_span, end_kind)) } else { 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) -> PResult<'a, (Vec , bool)> { - self.expect(&token::OpenDelim(token::Paren))?; - let sp = self.token.span; let mut c_variadic = false; - let (args, recovered): (Vec>, bool) = - self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| { - let do_not_enforce_named_arguments_for_c_variadic = - |token: &token::Token| -> bool { - 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)))) + let (args, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { + let do_not_enforce_named_arguments_for_c_variadic = + |token: &token::Token| -> bool { + 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)))) } - )?; - - if !recovered { - self.eat(&token::CloseDelim(token::Paren)); - } + } + })?; let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); @@ -5573,7 +5525,7 @@ impl<'a> Parser<'a> { (vec![self_arg], false) } else if self.eat(&token::Comma) { 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)?; fn_inputs.append(&mut input); (fn_inputs, recovered) @@ -5584,7 +5536,9 @@ impl<'a> Parser<'a> { } } } 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 { @@ -6185,26 +6139,20 @@ impl<'a> Parser<'a> { fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec> { // This is the case where we find `struct Foo(T) where T: Copy;` // Unit like structs are handled in parse_item_struct function - let fields = self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| { - let attrs = p.parse_outer_attributes()?; - let lo = p.token.span; - let vis = p.parse_visibility(true)?; - let ty = p.parse_ty()?; - Ok(StructField { - span: lo.to(ty.span), - vis, - ident: None, - id: ast::DUMMY_NODE_ID, - ty, - attrs, - }) - })?; - - Ok(fields) + self.parse_paren_comma_seq(|p| { + let attrs = p.parse_outer_attributes()?; + let lo = p.token.span; + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; + Ok(StructField { + span: lo.to(ty.span), + vis, + ident: None, + id: ast::DUMMY_NODE_ID, + ty, + attrs, + }) + }).map(|(r, _)| r) } /// Parses a structure field declaration. @@ -7786,11 +7734,8 @@ impl<'a> Parser<'a> { /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] /// ``` fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { - self.parse_unspanned_seq(&token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::trailing_allowed(token::Comma), |this| { - Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID)) - }) + self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID))) + .map(|(r, _)| r) } fn parse_rename(&mut self) -> PResult<'a, Option> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 16e0bace92584..36cd656f7277e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2369,22 +2369,10 @@ impl<'a> State<'a> { self.print_pat(p); } } - PatKind::TupleStruct(ref path, ref elts, ddpos) => { + PatKind::TupleStruct(ref path, ref elts) => { self.print_path(path, true, 0); self.popen(); - if let Some(ddpos) = ddpos { - 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.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.pclose(); } PatKind::Path(None, ref path) => { @@ -2416,23 +2404,11 @@ impl<'a> State<'a> { self.s.space(); self.s.word("}"); } - PatKind::Tuple(ref elts, ddpos) => { + PatKind::Tuple(ref elts) => { self.popen(); - if let Some(ddpos) = ddpos { - 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)); - if elts.len() == 1 { - self.s.word(","); - } + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); + if elts.len() == 1 { + self.s.word(","); } self.pclose(); } @@ -2458,26 +2434,12 @@ impl<'a> State<'a> { } self.print_expr(end); } - PatKind::Slice(ref before, ref slice, ref after) => { + PatKind::Slice(ref elts) => { self.s.word("["); - self.commasep(Inconsistent, - &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.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p)); self.s.word("]"); } + PatKind::Rest => self.s.word(".."), PatKind::Paren(ref inner) => { self.popen(); self.print_pat(inner); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9ec9550f93ab9..ff6440fb9dceb 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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) { match pattern.node { - PatKind::TupleStruct(ref path, ref children, _) => { + PatKind::TupleStruct(ref path, ref elems) => { 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) => { 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) } } - PatKind::Tuple(ref tuple_elements, _) => { - walk_list!(visitor, visit_pat, tuple_elements); + PatKind::Tuple(ref elems) => { + walk_list!(visitor, visit_pat, elems); } PatKind::Box(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(upper_bound); } - PatKind::Wild => (), - PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => { - walk_list!(visitor, visit_pat, prepatterns); - walk_list!(visitor, visit_pat, slice_pattern); - walk_list!(visitor, visit_pat, postpatterns); + PatKind::Wild | PatKind::Rest => {}, + PatKind::Slice(ref elems) => { + walk_list!(visitor, visit_pat, elems); } PatKind::Mac(ref mac) => visitor.visit_mac(mac), } diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs index fac5ef3b03ce1..c249154c71e23 100644 --- a/src/test/mir-opt/uniform_array_move_out.rs +++ b/src/test/mir-opt/uniform_array_move_out.rs @@ -8,7 +8,7 @@ fn move_out_from_end() { fn move_out_by_subslice() { let a = [box 1, box 2]; - let [_y..] = a; + let [_y @ ..] = a; } fn main() { diff --git a/src/test/ui/array-slice-vec/vec-matching-fold.rs b/src/test/ui/array-slice-vec/vec-matching-fold.rs index 2b19c49c42700..f416160db2422 100644 --- a/src/test/ui/array-slice-vec/vec-matching-fold.rs +++ b/src/test/ui/array-slice-vec/vec-matching-fold.rs @@ -11,7 +11,7 @@ fn foldl(values: &[T], U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, { match values { - &[ref head, ref tail..] => + &[ref head, ref tail @ ..] => foldl(tail, function(initial, head), function), &[] => { // FIXME: call guards @@ -28,7 +28,7 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - &[ref head.., ref tail] => + &[ref head @ .., ref tail] => foldr(head, function(tail, initial), function), &[] => { // FIXME: call guards diff --git a/src/test/ui/array-slice-vec/vec-matching-legal-tail-element-borrow.rs b/src/test/ui/array-slice-vec/vec-matching-legal-tail-element-borrow.rs index bce03b3375e51..f0602c328b071 100644 --- a/src/test/ui/array-slice-vec/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/ui/array-slice-vec/vec-matching-legal-tail-element-borrow.rs @@ -8,7 +8,7 @@ pub fn main() { let x: &[isize] = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { - &[1, ref tail..] => &tail[0], + &[1, ref tail @ ..] => &tail[0], _ => unreachable!() }; println!("{}", *el); diff --git a/src/test/ui/array-slice-vec/vec-matching.rs b/src/test/ui/array-slice-vec/vec-matching.rs index a37c25160fa76..49c736bd72847 100644 --- a/src/test/ui/array-slice-vec/vec-matching.rs +++ b/src/test/ui/array-slice-vec/vec-matching.rs @@ -14,7 +14,7 @@ fn a() { fn b() { let x = [1, 2, 3]; match x { - [a, b, c..] => { + [a, b, c @ ..] => { assert_eq!(a, 1); assert_eq!(b, 2); let expected: &[_] = &[3]; @@ -22,7 +22,7 @@ fn b() { } } match x { - [a.., b, c] => { + [a @ .., b, c] => { let expected: &[_] = &[1]; assert_eq!(a, expected); assert_eq!(b, 2); @@ -30,7 +30,7 @@ fn b() { } } match x { - [a, b.., c] => { + [a, b @ .., c] => { assert_eq!(a, 1); let expected: &[_] = &[2]; assert_eq!(b, expected); @@ -50,7 +50,7 @@ fn b() { fn b_slice() { let x : &[_] = &[1, 2, 3]; match x { - &[a, b, ref c..] => { + &[a, b, ref c @ ..] => { assert_eq!(a, 1); assert_eq!(b, 2); let expected: &[_] = &[3]; @@ -59,7 +59,7 @@ fn b_slice() { _ => unreachable!() } match x { - &[ref a.., b, c] => { + &[ref a @ .., b, c] => { let expected: &[_] = &[1]; assert_eq!(a, expected); assert_eq!(b, 2); @@ -68,7 +68,7 @@ fn b_slice() { _ => unreachable!() } match x { - &[a, ref b.., c] => { + &[a, ref b @ .., c] => { assert_eq!(a, 1); let expected: &[_] = &[2]; assert_eq!(b, expected); @@ -134,20 +134,6 @@ fn e() { 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() { a(); b(); @@ -155,5 +141,4 @@ pub fn main() { c(); d(); e(); - f(); } diff --git a/src/test/ui/array-slice-vec/vec-tail-matching.rs b/src/test/ui/array-slice-vec/vec-tail-matching.rs index 84d246dff825c..3c7b160dcc540 100644 --- a/src/test/ui/array-slice-vec/vec-tail-matching.rs +++ b/src/test/ui/array-slice-vec/vec-tail-matching.rs @@ -13,14 +13,14 @@ pub fn main() { Foo { string: "baz" } ]; match x { - [ref first, ref tail..] => { + [ref first, ref tail @ ..] => { assert_eq!(first.string, "foo"); assert_eq!(tail.len(), 2); assert_eq!(tail[0].string, "bar"); assert_eq!(tail[1].string, "baz"); match *(tail as &[_]) { - [Foo { .. }, _, Foo { .. }, ref _tail..] => { + [Foo { .. }, _, Foo { .. }, ref _tail @ ..] => { unreachable!(); } [Foo { string: ref a }, Foo { string: ref b }] => { diff --git a/src/test/ui/associated-path-shl.rs b/src/test/ui/associated-path-shl.rs index d159082ab7ad5..20a6fd83faa32 100644 --- a/src/test/ui/associated-path-shl.rs +++ b/src/test/ui/associated-path-shl.rs @@ -5,6 +5,5 @@ fn main() { let _ = <::B>::C; //~ ERROR cannot find type `A` in this scope let <::B>::C; //~ ERROR cannot find type `A` in this scope let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope - //~^ ERROR only char and numeric types are allowed in range patterns <::B>::C; //~ ERROR cannot find type `A` in this scope } diff --git a/src/test/ui/associated-path-shl.stderr b/src/test/ui/associated-path-shl.stderr index 23918ed2e3912..71ee93f4835fb 100644 --- a/src/test/ui/associated-path-shl.stderr +++ b/src/test/ui/associated-path-shl.stderr @@ -23,21 +23,11 @@ LL | let 0 ..= <::B>::C; | ^ not found 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 | <::B>::C; | ^ not found in this scope -error[E0029]: only char and numeric types are allowed in range patterns - --> $DIR/associated-path-shl.rs:7:15 - | -LL | let 0 ..= <::B>::C; - | ^^^^^^^^^^^ ranges require char or numeric types - | - = note: start type: {integer} - = note: end type: [type error] - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0029, E0412. -For more information about an error, try `rustc --explain E0029`. +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/binding/irrefutable-slice-patterns.rs b/src/test/ui/binding/irrefutable-slice-patterns.rs index 733e6b7b57f72..ac733ef6e9c86 100644 --- a/src/test/ui/binding/irrefutable-slice-patterns.rs +++ b/src/test/ui/binding/irrefutable-slice-patterns.rs @@ -4,7 +4,7 @@ #![feature(slice_patterns)] fn foo(s: &[i32]) -> &[i32] { - let &[ref xs..] = s; + let &[ref xs @ ..] = s; xs } diff --git a/src/test/ui/binding/zero_sized_subslice_match.rs b/src/test/ui/binding/zero_sized_subslice_match.rs index 51e1c024bffff..5326fa612a87b 100644 --- a/src/test/ui/binding/zero_sized_subslice_match.rs +++ b/src/test/ui/binding/zero_sized_subslice_match.rs @@ -7,6 +7,6 @@ fn main() { // The subslice used to go out of bounds for zero-sized array items, check that this doesn't // happen anymore 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 ()) } } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr index f1e1ae18839c4..20f05353d4633 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr @@ -192,8 +192,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here LL | match v { -LL | &[x..] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[x @ ..] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -204,8 +204,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[_, x..] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[_, x @ ..] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -216,8 +216,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[x @ .., _] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -228,8 +228,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[_, x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[_, x @ .., _] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index c8dbf4e691816..c27d9519dc798 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -140,22 +140,22 @@ fn main() { let mut v = &[1, 2, 3, 4, 5]; let x = &mut v; match v { - &[x..] => println!("{:?}", x), + &[x @ ..] => println!("{:?}", x), //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { - &[_, x..] => println!("{:?}", x), + &[_, x @ ..] => println!("{:?}", x), //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { - &[x.., _] => println!("{:?}", x), + &[x @ .., _] => println!("{:?}", x), //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } match v { - &[_, x.., _] => println!("{:?}", x), + &[_, x @ .., _] => println!("{:?}", x), //~^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index 14b9b50f0c32a..38d847a90ff95 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -192,8 +192,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here LL | match v { -LL | &[x..] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[x @ ..] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -204,8 +204,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[_, x..] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[_, x @ ..] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -216,8 +216,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[x @ .., _] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -228,8 +228,8 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed LL | let x = &mut v; | ------ borrow of `v` occurs here ... -LL | &[_, x.., _] => println!("{:?}", x), - | ^ use of borrowed `v` +LL | &[_, x @ .., _] => println!("{:?}", x), + | ^^^^^^ use of borrowed `v` ... LL | drop(x); | - borrow later used here diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.rs b/src/test/ui/borrowck/borrowck-move-out-from-array.rs index 856b03edd2d72..ee6abf407a304 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.rs @@ -10,7 +10,7 @@ fn move_out_from_begin_and_end() { fn move_out_by_const_index_and_subslice() { let a = [box 1, box 2]; let [_x, _] = a; - let [_y..] = a; //~ ERROR [E0382] + let [_y @ ..] = a; //~ ERROR [E0382] } fn main() {} diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index 16722a456defa..b34c03e6deff8 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -13,8 +13,8 @@ error[E0382]: use of moved value: `a[..]` | LL | let [_x, _] = a; | -- value moved here -LL | let [_y..] = a; - | ^^ value used here after move +LL | let [_y @ ..] = a; + | ^^^^^^^ value used here after move | = note: move occurs because `a[..]` has type `std::boxed::Box`, which does not implement the `Copy` trait diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs index cc524c1ac3e6e..fa9a3c217db77 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.rs @@ -15,7 +15,7 @@ pub fn main() { ]; let x: &[Foo] = &x; match *x { - [_, ref tail..] => { + [_, ref tail @ ..] => { match tail { //~^ ERROR cannot move out of type `[Foo]` &[Foo { string: a }, diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs index 7675147c8ec2a..048813b2b93e6 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs @@ -5,7 +5,7 @@ fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> { match *v { - [ref mut head, ref mut tail..] => { + [ref mut head, ref mut tail @ ..] => { Some((head, tail)) } [] => None diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs index 5de8dd3305e37..a6b54f9537ddc 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs @@ -70,7 +70,7 @@ fn const_index_mixed(s: &mut [i32]) { fn const_index_and_subslice_ok(s: &mut [i32]) { if let [ref first, ref second, ..] = *s { - if let [_, _, ref mut tail..] = *s { + if let [_, _, ref mut tail @ ..] = *s { nop(&[first, second]); 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]) { 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_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]) { if let [.., ref second, ref first] = *s { - if let [ref mut tail.., _, _] = *s { + if let [ref mut tail @ .., _, _] = *s { nop(&[first, second]); 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]) { 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_subslice(tail); } @@ -105,8 +105,8 @@ fn const_index_and_subslice_from_end_err(s: &mut [i32]) { } fn subslices(s: &mut [i32]) { - if let [_, _, _, ref s1..] = *s { - if let [ref mut s2.., _, _, _] = *s { //~ERROR + if let [_, _, _, ref s1 @ ..] = *s { + if let [ref mut s2 @ .., _, _, _] = *s { //~ERROR nop_subslice(s1); nop_subslice(s2); } diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr index f716ee68b0002..2c019f4461182 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr @@ -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 { | ---------- immutable borrow occurs here -LL | if let [_, ref mut tail..] = *s { - | ^^^^^^^^^^^^ mutable borrow occurs here +LL | if let [_, ref mut tail @ ..] = *s { + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ 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 { | ---------- immutable borrow occurs here -LL | if let [ref mut tail.., _] = *s { - | ^^^^^^^^^^^^ mutable borrow occurs here +LL | if let [ref mut tail @ .., _] = *s { + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable --> $DIR/borrowck-slice-pattern-element-loan.rs:109:17 | -LL | if let [_, _, _, ref s1..] = *s { - | ------ immutable borrow occurs here -LL | if let [ref mut s2.., _, _, _] = *s { - | ^^^^^^^^^^ mutable borrow occurs here +LL | if let [_, _, _, ref s1 @ ..] = *s { + | ----------- immutable borrow occurs here +LL | if let [ref mut s2 @ .., _, _, _] = *s { + | ^^^^^^^^^^^^^^^ mutable borrow occurs here LL | nop_subslice(s1); | -- immutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs index 100384d78c8ea..53a9bcef74a22 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-element-loan.rs @@ -4,7 +4,7 @@ fn a<'a>() -> &'a [isize] { let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; let tail = match vec { - &[_, ref tail..] => tail, + &[_, ref tail @ ..] => tail, _ => panic!("a") }; 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: &[isize] = &vec; let init = match vec { - &[ref init.., _] => init, + &[ref init @ .., _] => init, _ => panic!("b") }; 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: &[isize] = &vec; let slice = match vec { - &[_, ref slice.., _] => slice, + &[_, ref slice @ .., _] => slice, _ => panic!("c") }; slice //~ ERROR cannot return value referencing local variable `vec` diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs index 4d99a92b18ba8..dd9023f6d9f79 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs @@ -4,7 +4,7 @@ fn a() { let mut v = vec![1, 2, 3]; let vb: &mut [isize] = &mut v; match vb { - &mut [_a, ref tail..] => { + &mut [_a, ref tail @ ..] => { v.push(tail[0] + tail[1]); //~ ERROR cannot borrow } _ => {} diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs index efc52530716c8..420223009a45b 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.rs @@ -5,7 +5,7 @@ fn main() { let mut a = [1, 2, 3, 4]; let t = match a { - [1, 2, ref tail..] => tail, + [1, 2, ref tail @ ..] => tail, _ => unreachable!() }; println!("t[0]: {}", t[0]); diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr index b2f553ba49f70..9f8e6fe3b6898 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr @@ -1,8 +1,8 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-move-tail.rs:12:5 | -LL | [1, 2, ref tail..] => tail, - | -------- borrow of `a[_]` occurs here +LL | [1, 2, ref tail @ ..] => tail, + | ------------- borrow of `a[_]` occurs here ... LL | a[2] = 0; | ^^^^^^^^ assignment to borrowed `a[_]` occurs here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs index 6448149391def..a215305f684dd 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -19,7 +19,7 @@ fn b() { let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { - &mut [ref _b..] => { + &mut [ref _b @ ..] => { //~^ borrow of `vec[_]` occurs here vec[0] = box 4; //~ ERROR cannot assign //~^ NOTE assignment to borrowed `vec[_]` occurs here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 072501f23ff84..f54a3a4072cd2 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -13,8 +13,8 @@ LL | _a.use_ref(); error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:24:13 | -LL | &mut [ref _b..] => { - | ------ borrow of `vec[_]` occurs here +LL | &mut [ref _b @ ..] => { + | ----------- borrow of `vec[_]` occurs here LL | LL | vec[0] = box 4; | ^^^^^^ assignment to borrowed `vec[_]` occurs here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs index e602e75886d95..c35be2f6be62c 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs @@ -4,7 +4,7 @@ fn a<'a>() -> &'a isize { let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; let tail = match vec { - &[_a, ref tail..] => &tail[0], + &[_a, ref tail @ ..] => &tail[0], _ => panic!("foo") }; tail //~ ERROR cannot return value referencing local variable `vec` diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index 9226145d9354d..f3f5c382275fe 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -217,7 +217,7 @@ async fn subslice_pattern_from_end_with_drop(a: Rc, arg: bool, arg2: if arg { let [.., _x, _] = arr; } else { - let [_, _y..] = arr; + let [_, _y @ ..] = arr; } a.alloc().await; } @@ -226,7 +226,7 @@ async fn subslice_pattern_reassign(a: Rc) { let mut ar = [a.alloc().await, a.alloc().await, a.alloc().await]; let [_, _, _x] = ar; ar = [a.alloc().await, a.alloc().await, a.alloc().await]; - let [_, _y..] = ar; + let [_, _y @ ..] = ar; a.alloc().await; } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index eb1a3f3a9f9cb..8516bc3d96424 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -237,7 +237,7 @@ fn subslice_pattern_from_end(a: &Allocator, arg: bool) { if arg { let[.., _x, _] = a; } 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 { let[.., _x, _] = a; } 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[_, _, _x] = ar; ar = [a.alloc(), a.alloc(), a.alloc()]; - let[_, _y..] = ar; + let[_, _y @ ..] = ar; } fn panic_after_return(a: &Allocator) -> Ptr<'_> { diff --git a/src/test/ui/error-codes/E0528.rs b/src/test/ui/error-codes/E0528.rs index f2681fa043dab..17d03b14fc6e1 100644 --- a/src/test/ui/error-codes/E0528.rs +++ b/src/test/ui/error-codes/E0528.rs @@ -3,7 +3,7 @@ fn main() { let r = &[1, 2]; match r { - &[a, b, c, rest..] => { + &[a, b, c, rest @ ..] => { //~^ ERROR E0528 } } diff --git a/src/test/ui/error-codes/E0528.stderr b/src/test/ui/error-codes/E0528.stderr index a7205af50542a..0f566091145bf 100644 --- a/src/test/ui/error-codes/E0528.stderr +++ b/src/test/ui/error-codes/E0528.stderr @@ -1,8 +1,8 @@ error[E0528]: pattern requires at least 3 elements but array has 2 --> $DIR/E0528.rs:6:10 | -LL | &[a, b, c, rest..] => { - | ^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements +LL | &[a, b, c, rest @ ..] => { + | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements error: aborting due to previous error diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs index d95c4b0999405..d97b693f52098 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.rs @@ -2,7 +2,9 @@ fn main() { match [5..4, 99..105, 43..44] { - [_, 99.., _] => {}, //~ ERROR unexpected token: `,` + [_, 99.., _] => {}, + //~^ ERROR `X..` range patterns are not supported + //~| ERROR mismatched types _ => {}, } } diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 359725a41c105..4ecd8515ee164 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -1,8 +1,20 @@ -error: unexpected token: `,` - --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17 +error: `X..` range patterns are not supported + --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13 | 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`. diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs index 95677e34dd798..09f459c9862ee 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.rs @@ -2,7 +2,10 @@ fn main() { 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 _ => {}, } } diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index 8f849d7b3f87c..922d26923158b 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -1,8 +1,27 @@ -error: unexpected token: `]` - --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17 +error: `X..` range patterns are not supported + --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13 | 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`. diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs index 3bf5da710ef9f..95e58b1d48c88 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.rs @@ -2,7 +2,10 @@ fn main() { 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 _ => {}, } } diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr index a09ba3562e098..8907b875f8e11 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr @@ -1,8 +1,31 @@ -error: expected one of `,` or `]`, found `9` - --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 +error: `..X` range patterns are not supported + --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10 | 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`. diff --git a/src/test/ui/feature-gates/feature-gate-slice-patterns.rs b/src/test/ui/feature-gates/feature-gate-slice-patterns.rs index 0165321debe6b..f2a1b135b69cb 100644 --- a/src/test/ui/feature-gates/feature-gate-slice-patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-slice-patterns.rs @@ -3,15 +3,15 @@ fn main() { let x = [1, 2, 3, 4, 5]; match x { - [1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized - [1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized - [.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [1, 2, ..] => {} //~ ERROR subslice patterns are unstable + [1, .., 5] => {} //~ ERROR subslice patterns are unstable + [.., 4, 5] => {} //~ ERROR subslice patterns are unstable } let x = [ 1, 2, 3, 4, 5 ]; match x { - [ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized - [ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized - [ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized + [ xs @ .., 4, 5 ] => {} //~ ERROR subslice patterns are unstable + [ 1, xs @ .., 5 ] => {} //~ ERROR subslice patterns are unstable + [ 1, 2, xs @ .. ] => {} //~ ERROR subslice patterns are unstable } } diff --git a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr index e88fddaa81fbe..d4946a42b8f3d 100644 --- a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr @@ -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 | LL | [1, 2, ..] => {} @@ -7,7 +7,7 @@ LL | [1, 2, ..] => {} = 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]: syntax for subslices in slice patterns is not yet stabilized +error[E0658]: subslice patterns are unstable --> $DIR/feature-gate-slice-patterns.rs:7:13 | LL | [1, .., 5] => {} @@ -16,7 +16,7 @@ LL | [1, .., 5] => {} = 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]: syntax for subslices in slice patterns is not yet stabilized +error[E0658]: subslice patterns are unstable --> $DIR/feature-gate-slice-patterns.rs:8:10 | LL | [.., 4, 5] => {} @@ -25,29 +25,29 @@ LL | [.., 4, 5] => {} = 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]: syntax for subslices in slice patterns is not yet stabilized +error[E0658]: subslice patterns are unstable --> $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 = 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 | -LL | [ 1, xs.., 5 ] => {} - | ^^ +LL | [ 1, xs @ .., 5 ] => {} + | ^^^^^^^ | = 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]: syntax for subslices in slice patterns is not yet stabilized +error[E0658]: subslice patterns are unstable --> $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 = help: add `#![feature(slice_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/issues/issue-12369.rs b/src/test/ui/issues/issue-12369.rs index 8df8efefd05ed..0866131807463 100644 --- a/src/test/ui/issues/issue-12369.rs +++ b/src/test/ui/issues/issue-12369.rs @@ -6,7 +6,7 @@ fn main() { let v: isize = match &*sl { &[] => 0, &[a,b,c] => 3, - &[a, ref rest..] => a, - &[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern + &[a, ref rest @ ..] => a, + &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern }; } diff --git a/src/test/ui/issues/issue-12369.stderr b/src/test/ui/issues/issue-12369.stderr index fec9078dc4090..f27425e28c61d 100644 --- a/src/test/ui/issues/issue-12369.stderr +++ b/src/test/ui/issues/issue-12369.stderr @@ -1,8 +1,8 @@ error: unreachable pattern --> $DIR/issue-12369.rs:10:9 | -LL | &[10,a, ref rest..] => 10 - | ^^^^^^^^^^^^^^^^^^^ +LL | &[10,a, ref rest @ ..] => 10 + | ^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here --> $DIR/issue-12369.rs:2:9 diff --git a/src/test/ui/issues/issue-15080.rs b/src/test/ui/issues/issue-15080.rs index 4558118a8091c..b11b1cda38ae1 100644 --- a/src/test/ui/issues/issue-15080.rs +++ b/src/test/ui/issues/issue-15080.rs @@ -7,11 +7,11 @@ fn main() { let mut result = vec![]; loop { x = match *x { - [1, n, 3, ref rest..] => { + [1, n, 3, ref rest @ ..] => { result.push(n); rest } - [n, ref rest..] => { + [n, ref rest @ ..] => { result.push(n); rest } diff --git a/src/test/ui/issues/issue-15104.rs b/src/test/ui/issues/issue-15104.rs index 3a03a52c32485..ee977541137db 100644 --- a/src/test/ui/issues/issue-15104.rs +++ b/src/test/ui/issues/issue-15104.rs @@ -9,6 +9,6 @@ fn count_members(v: &[usize]) -> usize { match *v { [] => 0, [_] => 1, - [_, ref xs..] => 1 + count_members(xs) + [_, ref xs @ ..] => 1 + count_members(xs) } } diff --git a/src/test/ui/issues/issue-17877.rs b/src/test/ui/issues/issue-17877.rs index af22b1ad8f0bc..fefa3f2f87304 100644 --- a/src/test/ui/issues/issue-17877.rs +++ b/src/test/ui/issues/issue-17877.rs @@ -7,8 +7,8 @@ fn main() { }, 42_usize); assert_eq!(match [0u8; 1024] { - [1, _..] => 0_usize, - [0, _..] => 1_usize, + [1, ..] => 0_usize, + [0, ..] => 1_usize, _ => 2_usize }, 1_usize); } diff --git a/src/test/ui/issues/issue-26158.rs b/src/test/ui/issues/issue-26158.rs deleted file mode 100644 index 11f47b6d02a73..0000000000000 --- a/src/test/ui/issues/issue-26158.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(slice_patterns)] - -fn main() { - let x: &[u32] = &[]; - let &[[ref _a, ref _b..]..] = x; //~ ERROR refutable pattern -} diff --git a/src/test/ui/issues/issue-26158.stderr b/src/test/ui/issues/issue-26158.stderr deleted file mode 100644 index 3a4dd79e81053..0000000000000 --- a/src/test/ui/issues/issue-26158.stderr +++ /dev/null @@ -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`. diff --git a/src/test/ui/issues/issue-37598.rs b/src/test/ui/issues/issue-37598.rs index 1bec3d340d665..31b3aba6bc204 100644 --- a/src/test/ui/issues/issue-37598.rs +++ b/src/test/ui/issues/issue-37598.rs @@ -1,11 +1,10 @@ -// build-pass (FIXME(62277): could be check-pass?) -#![allow(dead_code)] +// check-pass #![feature(slice_patterns)] fn check(list: &[u8]) { match list { &[] => {}, - &[_u1, _u2, ref _next..] => {}, + &[_u1, _u2, ref _next @ ..] => {}, &[_u1] => {}, } } diff --git a/src/test/ui/issues/issue-7784.rs b/src/test/ui/issues/issue-7784.rs index b75e547079ef5..5b70bd6e5ff54 100644 --- a/src/test/ui/issues/issue-7784.rs +++ b/src/test/ui/issues/issue-7784.rs @@ -24,7 +24,7 @@ fn main() { assert_eq!(d, "baz"); let out = bar("baz", "foo"); - let [a, xs.., d] = out; + let [a, xs @ .., d] = out; assert_eq!(a, "baz"); assert_eq!(xs, ["foo", "foo"]); assert_eq!(d, "baz"); diff --git a/src/test/ui/match/match-vec-mismatch.rs b/src/test/ui/match/match-vec-mismatch.rs index 5e61c1b22a085..a0ef92743ac5a 100644 --- a/src/test/ui/match/match-vec-mismatch.rs +++ b/src/test/ui/match/match-vec-mismatch.rs @@ -19,10 +19,10 @@ fn main() { match [0, 1, 2] { [0] => {}, //~ ERROR pattern requires - [0, 1, x..] => { + [0, 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 diff --git a/src/test/ui/match/match-vec-mismatch.stderr b/src/test/ui/match/match-vec-mismatch.stderr index 47f9d48e26290..2f1bbb7621659 100644 --- a/src/test/ui/match/match-vec-mismatch.stderr +++ b/src/test/ui/match/match-vec-mismatch.stderr @@ -19,8 +19,8 @@ LL | [0] => {}, error[E0528]: pattern requires at least 4 elements but array has 3 --> $DIR/match-vec-mismatch.rs:25:9 | -LL | [0, 1, 2, 3, x..] => {} - | ^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements +LL | [0, 1, 2, 3, x @ ..] => {} + | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements error[E0282]: type annotations needed --> $DIR/match-vec-mismatch.rs:36:9 diff --git a/src/test/ui/match/match-vec-unreachable.rs b/src/test/ui/match/match-vec-unreachable.rs index 9e167f37ba9d9..78810525bad0f 100644 --- a/src/test/ui/match/match-vec-unreachable.rs +++ b/src/test/ui/match/match-vec-unreachable.rs @@ -23,7 +23,7 @@ fn main() { let x: Vec = vec!['a', 'b', 'c']; let x: &[char] = &x; match *x { - ['a', 'b', 'c', ref _tail..] => {} + ['a', 'b', 'c', ref _tail @ ..] => {} ['a', 'b', 'c'] => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/ui/non-exhaustive/non-exhaustive-match.rs b/src/test/ui/non-exhaustive/non-exhaustive-match.rs index e888bcf516891..8cc5f4042cccb 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-match.rs +++ b/src/test/ui/non-exhaustive/non-exhaustive-match.rs @@ -32,14 +32,14 @@ fn main() { let vec = vec![Some(42), None, Some(21)]; let vec: &[Option] = &vec; match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered - [Some(..), None, ref tail..] => {} - [Some(..), Some(..), ref tail..] => {} + [Some(..), None, ref tail @ ..] => {} + [Some(..), Some(..), ref tail @ ..] => {} [None] => {} } let vec = vec![1]; let vec: &[isize] = &vec; match *vec { - [_, ref tail..] => (), + [_, ref tail @ ..] => (), [] => () } let vec = vec![0.5f32]; @@ -53,10 +53,10 @@ fn main() { let vec = vec![Some(42), None, Some(21)]; let vec: &[Option] = &vec; match *vec { - [Some(..), None, ref tail..] => {} - [Some(..), Some(..), ref tail..] => {} - [None, None, ref tail..] => {} - [None, Some(..), ref tail..] => {} + [Some(..), None, ref tail @ ..] => {} + [Some(..), Some(..), ref tail @ ..] => {} + [None, None, ref tail @ ..] => {} + [None, Some(..), ref tail @ ..] => {} [Some(_)] => {} [None] => {} [] => {} diff --git a/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.rs b/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.rs index 9fcd4bdad7264..4ca1cbcebccf5 100644 --- a/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.rs +++ b/src/test/ui/non-exhaustive/non-exhaustive-pattern-witness.rs @@ -77,7 +77,7 @@ fn vectors_with_nested_enums() { [Enum::Second(true), Enum::First] => (), [Enum::Second(true), Enum::Second(true)] => (), [Enum::Second(false), _] => (), - [_, _, ref tail.., _] => () + [_, _, ref tail @ .., _] => () } } diff --git a/src/test/ui/parser/match-vec-invalid.rs b/src/test/ui/parser/match-vec-invalid.rs index e5e85ba8ca602..00f4374b256d2 100644 --- a/src/test/ui/parser/match-vec-invalid.rs +++ b/src/test/ui/parser/match-vec-invalid.rs @@ -1,7 +1,13 @@ fn main() { - let a = Vec::new(); + let a: &[u8] = &[]; 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 diff --git a/src/test/ui/parser/match-vec-invalid.stderr b/src/test/ui/parser/match-vec-invalid.stderr index fee8d248dcf07..0956ac21b7f1e 100644 --- a/src/test/ui/parser/match-vec-invalid.stderr +++ b/src/test/ui/parser/match-vec-invalid.stderr @@ -1,8 +1,45 @@ -error: expected one of `,` or `@`, found `..` - --> $DIR/match-vec-invalid.rs:4:25 +error[E0416]: identifier `tail` is bound more than once in the same pattern + --> $DIR/match-vec-invalid.rs:4:24 | -LL | [1, tail.., tail..] => {}, - | ^^ expected one of `,` or `@` here +LL | [1, tail @ .., tail @ ..] => {}, + | ^^^^ 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`. diff --git a/src/test/ui/parser/pat-lt-bracket-6.rs b/src/test/ui/parser/pat-lt-bracket-6.rs index 9bad0cb25c1e4..7b9721830993e 100644 --- a/src/test/ui/parser/pat-lt-bracket-6.rs +++ b/src/test/ui/parser/pat-lt-bracket-6.rs @@ -1,3 +1,9 @@ fn main() { + struct Test(&'static u8, [u8; 0]); + let x = Test(&0, []); + let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[` + //~^ ERROR subslice patterns are unstable } + +const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types diff --git a/src/test/ui/parser/pat-lt-bracket-6.stderr b/src/test/ui/parser/pat-lt-bracket-6.stderr index 2ee4bdb20fe88..201465b2c850c 100644 --- a/src/test/ui/parser/pat-lt-bracket-6.stderr +++ b/src/test/ui/parser/pat-lt-bracket-6.stderr @@ -1,8 +1,28 @@ 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; | ^ 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`. diff --git a/src/test/ui/parser/pat-lt-bracket-7.rs b/src/test/ui/parser/pat-lt-bracket-7.rs index 36c0d7733733a..020fdb845e8b5 100644 --- a/src/test/ui/parser/pat-lt-bracket-7.rs +++ b/src/test/ui/parser/pat-lt-bracket-7.rs @@ -1,3 +1,8 @@ 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 diff --git a/src/test/ui/parser/pat-lt-bracket-7.stderr b/src/test/ui/parser/pat-lt-bracket-7.stderr index 5552ea46d9b9d..17557efa49e80 100644 --- a/src/test/ui/parser/pat-lt-bracket-7.stderr +++ b/src/test/ui/parser/pat-lt-bracket-7.stderr @@ -1,8 +1,18 @@ 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 -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`. diff --git a/src/test/ui/parser/pat-tuple-2.rs b/src/test/ui/parser/pat-tuple-2.rs index fd25499381a28..a8f3debd3d634 100644 --- a/src/test/ui/parser/pat-tuple-2.rs +++ b/src/test/ui/parser/pat-tuple-2.rs @@ -1,6 +1,7 @@ +// check-pass + fn main() { match (0, 1, 2) { (pat, ..,) => {} - //~^ ERROR trailing comma is not permitted after `..` } } diff --git a/src/test/ui/parser/pat-tuple-2.stderr b/src/test/ui/parser/pat-tuple-2.stderr deleted file mode 100644 index c3a5c39a8e32a..0000000000000 --- a/src/test/ui/parser/pat-tuple-2.stderr +++ /dev/null @@ -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 - diff --git a/src/test/ui/parser/pat-tuple-3.rs b/src/test/ui/parser/pat-tuple-3.rs index e1e975d3c3ea0..1486ab231aab4 100644 --- a/src/test/ui/parser/pat-tuple-3.rs +++ b/src/test/ui/parser/pat-tuple-3.rs @@ -1,6 +1,6 @@ fn main() { match (0, 1, 2) { (.., pat, ..) => {} - //~^ ERROR `..` can only be used once per tuple or tuple struct pattern + //~^ ERROR `..` can only be used once per tuple pattern } } diff --git a/src/test/ui/parser/pat-tuple-3.stderr b/src/test/ui/parser/pat-tuple-3.stderr index c9f14bb90429b..9ac0611c5c933 100644 --- a/src/test/ui/parser/pat-tuple-3.stderr +++ b/src/test/ui/parser/pat-tuple-3.stderr @@ -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 | 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 diff --git a/src/test/ui/parser/pat-tuple-4.rs b/src/test/ui/parser/pat-tuple-4.rs index 76f60d94bc86e..2f03160430a22 100644 --- a/src/test/ui/parser/pat-tuple-4.rs +++ b/src/test/ui/parser/pat-tuple-4.rs @@ -1,5 +1,11 @@ fn main() { + const PAT: u8 = 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 diff --git a/src/test/ui/parser/pat-tuple-4.stderr b/src/test/ui/parser/pat-tuple-4.stderr index 26b92fae31391..af3ecce184649 100644 --- a/src/test/ui/parser/pat-tuple-4.stderr +++ b/src/test/ui/parser/pat-tuple-4.stderr @@ -1,8 +1,28 @@ -error: expected one of `)` or `,`, found `pat` - --> $DIR/pat-tuple-4.rs:3:13 +error: `..X` range patterns are not supported + --> $DIR/pat-tuple-4.rs:5:10 | -LL | (.. pat) => {} - | ^^^ expected one of `)` or `,` here +LL | (.. PAT) => {} + | ^^^^^^ 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`. diff --git a/src/test/ui/parser/pat-tuple-5.rs b/src/test/ui/parser/pat-tuple-5.rs index d4f05a5eb523e..5334ef93bb3bd 100644 --- a/src/test/ui/parser/pat-tuple-5.rs +++ b/src/test/ui/parser/pat-tuple-5.rs @@ -1,5 +1,10 @@ fn main() { + const PAT: u8 = 0; + 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 } } diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index f9832214c6800..09ebdc29a2161 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -1,8 +1,30 @@ -error: unexpected token: `)` - --> $DIR/pat-tuple-5.rs:3:16 +error: `X..` range patterns are not supported + --> $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`. diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs new file mode 100644 index 0000000000000..c66652ff4fa01 --- /dev/null +++ b/src/test/ui/parser/recover-range-pats.rs @@ -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 +} diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr new file mode 100644 index 0000000000000..c50d5e6eb6153 --- /dev/null +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -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`. diff --git a/src/test/ui/parser/recover-tuple-pat.rs b/src/test/ui/parser/recover-tuple-pat.rs index 488e8db6b8789..7fded752d675e 100644 --- a/src/test/ui/parser/recover-tuple-pat.rs +++ b/src/test/ui/parser/recover-tuple-pat.rs @@ -1,12 +1,12 @@ +// NOTE: This doesn't recover anymore. + fn main() { let x = (1, 2, 3, 4); match x { (1, .., 4) => {} (1, .=., 4) => { let _: usize = ""; } //~^ ERROR expected pattern, found `.` - //~| ERROR mismatched types (.=., 4) => {} - //~^ ERROR expected pattern, found `.` (1, 2, 3, 4) => {} } } diff --git a/src/test/ui/parser/recover-tuple-pat.stderr b/src/test/ui/parser/recover-tuple-pat.stderr index 5919aa72355ac..93a6a66a63082 100644 --- a/src/test/ui/parser/recover-tuple-pat.stderr +++ b/src/test/ui/parser/recover-tuple-pat.stderr @@ -1,24 +1,8 @@ error: expected pattern, found `.` - --> $DIR/recover-tuple-pat.rs:5:13 + --> $DIR/recover-tuple-pat.rs:7:13 | LL | (1, .=., 4) => { let _: usize = ""; } | ^ expected pattern -error: expected pattern, found `.` - --> $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 +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.rs b/src/test/ui/rfc-2005-default-binding-mode/slice.rs index fd85bf7f16007..1484b8c4a1f13 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/slice.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/slice.rs @@ -4,6 +4,6 @@ pub fn main() { let sl: &[u8] = b"foo"; match sl { //~ ERROR non-exhaustive patterns - [first, remainder..] => {}, + [first, remainder @ ..] => {}, }; } diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs index 939a3c4a1fd7a..38b0941aad0a6 100644 --- a/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/slice.rs @@ -5,7 +5,7 @@ fn slice_pat() { let sl: &[u8] = b"foo"; match sl { - [first, remainder..] => { + [first, remainder @ ..] => { let _: &u8 = first; assert_eq!(first, &b'f'); assert_eq!(remainder, b"oo"); diff --git a/src/test/ui/trailing-comma.rs b/src/test/ui/trailing-comma.rs index f34e6b7606dd7..929c35a9e1122 100644 --- a/src/test/ui/trailing-comma.rs +++ b/src/test/ui/trailing-comma.rs @@ -25,7 +25,7 @@ pub fn main() { let (_, _,) = (1, 1,); let [_, _,] = [1, 1,]; let [_, _, .., _,] = [1, 1, 1, 1,]; - let [_, _, _.., _,] = [1, 1, 1, 1,]; + let [_, _, _, ..,] = [1, 1, 1, 1,]; let x: Foo = Foo::(1);