diff --git a/Cargo.lock b/Cargo.lock index 847653696d37..45804c087e80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,6 +1070,7 @@ dependencies = [ "drop_bomb", "either", "insta", + "itertools", "log", "once_cell", "ra_arena", diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 1efa00fe005e..6b9be9948c60 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -14,6 +14,7 @@ rustc-hash = "1.0" either = "1.5" anymap = "0.12" drop_bomb = "0.1.4" +itertools = "0.8.2" ra_arena = { path = "../ra_arena" } ra_db = { path = "../ra_db" } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index fe0973fc764c..1fc8923620ae 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -8,7 +8,7 @@ use ra_arena::Arena; use ra_syntax::{ ast::{ self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, - TypeAscriptionOwner, + SlicePatComponents, TypeAscriptionOwner, }, AstNode, AstPtr, }; @@ -596,7 +596,7 @@ where let args = p.args().map(|p| self.collect_pat(p)).collect(); Pat::Tuple(args) } - ast::Pat::PlaceholderPat(_) => Pat::Wild, + ast::Pat::PlaceholderPat(_) | ast::Pat::DotDotPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); let record_field_pat_list = @@ -621,12 +621,20 @@ where Pat::Record { path, args: fields } } + ast::Pat::SlicePat(p) => { + let SlicePatComponents { prefix, slice, suffix } = p.components(); + + Pat::Slice { + prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(), + slice: slice.map(|p| self.collect_pat(p)), + suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(), + } + } // FIXME: implement - ast::Pat::DotDotPat(_) => Pat::Missing, ast::Pat::BoxPat(_) => Pat::Missing, ast::Pat::LiteralPat(_) => Pat::Missing, - ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, + ast::Pat::RangePat(_) => Pat::Missing, }; let ptr = AstPtr::new(&pat); self.alloc_pat(pattern, Either::Left(ptr)) diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 5a84e08ededc..9707c55276af 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs @@ -394,7 +394,7 @@ pub enum Pat { }, Slice { prefix: Vec, - rest: Option, + slice: Option, suffix: Vec, }, Path(Path), @@ -425,8 +425,8 @@ impl Pat { args.iter().copied().for_each(f); } Pat::Ref { pat, .. } => f(*pat), - Pat::Slice { prefix, rest, suffix } => { - let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); + Pat::Slice { prefix, slice, suffix } => { + let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); total_iter.copied().for_each(f); } Pat::Record { args, .. } => { diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 89cb9a9f3943..d3e8888bd5e2 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -18,7 +18,8 @@ use crate::{ pub use self::{ expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp, RangeOp}, extensions::{ - FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind, VisibilityKind, + FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind, TypeBoundKind, + VisibilityKind, }, generated::*, tokens::*, diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index cb0aee422592..7dcf084de90a 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs @@ -1,6 +1,8 @@ //! Various extension methods to ast Nodes, which are hard to code-generate. //! Extensions for various expressions live in a sibling `expr_extensions` module. +use itertools::Itertools; + use crate::{ ast::{self, child_opt, children, AstNode, AttrInput, SyntaxNode}, SmolStr, SyntaxElement, @@ -293,6 +295,40 @@ impl ast::BindPat { } } +pub struct SlicePatComponents { + pub prefix: Vec, + pub slice: Option, + pub suffix: Vec, +} + +impl ast::SlicePat { + pub fn components(&self) -> SlicePatComponents { + let mut args = self.args().peekable(); + let prefix = args + .peeking_take_while(|p| match p { + ast::Pat::DotDotPat(_) => false, + ast::Pat::BindPat(bp) => match bp.pat() { + Some(ast::Pat::DotDotPat(_)) => false, + _ => true, + }, + ast::Pat::RefPat(rp) => match rp.pat() { + Some(ast::Pat::DotDotPat(_)) => false, + Some(ast::Pat::BindPat(bp)) => match bp.pat() { + Some(ast::Pat::DotDotPat(_)) => false, + _ => true, + }, + _ => true, + }, + _ => true, + }) + .collect(); + let slice = args.next(); + let suffix = args.collect(); + + SlicePatComponents { prefix, slice, suffix } + } +} + impl ast::PointerType { pub fn is_mut(&self) -> bool { self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 8d640642d275..8eb240801d50 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -2117,7 +2117,11 @@ impl AstNode for SlicePat { &self.syntax } } -impl SlicePat {} +impl SlicePat { + pub fn args(&self) -> AstChildren { + AstChildren::new(&self.syntax) + } +} #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RangePat { pub(crate) syntax: SyntaxNode, diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 3f530e4899c7..2d9ae904b129 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -417,14 +417,14 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { pat: Pat, guard: MatchGuard, Expr, - } + } struct MatchGuard { Expr } struct RecordLit { Path, RecordFieldList } struct RecordFieldList { fields: [RecordField], spread: Expr, - } + } struct RecordField { NameRef, Expr } struct OrPat { pats: [Pat] } @@ -434,8 +434,8 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { struct BindPat: NameOwner { Pat } struct PlaceholderPat { } struct DotDotPat { } - struct PathPat { Path } - struct SlicePat {} + struct PathPat { Path } + struct SlicePat { args: [Pat] } struct RangePat {} struct LiteralPat { Literal }