about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChayim Refael Friedman <chayimfr@gmail.com>2025-04-21 02:11:56 +0300
committerChayim Refael Friedman <chayimfr@gmail.com>2025-04-21 02:11:56 +0300
commitc9e272ea0a3a4a1d9be4be634f8985774b36f5d3 (patch)
tree08a6abdda911b145353f70d8bcb1a08e9f824e60
parent42de0a525b7747bb8e901a39b90c2bf529883ffd (diff)
downloadrust-c9e272ea0a3a4a1d9be4be634f8985774b36f5d3.tar.gz
rust-c9e272ea0a3a4a1d9be4be634f8985774b36f5d3.zip
Parse generic consts
A lang team experiment, https://github.com/rust-lang/rust/issues/113521.
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rast44
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rast89
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rast71
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs7
12 files changed, 305 insertions, 3 deletions
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs
index 9549ec9b400..8e255985a20 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs
+++ b/src/tools/rust-analyzer/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<i32>: u32 = 0;
+        // impl Foo {
+        //     const C<'a>: &'a () = &();
+        // }
+        generic_params::opt_generic_param_list(p);
+    }
+    // test_err generic_static
+    // static C<i32>: 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<i32>: 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/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 2ea29345edd..87ffc99539b 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rast
new file mode 100644
index 00000000000..485ad11f233
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rs
new file mode 100644
index 00000000000..d76aa7a205b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_static.rs
@@ -0,0 +1 @@
+static C<i32>: u32 = 0;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rast
new file mode 100644
index 00000000000..cde3e47ad5c
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/static_where_clause.rs
new file mode 100644
index 00000000000..c330f35da24
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rast
new file mode 100644
index 00000000000..12148f6afe4
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rs
new file mode 100644
index 00000000000..5ad4b2fe832
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_where_clause.rs
@@ -0,0 +1,5 @@
+const C<i32>: u32 = 0
+where i32: Copy;
+trait Foo {
+    const C: i32 where i32: Copy;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rast
new file mode 100644
index 00000000000..bf432b99b9d
--- /dev/null
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rs
new file mode 100644
index 00000000000..ce718a46288
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_const.rs
@@ -0,0 +1,4 @@
+const C<i32>: u32 = 0;
+impl Foo {
+    const C<'a>: &'a () = &();
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 673334bd225..f8f9a51368e 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index fd23cdccd57..21548a8ea63 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/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<Self> {
@@ -9445,6 +9446,10 @@ impl fmt::Debug for AnyHasGenericParams {
         f.debug_struct("AnyHasGenericParams").field("syntax", &self.syntax).finish()
     }
 }
+impl From<Const> for AnyHasGenericParams {
+    #[inline]
+    fn from(node: Const) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } }
+}
 impl From<Enum> for AnyHasGenericParams {
     #[inline]
     fn from(node: Enum) -> AnyHasGenericParams { AnyHasGenericParams { syntax: node.syntax } }