diff options
author | Josh Mcguigan <[email protected]> | 2020-04-12 16:40:09 +0100 |
---|---|---|
committer | Josh Mcguigan <[email protected]> | 2020-04-13 16:19:19 +0100 |
commit | ee822d19b7662a9055bc6693c4c40d8dcf752ea1 (patch) | |
tree | a895315e5ca25485fa0ac5a341dd35fc6a851f9b /crates/ra_hir_def/src | |
parent | 268b7987290143550461090c2c0e23371813dbec (diff) |
handle tuple patterns with ellipsis
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 6 |
2 files changed, 25 insertions, 8 deletions
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::{ | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | use super::{ExprSource, PatSource}; | 35 | use super::{ExprSource, PatSource}; |
36 | use ast::AstChildren; | ||
36 | 37 | ||
37 | pub(super) fn lower( | 38 | pub(super) fn lower( |
38 | db: &dyn DefDatabase, | 39 | db: &dyn DefDatabase, |
@@ -598,8 +599,8 @@ impl ExprCollector<'_> { | |||
598 | } | 599 | } |
599 | ast::Pat::TupleStructPat(p) => { | 600 | ast::Pat::TupleStructPat(p) => { |
600 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 601 | let path = p.path().and_then(|path| self.expander.parse_path(path)); |
601 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | 602 | let (args, ellipsis) = self.collect_tuple_pat(p.args()); |
602 | Pat::TupleStruct { path, args } | 603 | Pat::TupleStruct { path, args, ellipsis } |
603 | } | 604 | } |
604 | ast::Pat::RefPat(p) => { | 605 | ast::Pat::RefPat(p) => { |
605 | let pat = self.collect_pat_opt(p.pat()); | 606 | let pat = self.collect_pat_opt(p.pat()); |
@@ -616,10 +617,10 @@ impl ExprCollector<'_> { | |||
616 | } | 617 | } |
617 | ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), | 618 | ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), |
618 | ast::Pat::TuplePat(p) => { | 619 | ast::Pat::TuplePat(p) => { |
619 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | 620 | let (args, ellipsis) = self.collect_tuple_pat(p.args()); |
620 | Pat::Tuple(args) | 621 | Pat::Tuple { args, ellipsis } |
621 | } | 622 | } |
622 | ast::Pat::PlaceholderPat(_) | ast::Pat::DotDotPat(_) => Pat::Wild, | 623 | ast::Pat::PlaceholderPat(_) => Pat::Wild, |
623 | ast::Pat::RecordPat(p) => { | 624 | ast::Pat::RecordPat(p) => { |
624 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 625 | let path = p.path().and_then(|path| self.expander.parse_path(path)); |
625 | let record_field_pat_list = | 626 | let record_field_pat_list = |
@@ -665,6 +666,9 @@ impl ExprCollector<'_> { | |||
665 | Pat::Missing | 666 | Pat::Missing |
666 | } | 667 | } |
667 | } | 668 | } |
669 | ast::Pat::DotDotPat(_) => unreachable!( | ||
670 | "`DotDotPat` requires special handling and should not be mapped to a Pat." | ||
671 | ), | ||
668 | // FIXME: implement | 672 | // FIXME: implement |
669 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 673 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, |
670 | }; | 674 | }; |
@@ -679,6 +683,19 @@ impl ExprCollector<'_> { | |||
679 | self.missing_pat() | 683 | self.missing_pat() |
680 | } | 684 | } |
681 | } | 685 | } |
686 | |||
687 | fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) { | ||
688 | // Find the location of the `..`, if there is one. Note that we do not | ||
689 | // consider the possiblity of there being multiple `..` here. | ||
690 | let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::DotDotPat(_))); | ||
691 | // We want to skip the `..` pattern here, since we account for it above. | ||
692 | let args = args | ||
693 | .filter(|p| !matches!(p, ast::Pat::DotDotPat(_))) | ||
694 | .map(|p| self.collect_pat(p)) | ||
695 | .collect(); | ||
696 | |||
697 | (args, ellipsis) | ||
698 | } | ||
682 | } | 699 | } |
683 | 700 | ||
684 | impl From<ast::BinOp> for BinaryOp { | 701 | impl From<ast::BinOp> 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 { | |||
374 | pub enum Pat { | 374 | pub enum Pat { |
375 | Missing, | 375 | Missing, |
376 | Wild, | 376 | Wild, |
377 | Tuple(Vec<PatId>), | 377 | Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, |
378 | Or(Vec<PatId>), | 378 | Or(Vec<PatId>), |
379 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, | 379 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, |
380 | Range { start: ExprId, end: ExprId }, | 380 | Range { start: ExprId, end: ExprId }, |
@@ -382,7 +382,7 @@ pub enum Pat { | |||
382 | Path(Path), | 382 | Path(Path), |
383 | Lit(ExprId), | 383 | Lit(ExprId), |
384 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | 384 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, |
385 | TupleStruct { path: Option<Path>, args: Vec<PatId> }, | 385 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, |
386 | Ref { pat: PatId, mutability: Mutability }, | 386 | Ref { pat: PatId, mutability: Mutability }, |
387 | } | 387 | } |
388 | 388 | ||
@@ -393,7 +393,7 @@ impl Pat { | |||
393 | Pat::Bind { subpat, .. } => { | 393 | Pat::Bind { subpat, .. } => { |
394 | subpat.iter().copied().for_each(f); | 394 | subpat.iter().copied().for_each(f); |
395 | } | 395 | } |
396 | Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { | 396 | Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { |
397 | args.iter().copied().for_each(f); | 397 | args.iter().copied().for_each(f); |
398 | } | 398 | } |
399 | Pat::Ref { pat, .. } => f(*pat), | 399 | Pat::Ref { pat, .. } => f(*pat), |