diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 804d98ce381..bafaa726611 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -821,7 +821,7 @@ impl ExprCollector<'_> { let ellipsis = p .record_pat_field_list() .expect("every struct should have a field list") - .dotdot_token() + .rest_pat() .is_some(); Pat::Record { path, args, ellipsis } diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 81e2051abb5..7ba81d0cb15 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -200,12 +200,43 @@ fn tuple_pat_fields(p: &mut Parser) { p.expect(T![')']); } +// test record_pat_field +// fn foo() { +// let S { 0: 1 } = (); +// let S { x: 1 } = (); +// let S { #[cfg(any())] x: 1 } = (); +// } +fn record_pat_field(p: &mut Parser) { + match p.current() { + IDENT | INT_NUMBER if p.nth(1) == T![:] => { + name_ref_or_index(p); + p.bump(T![:]); + pattern(p); + } + T![.] => { + if p.at(T![..]) { + p.bump(T![..]); + } else { + ident_pat(p, false); + } + } + T![box] => { + // FIXME: not all box patterns should be allowed + box_pat(p); + } + _ => { + ident_pat(p, false); + } + } +} + // test record_pat_field_list // fn foo() { // let S {} = (); // let S { f, ref mut g } = (); // let S { h: _, ..} = (); // let S { h: _, } = (); +// let S { #[cfg(any())] .. } = (); // } fn record_pat_field_list(p: &mut Parser) { assert!(p.at(T!['{'])); @@ -214,32 +245,26 @@ fn record_pat_field_list(p: &mut Parser) { while !p.at(EOF) && !p.at(T!['}']) { match p.current() { // A trailing `..` is *not* treated as a REST_PAT. - T![.] if p.at(T![..]) => p.bump(T![..]), + T![.] if p.at(T![..]) => { + rest_pat(p); + } T!['{'] => error_block(p, "expected ident"), + T![#] => { + let m = p.start(); + attributes::outer_attrs(p); + if p.at(T![..]) { + p.bump(T![..]); + m.complete(p, REST_PAT); + } else { + record_pat_field(p); + m.complete(p, RECORD_PAT_FIELD); + } + } _ => { let m = p.start(); attributes::outer_attrs(p); - match p.current() { - // test record_pat_field - // fn foo() { - // let S { 0: 1 } = (); - // let S { x: 1 } = (); - // let S { #[cfg(any())] x: 1 } = (); - // } - IDENT | INT_NUMBER if p.nth(1) == T![:] => { - name_ref_or_index(p); - p.bump(T![:]); - pattern(p); - } - T![box] => { - // FIXME: not all box patterns should be allowed - box_pat(p); - } - _ => { - ident_pat(p, false); - } - } + record_pat_field(p); m.complete(p, RECORD_PAT_FIELD); } } diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 5d92a0f9e59..9d4aad2d2b8 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1175,6 +1175,7 @@ impl BoxPat { pub struct RestPat { pub(crate) syntax: SyntaxNode, } +impl ast::HasAttrs for RestPat {} impl RestPat { pub fn dotdot_token(&self) -> Option { support::token(&self.syntax, T![..]) } } @@ -1289,7 +1290,7 @@ pub struct RecordPatFieldList { impl RecordPatFieldList { pub fn l_curly_token(&self) -> Option { support::token(&self.syntax, T!['{']) } pub fn fields(&self) -> AstChildren { support::children(&self.syntax) } - pub fn dotdot_token(&self) -> Option { support::token(&self.syntax, T![..]) } + pub fn rest_pat(&self) -> Option { support::child(&self.syntax) } pub fn r_curly_token(&self) -> Option { support::token(&self.syntax, T!['}']) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -3687,6 +3688,7 @@ impl AstNode for AnyHasAttrs { | MATCH_ARM_LIST | MATCH_ARM | IDENT_PAT + | REST_PAT | RECORD_PAT_FIELD => true, _ => false, } diff --git a/crates/syntax/test_data/parser/inline/ok/0008_path_part.rast b/crates/syntax/test_data/parser/inline/ok/0008_path_part.rast index ff813071288..c20e41ffae7 100644 --- a/crates/syntax/test_data/parser/inline/ok/0008_path_part.rast +++ b/crates/syntax/test_data/parser/inline/ok/0008_path_part.rast @@ -62,7 +62,8 @@ SOURCE_FILE@0..103 RECORD_PAT_FIELD_LIST@66..72 L_CURLY@66..67 "{" WHITESPACE@67..68 " " - DOT2@68..70 ".." + REST_PAT@68..70 + DOT2@68..70 ".." WHITESPACE@70..71 " " R_CURLY@71..72 "}" WHITESPACE@72..73 " " diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast index 4c44da9d555..761438d2ec6 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast @@ -1,5 +1,5 @@ -SOURCE_FILE@0..119 - FN@0..118 +SOURCE_FILE@0..156 + FN@0..155 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..6 @@ -8,8 +8,8 @@ SOURCE_FILE@0..119 L_PAREN@6..7 "(" R_PAREN@7..8 ")" WHITESPACE@8..9 " " - BLOCK_EXPR@9..118 - STMT_LIST@9..118 + BLOCK_EXPR@9..155 + STMT_LIST@9..155 L_CURLY@9..10 "{" WHITESPACE@10..15 "\n " LET_STMT@15..29 @@ -89,7 +89,8 @@ SOURCE_FILE@0..119 UNDERSCORE@78..79 "_" COMMA@79..80 "," WHITESPACE@80..81 " " - DOT2@81..83 ".." + REST_PAT@81..83 + DOT2@81..83 ".." R_CURLY@83..84 "}" WHITESPACE@84..85 " " EQ@85..86 "=" @@ -128,6 +129,47 @@ SOURCE_FILE@0..119 L_PAREN@113..114 "(" R_PAREN@114..115 ")" SEMICOLON@115..116 ";" - WHITESPACE@116..117 "\n" - R_CURLY@117..118 "}" - WHITESPACE@118..119 "\n" + WHITESPACE@116..121 "\n " + LET_STMT@121..153 + LET_KW@121..124 "let" + WHITESPACE@124..125 " " + RECORD_PAT@125..147 + PATH@125..126 + PATH_SEGMENT@125..126 + NAME_REF@125..126 + IDENT@125..126 "S" + WHITESPACE@126..127 " " + RECORD_PAT_FIELD_LIST@127..147 + L_CURLY@127..128 "{" + WHITESPACE@128..129 " " + REST_PAT@129..145 + ATTR@129..142 + POUND@129..130 "#" + L_BRACK@130..131 "[" + META@131..141 + PATH@131..134 + PATH_SEGMENT@131..134 + NAME_REF@131..134 + IDENT@131..134 "cfg" + TOKEN_TREE@134..141 + L_PAREN@134..135 "(" + IDENT@135..138 "any" + TOKEN_TREE@138..140 + L_PAREN@138..139 "(" + R_PAREN@139..140 ")" + R_PAREN@140..141 ")" + R_BRACK@141..142 "]" + WHITESPACE@142..143 " " + DOT2@143..145 ".." + WHITESPACE@145..146 " " + R_CURLY@146..147 "}" + WHITESPACE@147..148 " " + EQ@148..149 "=" + WHITESPACE@149..150 " " + TUPLE_EXPR@150..152 + L_PAREN@150..151 "(" + R_PAREN@151..152 ")" + SEMICOLON@152..153 ";" + WHITESPACE@153..154 "\n" + R_CURLY@154..155 "}" + WHITESPACE@155..156 "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs index da3412fa8a9..0bfaae7c4d0 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs @@ -3,4 +3,5 @@ fn foo() { let S { f, ref mut g } = (); let S { h: _, ..} = (); let S { h: _, } = (); + let S { #[cfg(any())] .. } = (); }