From ee822d19b7662a9055bc6693c4c40d8dcf752ea1 Mon Sep 17 00:00:00 2001 From: Josh Mcguigan Date: Sun, 12 Apr 2020 08:40:09 -0700 Subject: handle tuple patterns with ellipsis --- crates/ra_hir_def/src/body/lower.rs | 27 ++++++++++++++++++++++----- crates/ra_hir_def/src/expr.rs | 6 +++--- 2 files changed, 25 insertions(+), 8 deletions(-) (limited to 'crates/ra_hir_def') diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 6caa87db4..79abe55ce 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -33,6 +33,7 @@ use crate::{ }; use super::{ExprSource, PatSource}; +use ast::AstChildren; pub(super) fn lower( db: &dyn DefDatabase, @@ -598,8 +599,8 @@ impl ExprCollector<'_> { } ast::Pat::TupleStructPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); - let args = p.args().map(|p| self.collect_pat(p)).collect(); - Pat::TupleStruct { path, args } + let (args, ellipsis) = self.collect_tuple_pat(p.args()); + Pat::TupleStruct { path, args, ellipsis } } ast::Pat::RefPat(p) => { let pat = self.collect_pat_opt(p.pat()); @@ -616,10 +617,10 @@ impl ExprCollector<'_> { } ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), ast::Pat::TuplePat(p) => { - let args = p.args().map(|p| self.collect_pat(p)).collect(); - Pat::Tuple(args) + let (args, ellipsis) = self.collect_tuple_pat(p.args()); + Pat::Tuple { args, ellipsis } } - ast::Pat::PlaceholderPat(_) | ast::Pat::DotDotPat(_) => Pat::Wild, + ast::Pat::PlaceholderPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); let record_field_pat_list = @@ -665,6 +666,9 @@ impl ExprCollector<'_> { Pat::Missing } } + ast::Pat::DotDotPat(_) => unreachable!( + "`DotDotPat` requires special handling and should not be mapped to a Pat." + ), // FIXME: implement ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, }; @@ -679,6 +683,19 @@ impl ExprCollector<'_> { self.missing_pat() } } + + fn collect_tuple_pat(&mut self, args: AstChildren) -> (Vec, Option) { + // Find the location of the `..`, if there is one. Note that we do not + // consider the possiblity of there being multiple `..` here. + let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_))); + // We want to skip the `..` pattern here, since we account for it above. + let args = args + .filter(|p| !matches!(p, ast::Pat::DotDotPat(_))) + .map(|p| self.collect_pat(p)) + .collect(); + + (args, ellipsis) + } } impl From for BinaryOp { diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index e11bdf3ec..a0cdad529 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs @@ -374,7 +374,7 @@ pub struct RecordFieldPat { pub enum Pat { Missing, Wild, - Tuple(Vec), + Tuple { args: Vec, ellipsis: Option }, Or(Vec), Record { path: Option, args: Vec, ellipsis: bool }, Range { start: ExprId, end: ExprId }, @@ -382,7 +382,7 @@ pub enum Pat { Path(Path), Lit(ExprId), Bind { mode: BindingAnnotation, name: Name, subpat: Option }, - TupleStruct { path: Option, args: Vec }, + TupleStruct { path: Option, args: Vec, ellipsis: Option }, Ref { pat: PatId, mutability: Mutability }, } @@ -393,7 +393,7 @@ impl Pat { Pat::Bind { subpat, .. } => { subpat.iter().copied().for_each(f); } - Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { + Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { args.iter().copied().for_each(f); } Pat::Ref { pat, .. } => f(*pat), -- cgit v1.2.3