diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 4c1a3344ec..372cf9aba8 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -818,7 +818,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 5fe1a7b13b..9da94ce162 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs @@ -205,46 +205,64 @@ 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!['{'])); let m = p.start(); p.bump(T!['{']); while !p.at(EOF) && !p.at(T!['}']) { + let m = p.start(); + attributes::outer_attrs(p); + match p.current() { // A trailing `..` is *not* treated as a REST_PAT. - T![.] if p.at(T![..]) => p.bump(T![..]), - T!['{'] => error_block(p, "expected ident"), - + T![.] if p.at(T![..]) => { + p.bump(T![..]); + m.complete(p, REST_PAT); + } + T!['{'] => { + error_block(p, "expected ident"); + m.abandon(p); + } _ => { - 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/Cargo.toml b/crates/syntax/Cargo.toml index f889fa2a2c..3c5adb97fb 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -29,7 +29,7 @@ rayon = "1" expect-test = "1.1" proc-macro2 = "1.0.8" quote = "1.0.2" -ungrammar = "=1.14.5" +ungrammar = "=1.14.6" test_utils = { path = "../test_utils" } sourcegen = { path = "../sourcegen" } diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 1810033e84..f69c873663 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1290,6 +1290,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![..]) } } @@ -1418,7 +1419,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!['}']) } } @@ -3836,6 +3837,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 ff81307128..c20e41ffae 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 4c44da9d55..761438d2ec 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 da3412fa8a..0bfaae7c4d 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())] .. } = (); }