diff --git a/crates/parser/src/grammar/items/consts.rs b/crates/parser/src/grammar/items/consts.rs index 9549ec9b4005..8e255985a205 100644 --- a/crates/parser/src/grammar/items/consts.rs +++ b/crates/parser/src/grammar/items/consts.rs @@ -24,6 +24,18 @@ fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { name(p); } + // FIXME: Recover on statics with generic params/where clause. + if is_const { + // test generic_const + // const C: u32 = 0; + // impl Foo { + // const C<'a>: &'a () = &(); + // } + generic_params::opt_generic_param_list(p); + } + // test_err generic_static + // static C: u32 = 0; + if p.at(T![:]) { types::ascription(p); } else { @@ -32,6 +44,20 @@ fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) { if p.eat(T![=]) { expressions::expr(p); } + + if is_const { + // test const_where_clause + // const C: u32 = 0 + // where i32: Copy; + // trait Foo { + // const C: i32 where i32: Copy; + // } + generic_params::opt_where_clause(p); + } + // test_err static_where_clause + // static C: u32 = 0 + // where i32: Copy; + p.expect(T![;]); m.complete(p, if is_const { CONST } else { STATIC }); } diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs index 2ea29345eddc..87ffc99539b7 100644 --- a/crates/parser/test_data/generated/runner.rs +++ b/crates/parser/test_data/generated/runner.rs @@ -139,6 +139,10 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/const_trait_bound.rs"); } #[test] + fn const_where_clause() { + run_and_expect_no_errors("test_data/parser/inline/ok/const_where_clause.rs"); + } + #[test] fn continue_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/continue_expr.rs"); } #[test] fn crate_path() { run_and_expect_no_errors("test_data/parser/inline/ok/crate_path.rs"); } @@ -278,6 +282,8 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs"); } #[test] + fn generic_const() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_const.rs"); } + #[test] fn generic_param_attribute() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs"); } @@ -764,6 +770,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs"); } #[test] + fn generic_static() { run_and_expect_errors("test_data/parser/inline/err/generic_static.rs"); } + #[test] fn impl_type() { run_and_expect_errors("test_data/parser/inline/err/impl_type.rs"); } #[test] fn let_else_right_curly_brace() { @@ -836,6 +844,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/recover_from_missing_const_default.rs"); } #[test] + fn static_where_clause() { + run_and_expect_errors("test_data/parser/inline/err/static_where_clause.rs"); + } + #[test] fn struct_field_recover() { run_and_expect_errors("test_data/parser/inline/err/struct_field_recover.rs"); } diff --git a/crates/parser/test_data/parser/inline/err/generic_static.rast b/crates/parser/test_data/parser/inline/err/generic_static.rast new file mode 100644 index 000000000000..485ad11f233a --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/generic_static.rast @@ -0,0 +1,42 @@ +SOURCE_FILE + STATIC + STATIC_KW "static" + WHITESPACE " " + NAME + IDENT "C" + ERROR + L_ANGLE "<" + ERROR + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + ERROR + R_ANGLE ">" + ERROR + COLON ":" + WHITESPACE " " + ERROR + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + WHITESPACE " " + ERROR + EQ "=" + WHITESPACE " " + ERROR + INT_NUMBER "0" + ERROR + SEMICOLON ";" + WHITESPACE "\n" +error 8: missing type for `const` or `static` +error 8: expected SEMICOLON +error 8: expected an item +error 12: expected an item +error 12: expected an item +error 13: expected an item +error 18: expected an item +error 19: expected an item +error 21: expected an item +error 22: expected an item diff --git a/crates/parser/test_data/parser/inline/err/generic_static.rs b/crates/parser/test_data/parser/inline/err/generic_static.rs new file mode 100644 index 000000000000..d76aa7a205bc --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/generic_static.rs @@ -0,0 +1 @@ +static C: u32 = 0; diff --git a/crates/parser/test_data/parser/inline/err/static_where_clause.rast b/crates/parser/test_data/parser/inline/err/static_where_clause.rast new file mode 100644 index 000000000000..cde3e47ad5c3 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/static_where_clause.rast @@ -0,0 +1,44 @@ +SOURCE_FILE + STATIC + STATIC_KW "static" + WHITESPACE " " + NAME + IDENT "C" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + WHITESPACE "\n" + ERROR + WHERE_KW "where" + WHITESPACE " " + ERROR + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + ERROR + COLON ":" + WHITESPACE " " + ERROR + PATH + PATH_SEGMENT + NAME_REF + IDENT "Copy" + ERROR + SEMICOLON ";" + WHITESPACE "\n" +error 17: expected SEMICOLON +error 18: expected an item +error 27: expected an item +error 27: expected an item +error 33: expected an item +error 33: expected an item diff --git a/crates/parser/test_data/parser/inline/err/static_where_clause.rs b/crates/parser/test_data/parser/inline/err/static_where_clause.rs new file mode 100644 index 000000000000..c330f35da243 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/static_where_clause.rs @@ -0,0 +1,2 @@ +static C: u32 = 0 +where i32: Copy; diff --git a/crates/parser/test_data/parser/inline/ok/const_where_clause.rast b/crates/parser/test_data/parser/inline/ok/const_where_clause.rast new file mode 100644 index 000000000000..12148f6afe4b --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/const_where_clause.rast @@ -0,0 +1,89 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "C" + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME + IDENT "i32" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + WHITESPACE "\n" + WHERE_CLAUSE + WHERE_KW "where" + WHITESPACE " " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Copy" + SEMICOLON ";" + WHITESPACE "\n" + TRAIT + TRAIT_KW "trait" + WHITESPACE " " + NAME + IDENT "Foo" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + WHITESPACE "\n " + CONST + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "C" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + WHERE_CLAUSE + WHERE_KW "where" + WHITESPACE " " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Copy" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/const_where_clause.rs b/crates/parser/test_data/parser/inline/ok/const_where_clause.rs new file mode 100644 index 000000000000..5ad4b2fe8323 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/const_where_clause.rs @@ -0,0 +1,5 @@ +const C: u32 = 0 +where i32: Copy; +trait Foo { + const C: i32 where i32: Copy; +} diff --git a/crates/parser/test_data/parser/inline/ok/generic_const.rast b/crates/parser/test_data/parser/inline/ok/generic_const.rast new file mode 100644 index 000000000000..bf432b99b9de --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/generic_const.rast @@ -0,0 +1,71 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "C" + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME + IDENT "i32" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u32" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + SEMICOLON ";" + WHITESPACE "\n" + IMPL + IMPL_KW "impl" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + WHITESPACE "\n " + CONST + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "C" + GENERIC_PARAM_LIST + L_ANGLE "<" + LIFETIME_PARAM + LIFETIME + LIFETIME_IDENT "'a" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + REF_TYPE + AMP "&" + LIFETIME + LIFETIME_IDENT "'a" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + REF_EXPR + AMP "&" + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/generic_const.rs b/crates/parser/test_data/parser/inline/ok/generic_const.rs new file mode 100644 index 000000000000..ce718a46288d --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/generic_const.rs @@ -0,0 +1,4 @@ +const C: u32 = 0; +impl Foo { + const C<'a>: &'a () = &(); +} diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 673334bd2251..f8f9a51368ef 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -287,8 +287,9 @@ VariantDef = Const = Attr* Visibility? 'default'? - 'const' (Name | '_') ':' Type - ('=' body:Expr)? ';' + 'const' (Name | '_') GenericParamList? ':' Type + ('=' body:Expr)? + WhereClause? ';' Static = Attr* Visibility? diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index fd23cdccd572..21548a8ea639 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -405,6 +405,7 @@ pub struct Const { } impl ast::HasAttrs for Const {} impl ast::HasDocComments for Const {} +impl ast::HasGenericParams for Const {} impl ast::HasName for Const {} impl ast::HasVisibility for Const {} impl Const { @@ -9421,7 +9422,7 @@ impl ast::HasGenericParams for AnyHasGenericParams {} impl AstNode for AnyHasGenericParams { #[inline] fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION) + matches!(kind, CONST | ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION) } #[inline] fn cast(syntax: SyntaxNode) -> Option { @@ -9445,6 +9446,10 @@ impl fmt::Debug for AnyHasGenericParams { f.debug_struct("AnyHasGenericParams").field("syntax", &self.syntax).finish() } } +impl From for AnyHasGenericParams { + #[inline] + fn from(node: Const) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } } +} impl From for AnyHasGenericParams { #[inline] fn from(node: Enum) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } }