From 040b4c800d5279e77a6825fc90cb2921d26c7f95 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Fri, 31 Jul 2020 18:41:37 +0200
Subject: [PATCH] Fix GenericArgs grammar

---
 crates/ra_assists/src/ast_transform.rs      | 16 ++--
 crates/ra_hir_def/src/path/lower.rs         | 42 +++++-----
 crates/ra_syntax/src/ast/generated/nodes.rs | 85 ++++++++++++++++-----
 xtask/src/codegen/rust.ungram               | 14 ++--
 4 files changed, 107 insertions(+), 50 deletions(-)

diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index e233317736e..0a7be87a0c4 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -79,19 +79,25 @@ impl<'a> SubstituteTypeParams<'a> {
         };
 
         // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
-        // trait ref, and then go from the types in the substs back to the syntax)
+        // trait ref, and then go from the types in the substs back to the syntax).
         fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
             let target_trait = impl_def.target_trait()?;
             let path_type = match target_trait {
                 ast::Type::PathType(path) => path,
                 _ => return None,
             };
-            let type_arg_list = path_type.path()?.segment()?.generic_arg_list()?;
+            let generic_arg_list = path_type.path()?.segment()?.generic_arg_list()?;
+
             let mut result = Vec::new();
-            for type_arg in type_arg_list.type_args() {
-                let type_arg: ast::TypeArg = type_arg;
-                result.push(type_arg.ty()?);
+            for generic_arg in generic_arg_list.generic_args() {
+                match generic_arg {
+                    ast::GenericArg::TypeArg(type_arg) => result.push(type_arg.ty()?),
+                    ast::GenericArg::AssocTypeArg(_)
+                    | ast::GenericArg::LifetimeArg(_)
+                    | ast::GenericArg::ConstArg(_) => (),
+                }
             }
+
             Some(result)
         }
     }
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
index aefeca40083..d09fc66e4dc 100644
--- a/crates/ra_hir_def/src/path/lower.rs
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -151,30 +151,34 @@ pub(super) fn lower_generic_args(
     node: ast::GenericArgList,
 ) -> Option<GenericArgs> {
     let mut args = Vec::new();
-    for type_arg in node.type_args() {
-        let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
-        args.push(GenericArg::Type(type_ref));
-    }
-    // lifetimes ignored for now
     let mut bindings = Vec::new();
-    for assoc_type_arg in node.assoc_type_args() {
-        let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg;
-        if let Some(name_ref) = assoc_type_arg.name_ref() {
-            let name = name_ref.as_name();
-            let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
-            let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
-            } else {
-                Vec::new()
-            };
-            bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
+    for generic_arg in node.generic_args() {
+        match generic_arg {
+            ast::GenericArg::TypeArg(type_arg) => {
+                let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
+                args.push(GenericArg::Type(type_ref));
+            }
+            ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
+                if let Some(name_ref) = assoc_type_arg.name_ref() {
+                    let name = name_ref.as_name();
+                    let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
+                    let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
+                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
+                    } else {
+                        Vec::new()
+                    };
+                    bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
+                }
+            }
+            // Lifetimes and constants are ignored for now.
+            ast::GenericArg::LifetimeArg(_) | ast::GenericArg::ConstArg(_) => (),
         }
     }
+
     if args.is_empty() && bindings.is_empty() {
-        None
-    } else {
-        Some(GenericArgs { args, has_self_type: false, bindings })
+        return None;
     }
+    Some(GenericArgs { args, has_self_type: false, bindings })
 }
 
 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs
index 903646149de..132c2ae8c34 100644
--- a/crates/ra_syntax/src/ast/generated/nodes.rs
+++ b/crates/ra_syntax/src/ast/generated/nodes.rs
@@ -46,10 +46,7 @@ pub struct GenericArgList {
 impl GenericArgList {
     pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
     pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    pub fn type_args(&self) -> AstChildren<TypeArg> { support::children(&self.syntax) }
-    pub fn lifetime_args(&self) -> AstChildren<LifetimeArg> { support::children(&self.syntax) }
-    pub fn assoc_type_args(&self) -> AstChildren<AssocTypeArg> { support::children(&self.syntax) }
-    pub fn const_args(&self) -> AstChildren<ConstArg> { support::children(&self.syntax) }
+    pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) }
     pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -86,15 +83,6 @@ impl TypeArg {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct LifetimeArg {
-    pub(crate) syntax: SyntaxNode,
-}
-impl LifetimeArg {
-    pub fn lifetime_token(&self) -> Option<SyntaxToken> {
-        support::token(&self.syntax, T![lifetime])
-    }
-}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AssocTypeArg {
     pub(crate) syntax: SyntaxNode,
 }
@@ -105,6 +93,15 @@ impl AssocTypeArg {
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct LifetimeArg {
+    pub(crate) syntax: SyntaxNode,
+}
+impl LifetimeArg {
+    pub fn lifetime_token(&self) -> Option<SyntaxToken> {
+        support::token(&self.syntax, T![lifetime])
+    }
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ConstArg {
     pub(crate) syntax: SyntaxNode,
 }
@@ -1272,6 +1269,13 @@ impl MacroStmts {
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum GenericArg {
+    TypeArg(TypeArg),
+    AssocTypeArg(AssocTypeArg),
+    LifetimeArg(LifetimeArg),
+    ConstArg(ConstArg),
+}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Type {
     ArrayType(ArrayType),
     DynTraitType(DynTraitType),
@@ -1489,8 +1493,8 @@ impl AstNode for TypeArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for LifetimeArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
+impl AstNode for AssocTypeArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -1500,8 +1504,8 @@ impl AstNode for LifetimeArg {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
-impl AstNode for AssocTypeArg {
-    fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
+impl AstNode for LifetimeArg {
+    fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         if Self::can_cast(syntax.kind()) {
             Some(Self { syntax })
@@ -2765,6 +2769,44 @@ impl AstNode for MacroStmts {
     }
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl From<TypeArg> for GenericArg {
+    fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) }
+}
+impl From<AssocTypeArg> for GenericArg {
+    fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) }
+}
+impl From<LifetimeArg> for GenericArg {
+    fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) }
+}
+impl From<ConstArg> for GenericArg {
+    fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
+}
+impl AstNode for GenericArg {
+    fn can_cast(kind: SyntaxKind) -> bool {
+        match kind {
+            TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true,
+            _ => false,
+        }
+    }
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }),
+            ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
+            LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
+            CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            GenericArg::TypeArg(it) => &it.syntax,
+            GenericArg::AssocTypeArg(it) => &it.syntax,
+            GenericArg::LifetimeArg(it) => &it.syntax,
+            GenericArg::ConstArg(it) => &it.syntax,
+        }
+    }
+}
 impl From<ArrayType> for Type {
     fn from(node: ArrayType) -> Type { Type::ArrayType(node) }
 }
@@ -3380,6 +3422,11 @@ impl From<Item> for Stmt {
 impl From<LetStmt> for Stmt {
     fn from(node: LetStmt) -> Stmt { Stmt::LetStmt(node) }
 }
+impl std::fmt::Display for GenericArg {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for Type {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -3470,12 +3517,12 @@ impl std::fmt::Display for TypeArg {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for LifetimeArg {
+impl std::fmt::Display for AssocTypeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
-impl std::fmt::Display for AssocTypeArg {
+impl std::fmt::Display for LifetimeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
     }
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
index cb4cd49fed1..fa18acbb36f 100644
--- a/xtask/src/codegen/rust.ungram
+++ b/xtask/src/codegen/rust.ungram
@@ -8,12 +8,13 @@ PathSegment =
 | '<' PathType ('as' PathType)? '>'
 
 GenericArgList =
-  '::'? '<'
-    TypeArg*
-    LifetimeArg*
-    AssocTypeArg*
-    ConstArg*
-  '>'
+  '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'
+
+GenericArg =
+  TypeArg
+| AssocTypeArg
+| LifetimeArg
+| ConstArg
 
 TypeArg =
   Type
@@ -27,7 +28,6 @@ LifetimeArg =
 ConstArg =
   Literal | BlockExpr BlockExpr
 
-
 SourceFile =
   'shebang'?
   Attr*