Repository: rust-analyzer/rust-analyzer
Pull request #2724 (2020-01-02 05:49:27)

Improve const generic parsing
Add support for generic arguments in:

`impl` type parameters:

```rust
impl<const N: u32> Bar<N> {}
```

type args:

```rust
type A = B<1, { 2 }>;
test::<10>();
```

matklad: Yeah, the changes look good, but unfortunatelly I've moved grammar.ron [here](https://github.com/rust-analyzer/rust-analyzer/blob/07340a62cc1b34efcebfc9f4cfc42f655edd2fc8/xtask/src/ast_src.rs) without checking if there are outstanding PR which will conflict with this :( Sorry about that!

bors delegate+
bors[bot]: :v: mchesser can now approve this pull request. To approve and merge a pull request, simply reply with `bors r+`. More detailed instructions are available [here](https://bors.tech/documentation/getting-started/#reviewing-pull-requests).

Patch:
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
index 2c560e8247..964fd30412 100644
--- a/crates/ra_parser/src/grammar/items/traits.rs
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -100,6 +100,8 @@ pub(crate) fn impl_item_list(p: &mut Parser) {
     m.complete(p, ITEM_LIST);
 }
 
+// test impl_type_params
+// impl<const N: u32> Bar<N> {}
 fn choose_type_params_over_qpath(p: &Parser) -> bool {
     // There's an ambiguity between generic parameters and qualified paths in impls.
     // If we see `<` it may start both, so we have to inspect some following tokens.
@@ -107,6 +109,7 @@ fn choose_type_params_over_qpath(p: &Parser) -> bool {
     // but not qualified paths (with one exception):
     //     `<` `>` - empty generic parameters
     //     `<` `#` - generic parameters with attributes
+    //     `<` `const` - const generic parameters
     //     `<` (LIFETIME|IDENT) `>` - single generic parameter
     //     `<` (LIFETIME|IDENT) `,` - first generic parameter in a list
     //     `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
@@ -119,7 +122,7 @@ fn choose_type_params_over_qpath(p: &Parser) -> bool {
     if !p.at(T![<]) {
         return false;
     }
-    if p.nth(1) == T![#] || p.nth(1) == T![>] {
+    if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == CONST_KW {
         return true;
     }
     (p.nth(1) == LIFETIME || p.nth(1) == IDENT)
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index 7256c2697c..33d9973e99 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -26,7 +26,7 @@ pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) {
 }
 
 // test type_arg
-// type A = B<'static, i32, Item=u64>;
+// type A = B<'static, i32, 1, { 2 }, Item=u64>;
 fn type_arg(p: &mut Parser) {
     let m = p.start();
     match p.current() {
@@ -47,6 +47,14 @@ fn type_arg(p: &mut Parser) {
             types::type_(p);
             m.complete(p, ASSOC_TYPE_ARG);
         }
+        T!['{'] => {
+            expressions::block(p);
+            m.complete(p, CONST_ARG);
+        }
+        k if k.is_literal() => {
+            p.bump(k);
+            m.complete(p, CONST_ARG);
+        }
         _ => {
             types::type_(p);
             m.complete(p, TYPE_ARG);
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index 262c545e4c..4b301d67af 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -234,6 +234,7 @@ pub enum SyntaxKind {
     LIFETIME_ARG,
     TYPE_ARG,
     ASSOC_TYPE_ARG,
+    CONST_ARG,
     PARAM_LIST,
     PARAM,
     SELF_PARAM,
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 2eb4b14d20..33d5578e70 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -3114,6 +3114,9 @@ impl TypeArgList {
     pub fn assoc_type_args(&self) -> AstChildren<AssocTypeArg> {
         AstChildren::new(&self.syntax)
     }
+    pub fn const_arg(&self) -> AstChildren<ConstArg> {
+        AstChildren::new(&self.syntax)
+    }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct TypeArg {
@@ -3196,6 +3199,36 @@ impl AstNode for LifetimeArg {
 }
 impl LifetimeArg {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ConstArg {
+    pub(crate) syntax: SyntaxNode,
+}
+impl AstNode for ConstArg {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        match kind {
+            CONST_ARG => true,
+            _ => false,
+        }
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        &self.syntax
+    }
+}
+impl ConstArg {
+    pub fn literal(&self) -> Option<Literal> {
+        AstChildren::new(&self.syntax).next()
+    }
+    pub fn block_expr(&self) -> Option<BlockExpr> {
+        AstChildren::new(&self.syntax).next()
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct MacroItems {
     pub(crate) syntax: SyntaxNode,
 }
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index d494a4a383..67d1f41bca 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -206,6 +206,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
         "LIFETIME_ARG",
         "TYPE_ARG",
         "ASSOC_TYPE_ARG",
+        "CONST_ARG",
         "PARAM_LIST",
         "PARAM",
         "SELF_PARAM",
@@ -511,10 +512,12 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
             type_args: [TypeArg],
             lifetime_args: [LifetimeArg],
             assoc_type_args: [AssocTypeArg],
+            const_arg: [ConstArg],
         }
         struct TypeArg { TypeRef }
         struct AssocTypeArg { NameRef, TypeRef }
         struct LifetimeArg {}
+        struct ConstArg { Literal, BlockExpr }
 
         struct MacroItems: ModuleItemOwner, FnDefOwner { }
 


Test patch:
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rs b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rs
index 385c431316..0d07d76514 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rs
@@ -1,1 +1,1 @@
-type A = B<'static, i32, Item=u64>;
+type A = B<'static, i32, 1, { 2 }, Item=u64>;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.txt b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.txt
index 4786bf77ac..025faf5cae 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.txt
@@ -1,5 +1,5 @@
-SOURCE_FILE@[0; 36)
-  TYPE_ALIAS_DEF@[0; 35)
+SOURCE_FILE@[0; 46)
+  TYPE_ALIAS_DEF@[0; 45)
     TYPE_KW@[0; 4) "type"
     WHITESPACE@[4; 5) " "
     NAME@[5; 6)
@@ -7,12 +7,12 @@ SOURCE_FILE@[0; 36)
     WHITESPACE@[6; 7) " "
     EQ@[7; 8) "="
     WHITESPACE@[8; 9) " "
-    PATH_TYPE@[9; 34)
-      PATH@[9; 34)
-        PATH_SEGMENT@[9; 34)
+    PATH_TYPE@[9; 44)
+      PATH@[9; 44)
+        PATH_SEGMENT@[9; 44)
           NAME_REF@[9; 10)
             IDENT@[9; 10) "B"
-          TYPE_ARG_LIST@[10; 34)
+          TYPE_ARG_LIST@[10; 44)
             L_ANGLE@[10; 11) "<"
             LIFETIME_ARG@[11; 18)
               LIFETIME@[11; 18) "\'static"
@@ -26,15 +26,30 @@ SOURCE_FILE@[0; 36)
                       IDENT@[20; 23) "i32"
             COMMA@[23; 24) ","
             WHITESPACE@[24; 25) " "
-            ASSOC_TYPE_ARG@[25; 33)
-              NAME_REF@[25; 29)
-                IDENT@[25; 29) "Item"
-              EQ@[29; 30) "="
-              PATH_TYPE@[30; 33)
-                PATH@[30; 33)
-                  PATH_SEGMENT@[30; 33)
-                    NAME_REF@[30; 33)
-                      IDENT@[30; 33) "u64"
-            R_ANGLE@[33; 34) ">"
-    SEMI@[34; 35) ";"
-  WHITESPACE@[35; 36) "\n"
+            CONST_ARG@[25; 26)
+              INT_NUMBER@[25; 26) "1"
+            COMMA@[26; 27) ","
+            WHITESPACE@[27; 28) " "
+            CONST_ARG@[28; 33)
+              BLOCK_EXPR@[28; 33)
+                BLOCK@[28; 33)
+                  L_CURLY@[28; 29) "{"
+                  WHITESPACE@[29; 30) " "
+                  LITERAL@[30; 31)
+                    INT_NUMBER@[30; 31) "2"
+                  WHITESPACE@[31; 32) " "
+                  R_CURLY@[32; 33) "}"
+            COMMA@[33; 34) ","
+            WHITESPACE@[34; 35) " "
+            ASSOC_TYPE_ARG@[35; 43)
+              NAME_REF@[35; 39)
+                IDENT@[35; 39) "Item"
+              EQ@[39; 40) "="
+              PATH_TYPE@[40; 43)
+                PATH@[40; 43)
+                  PATH_SEGMENT@[40; 43)
+                    NAME_REF@[40; 43)
+                      IDENT@[40; 43) "u64"
+            R_ANGLE@[43; 44) ">"
+    SEMI@[44; 45) ";"
+  WHITESPACE@[45; 46) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rs b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rs
new file mode 100644
index 0000000000..cb0a105c29
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rs
@@ -0,0 +1,1 @@
+impl<const N: u32> Bar<N> {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.txt b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.txt
new file mode 100644
index 0000000000..47fadef854
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.txt
@@ -0,0 +1,38 @@
+SOURCE_FILE@[0; 29)
+  IMPL_BLOCK@[0; 28)
+    IMPL_KW@[0; 4) "impl"
+    TYPE_PARAM_LIST@[4; 18)
+      L_ANGLE@[4; 5) "<"
+      CONST_PARAM@[5; 17)
+        CONST_KW@[5; 10) "const"
+        WHITESPACE@[10; 11) " "
+        NAME@[11; 12)
+          IDENT@[11; 12) "N"
+        COLON@[12; 13) ":"
+        WHITESPACE@[13; 14) " "
+        PATH_TYPE@[14; 17)
+          PATH@[14; 17)
+            PATH_SEGMENT@[14; 17)
+              NAME_REF@[14; 17)
+                IDENT@[14; 17) "u32"
+      R_ANGLE@[17; 18) ">"
+    WHITESPACE@[18; 19) " "
+    PATH_TYPE@[19; 25)
+      PATH@[19; 25)
+        PATH_SEGMENT@[19; 25)
+          NAME_REF@[19; 22)
+            IDENT@[19; 22) "Bar"
+          TYPE_ARG_LIST@[22; 25)
+            L_ANGLE@[22; 23) "<"
+            TYPE_ARG@[23; 24)
+              PATH_TYPE@[23; 24)
+                PATH@[23; 24)
+                  PATH_SEGMENT@[23; 24)
+                    NAME_REF@[23; 24)
+                      IDENT@[23; 24) "N"
+            R_ANGLE@[24; 25) ">"
+    WHITESPACE@[25; 26) " "
+    ITEM_LIST@[26; 28)
+      L_CURLY@[26; 27) "{"
+      R_CURLY@[27; 28) "}"
+  WHITESPACE@[28; 29) "\n"