diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index e233317736..0a7be87a0c 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> { 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 aefeca4008..d09fc66e4d 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 { 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 903646149d..132c2ae8c3 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 { support::token(&self.syntax, T![::]) } pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn type_args(&self) -> AstChildren { support::children(&self.syntax) } - pub fn lifetime_args(&self) -> AstChildren { support::children(&self.syntax) } - pub fn assoc_type_args(&self) -> AstChildren { support::children(&self.syntax) } - pub fn const_args(&self) -> AstChildren { support::children(&self.syntax) } + pub fn generic_args(&self) -> AstChildren { support::children(&self.syntax) } pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -86,15 +83,6 @@ impl TypeArg { pub fn ty(&self) -> Option { 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 { - 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 { 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 { + 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 { 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 { 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 { 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 for GenericArg { + fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) } +} +impl From for GenericArg { + fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) } +} +impl From for GenericArg { + fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) } +} +impl From 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 { + 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 for Type { fn from(node: ArrayType) -> Type { Type::ArrayType(node) } } @@ -3380,6 +3422,11 @@ impl From for Stmt { impl From 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 cb4cd49fed..fa18acbb36 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*