Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/parser/src/grammar/expressions.rs18
-rw-r--r--crates/parser/src/grammar/items/adt.rs5
-rw-r--r--crates/parser/test_data/generated/runner.rs12
-rw-r--r--crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast59
-rw-r--r--crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs4
-rw-r--r--crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast70
-rw-r--r--crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs2
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_field_default_values.rast28
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_field_default_values.rs1
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_lit.rast47
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_lit.rs2
-rw-r--r--crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast39
-rw-r--r--crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs3
-rw-r--r--crates/syntax/rust.ungram2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs4
15 files changed, 280 insertions, 16 deletions
diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs
index 389c01933c..fe1316c9bf 100644
--- a/crates/parser/src/grammar/expressions.rs
+++ b/crates/parser/src/grammar/expressions.rs
@@ -678,6 +678,8 @@ fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike
// S { x };
// S { x, y: 32, };
// S { x, y: 32, ..Default::default() };
+// S { x, y: 32, .. };
+// S { .. };
// S { x: ::default() };
// TupleStruct { 0: 1 };
// }
@@ -709,6 +711,8 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// fn main() {
// S { field ..S::default() }
// S { 0 ..S::default() }
+ // S { field .. }
+ // S { 0 .. }
// }
name_ref_or_index(p);
p.error("expected `:`");
@@ -739,7 +743,13 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// S { .. } = S {};
// }
- // We permit `.. }` on the left-hand side of a destructuring assignment.
+ // test struct_initializer_with_defaults
+ // fn foo() {
+ // let _s = S { .. };
+ // }
+
+ // We permit `.. }` on the left-hand side of a destructuring assignment
+ // or defaults values.
if !p.at(T!['}']) {
expr(p);
@@ -750,6 +760,12 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// S { ..x, a: 0 }
// }
+ // test_err comma_after_default_values_syntax
+ // fn foo() {
+ // S { .., };
+ // S { .., a: 0 }
+ // }
+
// Do not bump, so we can support additional fields after this comma.
p.error("cannot use a comma after the base struct");
}
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
index 21078175c0..9a16c9db6d 100644
--- a/crates/parser/src/grammar/items/adt.rs
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -135,6 +135,11 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
name(p);
p.expect(T![:]);
types::type_(p);
+ // test record_field_default_values
+ // struct S { f: f32 = 0.0 }
+ if p.eat(T![=]) {
+ expressions::expr(p);
+ }
m.complete(p, RECORD_FIELD);
} else {
m.abandon(p);
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index b9f87b6af2..c8ea8c547a 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -482,6 +482,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/record_field_attrs.rs");
}
#[test]
+ fn record_field_default_values() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/record_field_default_values.rs");
+ }
+ #[test]
fn record_field_list() {
run_and_expect_no_errors("test_data/parser/inline/ok/record_field_list.rs");
}
@@ -544,6 +548,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/stmt_postfix_expr_ambiguity.rs");
}
#[test]
+ fn struct_initializer_with_defaults() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/struct_initializer_with_defaults.rs");
+ }
+ #[test]
fn struct_item() { run_and_expect_no_errors("test_data/parser/inline/ok/struct_item.rs"); }
#[test]
fn trait_alias() { run_and_expect_no_errors("test_data/parser/inline/ok/trait_alias.rs"); }
@@ -719,6 +727,10 @@ mod err {
);
}
#[test]
+ fn comma_after_default_values_syntax() {
+ run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
+ }
+ #[test]
fn crate_visibility_empty_recover() {
run_and_expect_errors("test_data/parser/inline/err/crate_visibility_empty_recover.rs");
}
diff --git a/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast b/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast
new file mode 100644
index 0000000000..feb617e1aa
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast
@@ -0,0 +1,59 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 21: expected expression
+error 36: expected expression
+error 37: expected COMMA
diff --git a/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs b/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs
new file mode 100644
index 0000000000..f1ecdf89fa
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ S { .., };
+ S { .., a: 0 }
+}
diff --git a/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast b/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
index 08ae906421..12b4e233e3 100644
--- a/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
+++ b/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
@@ -44,6 +44,56 @@ SOURCE_FILE
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "field"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
RECORD_EXPR
PATH
PATH_SEGMENT
@@ -58,20 +108,6 @@ SOURCE_FILE
INT_NUMBER "0"
WHITESPACE " "
DOT2 ".."
- CALL_EXPR
- PATH_EXPR
- PATH
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "S"
- COLON2 "::"
- PATH_SEGMENT
- NAME_REF
- IDENT "default"
- ARG_LIST
- L_PAREN "("
- R_PAREN ")"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
@@ -82,3 +118,9 @@ error 25: expected COMMA
error 42: expected SEMICOLON
error 52: expected `:`
error 52: expected COMMA
+error 69: expected SEMICOLON
+error 83: expected `:`
+error 83: expected COMMA
+error 88: expected SEMICOLON
+error 98: expected `:`
+error 98: expected COMMA
diff --git a/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs b/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
index 65398ccb88..416cd763fd 100644
--- a/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
+++ b/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
@@ -1,4 +1,6 @@
fn main() {
S { field ..S::default() }
S { 0 ..S::default() }
+ S { field .. }
+ S { 0 .. }
}
diff --git a/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
new file mode 100644
index 0000000000..33088f2cab
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ FLOAT_NUMBER "0.0"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs
new file mode 100644
index 0000000000..d7b38944a8
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs
@@ -0,0 +1 @@
+struct S { f: f32 = 0.0 }
diff --git a/crates/parser/test_data/parser/inline/ok/record_lit.rast b/crates/parser/test_data/parser/inline/ok/record_lit.rast
index 00948c322f..b868da55bc 100644
--- a/crates/parser/test_data/parser/inline/ok/record_lit.rast
+++ b/crates/parser/test_data/parser/inline/ok/record_lit.rast
@@ -131,6 +131,53 @@ SOURCE_FILE
L_CURLY "{"
WHITESPACE " "
RECORD_EXPR_FIELD
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "32"
+ COMMA ","
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
NAME_REF
IDENT "x"
COLON ":"
diff --git a/crates/parser/test_data/parser/inline/ok/record_lit.rs b/crates/parser/test_data/parser/inline/ok/record_lit.rs
index 86411fbb7d..42895f759b 100644
--- a/crates/parser/test_data/parser/inline/ok/record_lit.rs
+++ b/crates/parser/test_data/parser/inline/ok/record_lit.rs
@@ -3,6 +3,8 @@ fn foo() {
S { x };
S { x, y: 32, };
S { x, y: 32, ..Default::default() };
+ S { x, y: 32, .. };
+ S { .. };
S { x: ::default() };
TupleStruct { 0: 1 };
}
diff --git a/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast b/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast
new file mode 100644
index 0000000000..987e219ae8
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_s"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs b/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs
new file mode 100644
index 0000000000..e08204f94c
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ let _s = S { .. };
+}
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 4e2a70d6cd..bbb8413cbc 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -241,7 +241,7 @@ RecordFieldList =
RecordField =
Attr* Visibility?
- Name ':' Type
+ Name ':' Type ('=' Expr)?
TupleFieldList =
'(' fields:(TupleField (',' TupleField)* ','?)? ')'
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 69e2a9f9c1..8f10ea9464 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1539,9 +1539,13 @@ impl ast::HasName for RecordField {}
impl ast::HasVisibility for RecordField {}
impl RecordField {
#[inline]
+ pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ #[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
+ #[inline]
+ pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]