about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-12-30 11:39:29 +0000
committerGitHub <noreply@github.com>2024-12-30 11:39:29 +0000
commit20a7bf12eb7d5f50996e5d87b1eaad0381bd1660 (patch)
tree2c28e12493abd2c90afde2b68f647ce1fd842150
parent56e05dc2bc9c0460e4797de99aab5b11283b535b (diff)
parent33f1f1d787f9f3a41a1983219d27d24f741c9fb1 (diff)
downloadrust-20a7bf12eb7d5f50996e5d87b1eaad0381bd1660.tar.gz
rust-20a7bf12eb7d5f50996e5d87b1eaad0381bd1660.zip
Merge pull request #18790 from ChayimFriedman2/proper-make
internal: Create a quoting mechanism instead of textual AST make
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs325
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast.rs8
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs1078
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs104
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs191
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/grammar.rs23
8 files changed, 1672 insertions, 60 deletions
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 7f3abcccc47..e303b3c1109 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -203,6 +203,8 @@ new_ret_no_self = "allow"
 useless_asref = "allow"
 # Has false positives
 assigning_clones = "allow"
+# Does not work with macros
+vec_init_then_push = "allow"
 
 ## Following lints should be tackled at some point
 too_many_arguments = "allow"
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
index f4b4c22d98d..9d01ec00f83 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs
@@ -85,7 +85,6 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
 
                 let is_unsafe = func_node.unsafe_token().is_some();
                 let ty = make::ty_fn_ptr(
-                    None,
                     is_unsafe,
                     func_node.abi(),
                     fn_params_vec.into_iter(),
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 0c9c6ffd715..318f71a2d4d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -331,6 +331,331 @@ pub enum SyntaxKind {
 }
 use self::SyntaxKind::*;
 impl SyntaxKind {
+    #[allow(unreachable_patterns)]
+    pub const fn text(self) -> &'static str {
+        match self {
+            TOMBSTONE
+            | EOF
+            | __LAST
+            | BYTE
+            | BYTE_STRING
+            | CHAR
+            | C_STRING
+            | FLOAT_NUMBER
+            | INT_NUMBER
+            | RAW_BYTE_STRING
+            | RAW_C_STRING
+            | RAW_STRING
+            | STRING
+            | ABI
+            | ADT
+            | ARG_LIST
+            | ARRAY_EXPR
+            | ARRAY_TYPE
+            | ASM_CLOBBER_ABI
+            | ASM_CONST
+            | ASM_DIR_SPEC
+            | ASM_EXPR
+            | ASM_LABEL
+            | ASM_OPERAND
+            | ASM_OPERAND_EXPR
+            | ASM_OPERAND_NAMED
+            | ASM_OPTION
+            | ASM_OPTIONS
+            | ASM_PIECE
+            | ASM_REG_OPERAND
+            | ASM_REG_SPEC
+            | ASM_SYM
+            | ASSOC_ITEM
+            | ASSOC_ITEM_LIST
+            | ASSOC_TYPE_ARG
+            | ATTR
+            | AWAIT_EXPR
+            | BECOME_EXPR
+            | BIN_EXPR
+            | BLOCK_EXPR
+            | BOX_PAT
+            | BREAK_EXPR
+            | CALL_EXPR
+            | CAST_EXPR
+            | CLOSURE_BINDER
+            | CLOSURE_EXPR
+            | CONST
+            | CONST_ARG
+            | CONST_BLOCK_PAT
+            | CONST_PARAM
+            | CONTINUE_EXPR
+            | DYN_TRAIT_TYPE
+            | ENUM
+            | EXPR
+            | EXPR_STMT
+            | EXTERN_BLOCK
+            | EXTERN_CRATE
+            | EXTERN_ITEM
+            | EXTERN_ITEM_LIST
+            | FIELD_EXPR
+            | FIELD_LIST
+            | FN
+            | FN_PTR_TYPE
+            | FORMAT_ARGS_ARG
+            | FORMAT_ARGS_EXPR
+            | FOR_EXPR
+            | FOR_TYPE
+            | GENERIC_ARG
+            | GENERIC_ARG_LIST
+            | GENERIC_PARAM
+            | GENERIC_PARAM_LIST
+            | IDENT_PAT
+            | IF_EXPR
+            | IMPL
+            | IMPL_TRAIT_TYPE
+            | INDEX_EXPR
+            | INFER_TYPE
+            | ITEM
+            | ITEM_LIST
+            | LABEL
+            | LET_ELSE
+            | LET_EXPR
+            | LET_STMT
+            | LIFETIME
+            | LIFETIME_ARG
+            | LIFETIME_PARAM
+            | LITERAL
+            | LITERAL_PAT
+            | LOOP_EXPR
+            | MACRO_CALL
+            | MACRO_DEF
+            | MACRO_EXPR
+            | MACRO_ITEMS
+            | MACRO_PAT
+            | MACRO_RULES
+            | MACRO_STMTS
+            | MACRO_TYPE
+            | MATCH_ARM
+            | MATCH_ARM_LIST
+            | MATCH_EXPR
+            | MATCH_GUARD
+            | META
+            | METHOD_CALL_EXPR
+            | MODULE
+            | NAME
+            | NAME_REF
+            | NEVER_TYPE
+            | OFFSET_OF_EXPR
+            | OR_PAT
+            | PARAM
+            | PARAM_LIST
+            | PARENTHESIZED_ARG_LIST
+            | PAREN_EXPR
+            | PAREN_PAT
+            | PAREN_TYPE
+            | PAT
+            | PATH
+            | PATH_EXPR
+            | PATH_PAT
+            | PATH_SEGMENT
+            | PATH_TYPE
+            | PREFIX_EXPR
+            | PTR_TYPE
+            | RANGE_EXPR
+            | RANGE_PAT
+            | RECORD_EXPR
+            | RECORD_EXPR_FIELD
+            | RECORD_EXPR_FIELD_LIST
+            | RECORD_FIELD
+            | RECORD_FIELD_LIST
+            | RECORD_PAT
+            | RECORD_PAT_FIELD
+            | RECORD_PAT_FIELD_LIST
+            | REF_EXPR
+            | REF_PAT
+            | REF_TYPE
+            | RENAME
+            | REST_PAT
+            | RETURN_EXPR
+            | RETURN_TYPE_SYNTAX
+            | RET_TYPE
+            | SELF_PARAM
+            | SLICE_PAT
+            | SLICE_TYPE
+            | SOURCE_FILE
+            | STATIC
+            | STMT
+            | STMT_LIST
+            | STRUCT
+            | TOKEN_TREE
+            | TRAIT
+            | TRAIT_ALIAS
+            | TRY_EXPR
+            | TUPLE_EXPR
+            | TUPLE_FIELD
+            | TUPLE_FIELD_LIST
+            | TUPLE_PAT
+            | TUPLE_STRUCT_PAT
+            | TUPLE_TYPE
+            | TYPE
+            | TYPE_ALIAS
+            | TYPE_ARG
+            | TYPE_BOUND
+            | TYPE_BOUND_LIST
+            | TYPE_PARAM
+            | UNDERSCORE_EXPR
+            | UNION
+            | USE
+            | USE_BOUND_GENERIC_ARG
+            | USE_BOUND_GENERIC_ARGS
+            | USE_TREE
+            | USE_TREE_LIST
+            | VARIANT
+            | VARIANT_LIST
+            | VISIBILITY
+            | WHERE_CLAUSE
+            | WHERE_PRED
+            | WHILE_EXPR
+            | WILDCARD_PAT
+            | YEET_EXPR
+            | YIELD_EXPR
+            | COMMENT
+            | ERROR
+            | IDENT
+            | LIFETIME_IDENT
+            | NEWLINE
+            | SHEBANG
+            | WHITESPACE => panic!("no text for these `SyntaxKind`s"),
+            DOLLAR => "$",
+            SEMICOLON => ";",
+            COMMA => ",",
+            L_PAREN => "(",
+            R_PAREN => ")",
+            L_CURLY => "{",
+            R_CURLY => "}",
+            L_BRACK => "[",
+            R_BRACK => "]",
+            L_ANGLE => "<",
+            R_ANGLE => ">",
+            AT => "@",
+            POUND => "#",
+            TILDE => "~",
+            QUESTION => "?",
+            AMP => "&",
+            PIPE => "|",
+            PLUS => "+",
+            STAR => "*",
+            SLASH => "/",
+            CARET => "^",
+            PERCENT => "%",
+            UNDERSCORE => "_",
+            DOT => ".",
+            DOT2 => "..",
+            DOT3 => "...",
+            DOT2EQ => "..=",
+            COLON => ":",
+            COLON2 => "::",
+            EQ => "=",
+            EQ2 => "==",
+            FAT_ARROW => "=>",
+            BANG => "!",
+            NEQ => "!=",
+            MINUS => "-",
+            THIN_ARROW => "->",
+            LTEQ => "<=",
+            GTEQ => ">=",
+            PLUSEQ => "+=",
+            MINUSEQ => "-=",
+            PIPEEQ => "|=",
+            AMPEQ => "&=",
+            CARETEQ => "^=",
+            SLASHEQ => "/=",
+            STAREQ => "*=",
+            PERCENTEQ => "%=",
+            AMP2 => "&&",
+            PIPE2 => "||",
+            SHL => "<<",
+            SHR => ">>",
+            SHLEQ => "<<=",
+            SHREQ => ">>=",
+            SELF_TYPE_KW => "Self",
+            ABSTRACT_KW => "abstract",
+            AS_KW => "as",
+            BECOME_KW => "become",
+            BOX_KW => "box",
+            BREAK_KW => "break",
+            CONST_KW => "const",
+            CONTINUE_KW => "continue",
+            CRATE_KW => "crate",
+            DO_KW => "do",
+            ELSE_KW => "else",
+            ENUM_KW => "enum",
+            EXTERN_KW => "extern",
+            FALSE_KW => "false",
+            FINAL_KW => "final",
+            FN_KW => "fn",
+            FOR_KW => "for",
+            IF_KW => "if",
+            IMPL_KW => "impl",
+            IN_KW => "in",
+            LET_KW => "let",
+            LOOP_KW => "loop",
+            MACRO_KW => "macro",
+            MATCH_KW => "match",
+            MOD_KW => "mod",
+            MOVE_KW => "move",
+            MUT_KW => "mut",
+            OVERRIDE_KW => "override",
+            PRIV_KW => "priv",
+            PUB_KW => "pub",
+            REF_KW => "ref",
+            RETURN_KW => "return",
+            SELF_KW => "self",
+            STATIC_KW => "static",
+            STRUCT_KW => "struct",
+            SUPER_KW => "super",
+            TRAIT_KW => "trait",
+            TRUE_KW => "true",
+            TYPE_KW => "type",
+            TYPEOF_KW => "typeof",
+            UNSAFE_KW => "unsafe",
+            UNSIZED_KW => "unsized",
+            USE_KW => "use",
+            VIRTUAL_KW => "virtual",
+            WHERE_KW => "where",
+            WHILE_KW => "while",
+            YIELD_KW => "yield",
+            ASM_KW => "asm",
+            ATT_SYNTAX_KW => "att_syntax",
+            AUTO_KW => "auto",
+            BUILTIN_KW => "builtin",
+            CLOBBER_ABI_KW => "clobber_abi",
+            DEFAULT_KW => "default",
+            DYN_KW => "dyn",
+            FORMAT_ARGS_KW => "format_args",
+            INLATEOUT_KW => "inlateout",
+            INOUT_KW => "inout",
+            LABEL_KW => "label",
+            LATEOUT_KW => "lateout",
+            MACRO_RULES_KW => "macro_rules",
+            MAY_UNWIND_KW => "may_unwind",
+            NOMEM_KW => "nomem",
+            NORETURN_KW => "noreturn",
+            NOSTACK_KW => "nostack",
+            OFFSET_OF_KW => "offset_of",
+            OPTIONS_KW => "options",
+            OUT_KW => "out",
+            PRESERVES_FLAGS_KW => "preserves_flags",
+            PURE_KW => "pure",
+            RAW_KW => "raw",
+            READONLY_KW => "readonly",
+            SAFE_KW => "safe",
+            SYM_KW => "sym",
+            UNION_KW => "union",
+            YEET_KW => "yeet",
+            ASYNC_KW => "async",
+            AWAIT_KW => "await",
+            DYN_KW => "dyn",
+            GEN_KW => "gen",
+            TRY_KW => "try",
+        }
+    }
     #[doc = r" Checks whether this syntax kind is a strict keyword for the given edition."]
     #[doc = r" Strict keywords are identifiers that are always considered keywords."]
     pub fn is_strict_keyword(self, edition: Edition) -> bool {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs
index 32b1f5f7544..72a46f2f9f0 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs
@@ -42,6 +42,14 @@ pub use self::{
 /// the same representation: a pointer to the tree root and a pointer to the
 /// node itself.
 pub trait AstNode {
+    /// This panics if the `SyntaxKind` is not statically known.
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        panic!("dynamic `SyntaxKind` for `AstNode::kind()`")
+    }
+
     fn can_cast(kind: SyntaxKind) -> bool
     where
         Self: Sized;
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 3876ef71a07..69e2a9f9c1b 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
@@ -2503,6 +2503,13 @@ pub struct AnyHasVisibility {
 impl ast::HasVisibility for AnyHasVisibility {}
 impl AstNode for Abi {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ABI
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2517,6 +2524,13 @@ impl AstNode for Abi {
 }
 impl AstNode for ArgList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ARG_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2531,6 +2545,13 @@ impl AstNode for ArgList {
 }
 impl AstNode for ArrayExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ARRAY_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2545,6 +2566,13 @@ impl AstNode for ArrayExpr {
 }
 impl AstNode for ArrayType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ARRAY_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2559,6 +2587,13 @@ impl AstNode for ArrayType {
 }
 impl AstNode for AsmClobberAbi {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_CLOBBER_ABI
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2573,6 +2608,13 @@ impl AstNode for AsmClobberAbi {
 }
 impl AstNode for AsmConst {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_CONST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2587,6 +2629,13 @@ impl AstNode for AsmConst {
 }
 impl AstNode for AsmDirSpec {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_DIR_SPEC
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2601,6 +2650,13 @@ impl AstNode for AsmDirSpec {
 }
 impl AstNode for AsmExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2615,6 +2671,13 @@ impl AstNode for AsmExpr {
 }
 impl AstNode for AsmLabel {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_LABEL
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2629,6 +2692,13 @@ impl AstNode for AsmLabel {
 }
 impl AstNode for AsmOperandExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_OPERAND_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2643,6 +2713,13 @@ impl AstNode for AsmOperandExpr {
 }
 impl AstNode for AsmOperandNamed {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_OPERAND_NAMED
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2657,6 +2734,13 @@ impl AstNode for AsmOperandNamed {
 }
 impl AstNode for AsmOption {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_OPTION
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2671,6 +2755,13 @@ impl AstNode for AsmOption {
 }
 impl AstNode for AsmOptions {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_OPTIONS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2685,6 +2776,13 @@ impl AstNode for AsmOptions {
 }
 impl AstNode for AsmRegOperand {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_REG_OPERAND
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2699,6 +2797,13 @@ impl AstNode for AsmRegOperand {
 }
 impl AstNode for AsmRegSpec {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_REG_SPEC
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2713,6 +2818,13 @@ impl AstNode for AsmRegSpec {
 }
 impl AstNode for AsmSym {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASM_SYM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2727,6 +2839,13 @@ impl AstNode for AsmSym {
 }
 impl AstNode for AssocItemList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASSOC_ITEM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2741,6 +2860,13 @@ impl AstNode for AssocItemList {
 }
 impl AstNode for AssocTypeArg {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ASSOC_TYPE_ARG
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2755,6 +2881,13 @@ impl AstNode for AssocTypeArg {
 }
 impl AstNode for Attr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ATTR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2769,6 +2902,13 @@ impl AstNode for Attr {
 }
 impl AstNode for AwaitExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        AWAIT_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2783,6 +2923,13 @@ impl AstNode for AwaitExpr {
 }
 impl AstNode for BecomeExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        BECOME_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2797,6 +2944,13 @@ impl AstNode for BecomeExpr {
 }
 impl AstNode for BinExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        BIN_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2811,6 +2965,13 @@ impl AstNode for BinExpr {
 }
 impl AstNode for BlockExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        BLOCK_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2825,6 +2986,13 @@ impl AstNode for BlockExpr {
 }
 impl AstNode for BoxPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        BOX_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2839,6 +3007,13 @@ impl AstNode for BoxPat {
 }
 impl AstNode for BreakExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        BREAK_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2853,6 +3028,13 @@ impl AstNode for BreakExpr {
 }
 impl AstNode for CallExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CALL_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2867,6 +3049,13 @@ impl AstNode for CallExpr {
 }
 impl AstNode for CastExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CAST_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2881,6 +3070,13 @@ impl AstNode for CastExpr {
 }
 impl AstNode for ClosureBinder {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CLOSURE_BINDER
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_BINDER }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2895,6 +3091,13 @@ impl AstNode for ClosureBinder {
 }
 impl AstNode for ClosureExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CLOSURE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2909,6 +3112,13 @@ impl AstNode for ClosureExpr {
 }
 impl AstNode for Const {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CONST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2923,6 +3133,13 @@ impl AstNode for Const {
 }
 impl AstNode for ConstArg {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CONST_ARG
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2937,6 +3154,13 @@ impl AstNode for ConstArg {
 }
 impl AstNode for ConstBlockPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CONST_BLOCK_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2951,6 +3175,13 @@ impl AstNode for ConstBlockPat {
 }
 impl AstNode for ConstParam {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CONST_PARAM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2965,6 +3196,13 @@ impl AstNode for ConstParam {
 }
 impl AstNode for ContinueExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        CONTINUE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2979,6 +3217,13 @@ impl AstNode for ContinueExpr {
 }
 impl AstNode for DynTraitType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        DYN_TRAIT_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -2993,6 +3238,13 @@ impl AstNode for DynTraitType {
 }
 impl AstNode for Enum {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ENUM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3007,6 +3259,13 @@ impl AstNode for Enum {
 }
 impl AstNode for ExprStmt {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        EXPR_STMT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3021,6 +3280,13 @@ impl AstNode for ExprStmt {
 }
 impl AstNode for ExternBlock {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        EXTERN_BLOCK
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3035,6 +3301,13 @@ impl AstNode for ExternBlock {
 }
 impl AstNode for ExternCrate {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        EXTERN_CRATE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3049,6 +3322,13 @@ impl AstNode for ExternCrate {
 }
 impl AstNode for ExternItemList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        EXTERN_ITEM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3063,6 +3343,13 @@ impl AstNode for ExternItemList {
 }
 impl AstNode for FieldExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FIELD_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3077,6 +3364,13 @@ impl AstNode for FieldExpr {
 }
 impl AstNode for Fn {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FN
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3091,6 +3385,13 @@ impl AstNode for Fn {
 }
 impl AstNode for FnPtrType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FN_PTR_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3105,6 +3406,13 @@ impl AstNode for FnPtrType {
 }
 impl AstNode for ForExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FOR_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3119,6 +3427,13 @@ impl AstNode for ForExpr {
 }
 impl AstNode for ForType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FOR_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3133,6 +3448,13 @@ impl AstNode for ForType {
 }
 impl AstNode for FormatArgsArg {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FORMAT_ARGS_ARG
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3147,6 +3469,13 @@ impl AstNode for FormatArgsArg {
 }
 impl AstNode for FormatArgsExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        FORMAT_ARGS_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3161,6 +3490,13 @@ impl AstNode for FormatArgsExpr {
 }
 impl AstNode for GenericArgList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        GENERIC_ARG_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3175,6 +3511,13 @@ impl AstNode for GenericArgList {
 }
 impl AstNode for GenericParamList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        GENERIC_PARAM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3189,6 +3532,13 @@ impl AstNode for GenericParamList {
 }
 impl AstNode for IdentPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        IDENT_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3203,6 +3553,13 @@ impl AstNode for IdentPat {
 }
 impl AstNode for IfExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        IF_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3217,6 +3574,13 @@ impl AstNode for IfExpr {
 }
 impl AstNode for Impl {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        IMPL
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3231,6 +3595,13 @@ impl AstNode for Impl {
 }
 impl AstNode for ImplTraitType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        IMPL_TRAIT_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3245,6 +3616,13 @@ impl AstNode for ImplTraitType {
 }
 impl AstNode for IndexExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        INDEX_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3259,6 +3637,13 @@ impl AstNode for IndexExpr {
 }
 impl AstNode for InferType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        INFER_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3273,6 +3658,13 @@ impl AstNode for InferType {
 }
 impl AstNode for ItemList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        ITEM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3287,6 +3679,13 @@ impl AstNode for ItemList {
 }
 impl AstNode for Label {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LABEL
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3301,6 +3700,13 @@ impl AstNode for Label {
 }
 impl AstNode for LetElse {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LET_ELSE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3315,6 +3721,13 @@ impl AstNode for LetElse {
 }
 impl AstNode for LetExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LET_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3329,6 +3742,13 @@ impl AstNode for LetExpr {
 }
 impl AstNode for LetStmt {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LET_STMT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3343,6 +3763,13 @@ impl AstNode for LetStmt {
 }
 impl AstNode for Lifetime {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LIFETIME
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3357,6 +3784,13 @@ impl AstNode for Lifetime {
 }
 impl AstNode for LifetimeArg {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LIFETIME_ARG
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3371,6 +3805,13 @@ impl AstNode for LifetimeArg {
 }
 impl AstNode for LifetimeParam {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LIFETIME_PARAM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3385,6 +3826,13 @@ impl AstNode for LifetimeParam {
 }
 impl AstNode for Literal {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LITERAL
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3399,6 +3847,13 @@ impl AstNode for Literal {
 }
 impl AstNode for LiteralPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LITERAL_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3413,6 +3868,13 @@ impl AstNode for LiteralPat {
 }
 impl AstNode for LoopExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        LOOP_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3427,6 +3889,13 @@ impl AstNode for LoopExpr {
 }
 impl AstNode for MacroCall {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_CALL
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3441,6 +3910,13 @@ impl AstNode for MacroCall {
 }
 impl AstNode for MacroDef {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_DEF
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3455,6 +3931,13 @@ impl AstNode for MacroDef {
 }
 impl AstNode for MacroExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3469,6 +3952,13 @@ impl AstNode for MacroExpr {
 }
 impl AstNode for MacroItems {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_ITEMS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3483,6 +3973,13 @@ impl AstNode for MacroItems {
 }
 impl AstNode for MacroPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3497,6 +3994,13 @@ impl AstNode for MacroPat {
 }
 impl AstNode for MacroRules {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_RULES
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3511,6 +4015,13 @@ impl AstNode for MacroRules {
 }
 impl AstNode for MacroStmts {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_STMTS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3525,6 +4036,13 @@ impl AstNode for MacroStmts {
 }
 impl AstNode for MacroType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MACRO_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3539,6 +4057,13 @@ impl AstNode for MacroType {
 }
 impl AstNode for MatchArm {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MATCH_ARM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3553,6 +4078,13 @@ impl AstNode for MatchArm {
 }
 impl AstNode for MatchArmList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MATCH_ARM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3567,6 +4099,13 @@ impl AstNode for MatchArmList {
 }
 impl AstNode for MatchExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MATCH_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3581,6 +4120,13 @@ impl AstNode for MatchExpr {
 }
 impl AstNode for MatchGuard {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MATCH_GUARD
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3595,6 +4141,13 @@ impl AstNode for MatchGuard {
 }
 impl AstNode for Meta {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        META
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == META }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3609,6 +4162,13 @@ impl AstNode for Meta {
 }
 impl AstNode for MethodCallExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        METHOD_CALL_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3623,6 +4183,13 @@ impl AstNode for MethodCallExpr {
 }
 impl AstNode for Module {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        MODULE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3637,6 +4204,13 @@ impl AstNode for Module {
 }
 impl AstNode for Name {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        NAME
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3651,6 +4225,13 @@ impl AstNode for Name {
 }
 impl AstNode for NameRef {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        NAME_REF
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3665,6 +4246,13 @@ impl AstNode for NameRef {
 }
 impl AstNode for NeverType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        NEVER_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3679,6 +4267,13 @@ impl AstNode for NeverType {
 }
 impl AstNode for OffsetOfExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        OFFSET_OF_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3693,6 +4288,13 @@ impl AstNode for OffsetOfExpr {
 }
 impl AstNode for OrPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        OR_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3707,6 +4309,13 @@ impl AstNode for OrPat {
 }
 impl AstNode for Param {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PARAM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3721,6 +4330,13 @@ impl AstNode for Param {
 }
 impl AstNode for ParamList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PARAM_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3735,6 +4351,13 @@ impl AstNode for ParamList {
 }
 impl AstNode for ParenExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PAREN_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3749,6 +4372,13 @@ impl AstNode for ParenExpr {
 }
 impl AstNode for ParenPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PAREN_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3763,6 +4393,13 @@ impl AstNode for ParenPat {
 }
 impl AstNode for ParenType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PAREN_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3777,6 +4414,13 @@ impl AstNode for ParenType {
 }
 impl AstNode for ParenthesizedArgList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PARENTHESIZED_ARG_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3791,6 +4435,13 @@ impl AstNode for ParenthesizedArgList {
 }
 impl AstNode for Path {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PATH
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3805,6 +4456,13 @@ impl AstNode for Path {
 }
 impl AstNode for PathExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PATH_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3819,6 +4477,13 @@ impl AstNode for PathExpr {
 }
 impl AstNode for PathPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PATH_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3833,6 +4498,13 @@ impl AstNode for PathPat {
 }
 impl AstNode for PathSegment {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PATH_SEGMENT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3847,6 +4519,13 @@ impl AstNode for PathSegment {
 }
 impl AstNode for PathType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PATH_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3861,6 +4540,13 @@ impl AstNode for PathType {
 }
 impl AstNode for PrefixExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PREFIX_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3875,6 +4561,13 @@ impl AstNode for PrefixExpr {
 }
 impl AstNode for PtrType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        PTR_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3889,6 +4582,13 @@ impl AstNode for PtrType {
 }
 impl AstNode for RangeExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RANGE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3903,6 +4603,13 @@ impl AstNode for RangeExpr {
 }
 impl AstNode for RangePat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RANGE_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3917,6 +4624,13 @@ impl AstNode for RangePat {
 }
 impl AstNode for RecordExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3931,6 +4645,13 @@ impl AstNode for RecordExpr {
 }
 impl AstNode for RecordExprField {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_EXPR_FIELD
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3945,6 +4666,13 @@ impl AstNode for RecordExprField {
 }
 impl AstNode for RecordExprFieldList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_EXPR_FIELD_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3959,6 +4687,13 @@ impl AstNode for RecordExprFieldList {
 }
 impl AstNode for RecordField {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_FIELD
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3973,6 +4708,13 @@ impl AstNode for RecordField {
 }
 impl AstNode for RecordFieldList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_FIELD_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3987,6 +4729,13 @@ impl AstNode for RecordFieldList {
 }
 impl AstNode for RecordPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4001,6 +4750,13 @@ impl AstNode for RecordPat {
 }
 impl AstNode for RecordPatField {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_PAT_FIELD
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4015,6 +4771,13 @@ impl AstNode for RecordPatField {
 }
 impl AstNode for RecordPatFieldList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RECORD_PAT_FIELD_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4029,6 +4792,13 @@ impl AstNode for RecordPatFieldList {
 }
 impl AstNode for RefExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        REF_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4043,6 +4813,13 @@ impl AstNode for RefExpr {
 }
 impl AstNode for RefPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        REF_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4057,6 +4834,13 @@ impl AstNode for RefPat {
 }
 impl AstNode for RefType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        REF_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4071,6 +4855,13 @@ impl AstNode for RefType {
 }
 impl AstNode for Rename {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RENAME
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4085,6 +4876,13 @@ impl AstNode for Rename {
 }
 impl AstNode for RestPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        REST_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4099,6 +4897,13 @@ impl AstNode for RestPat {
 }
 impl AstNode for RetType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RET_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4113,6 +4918,13 @@ impl AstNode for RetType {
 }
 impl AstNode for ReturnExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RETURN_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4127,6 +4939,13 @@ impl AstNode for ReturnExpr {
 }
 impl AstNode for ReturnTypeSyntax {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        RETURN_TYPE_SYNTAX
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_SYNTAX }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4141,6 +4960,13 @@ impl AstNode for ReturnTypeSyntax {
 }
 impl AstNode for SelfParam {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        SELF_PARAM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4155,6 +4981,13 @@ impl AstNode for SelfParam {
 }
 impl AstNode for SlicePat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        SLICE_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4169,6 +5002,13 @@ impl AstNode for SlicePat {
 }
 impl AstNode for SliceType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        SLICE_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4183,6 +5023,13 @@ impl AstNode for SliceType {
 }
 impl AstNode for SourceFile {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        SOURCE_FILE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4197,6 +5044,13 @@ impl AstNode for SourceFile {
 }
 impl AstNode for Static {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        STATIC
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4211,6 +5065,13 @@ impl AstNode for Static {
 }
 impl AstNode for StmtList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        STMT_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4225,6 +5086,13 @@ impl AstNode for StmtList {
 }
 impl AstNode for Struct {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        STRUCT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4239,6 +5107,13 @@ impl AstNode for Struct {
 }
 impl AstNode for TokenTree {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TOKEN_TREE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4253,6 +5128,13 @@ impl AstNode for TokenTree {
 }
 impl AstNode for Trait {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TRAIT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4267,6 +5149,13 @@ impl AstNode for Trait {
 }
 impl AstNode for TraitAlias {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TRAIT_ALIAS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_ALIAS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4281,6 +5170,13 @@ impl AstNode for TraitAlias {
 }
 impl AstNode for TryExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TRY_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4295,6 +5191,13 @@ impl AstNode for TryExpr {
 }
 impl AstNode for TupleExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4309,6 +5212,13 @@ impl AstNode for TupleExpr {
 }
 impl AstNode for TupleField {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_FIELD
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4323,6 +5233,13 @@ impl AstNode for TupleField {
 }
 impl AstNode for TupleFieldList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_FIELD_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4337,6 +5254,13 @@ impl AstNode for TupleFieldList {
 }
 impl AstNode for TuplePat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4351,6 +5275,13 @@ impl AstNode for TuplePat {
 }
 impl AstNode for TupleStructPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_STRUCT_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4365,6 +5296,13 @@ impl AstNode for TupleStructPat {
 }
 impl AstNode for TupleType {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TUPLE_TYPE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4379,6 +5317,13 @@ impl AstNode for TupleType {
 }
 impl AstNode for TypeAlias {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_ALIAS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4393,6 +5338,13 @@ impl AstNode for TypeAlias {
 }
 impl AstNode for TypeArg {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_ARG
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4407,6 +5359,13 @@ impl AstNode for TypeArg {
 }
 impl AstNode for TypeBound {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_BOUND
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4421,6 +5380,13 @@ impl AstNode for TypeBound {
 }
 impl AstNode for TypeBoundList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_BOUND_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4435,6 +5401,13 @@ impl AstNode for TypeBoundList {
 }
 impl AstNode for TypeParam {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_PARAM
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4449,6 +5422,13 @@ impl AstNode for TypeParam {
 }
 impl AstNode for UnderscoreExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        UNDERSCORE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4463,6 +5443,13 @@ impl AstNode for UnderscoreExpr {
 }
 impl AstNode for Union {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        UNION
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4477,6 +5464,13 @@ impl AstNode for Union {
 }
 impl AstNode for Use {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        USE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4491,6 +5485,13 @@ impl AstNode for Use {
 }
 impl AstNode for UseBoundGenericArgs {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        USE_BOUND_GENERIC_ARGS
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4505,6 +5506,13 @@ impl AstNode for UseBoundGenericArgs {
 }
 impl AstNode for UseTree {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        USE_TREE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4519,6 +5527,13 @@ impl AstNode for UseTree {
 }
 impl AstNode for UseTreeList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        USE_TREE_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4533,6 +5548,13 @@ impl AstNode for UseTreeList {
 }
 impl AstNode for Variant {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        VARIANT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4547,6 +5569,13 @@ impl AstNode for Variant {
 }
 impl AstNode for VariantList {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        VARIANT_LIST
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4561,6 +5590,13 @@ impl AstNode for VariantList {
 }
 impl AstNode for Visibility {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        VISIBILITY
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4575,6 +5611,13 @@ impl AstNode for Visibility {
 }
 impl AstNode for WhereClause {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        WHERE_CLAUSE
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4589,6 +5632,13 @@ impl AstNode for WhereClause {
 }
 impl AstNode for WherePred {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        WHERE_PRED
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4603,6 +5653,13 @@ impl AstNode for WherePred {
 }
 impl AstNode for WhileExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        WHILE_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4617,6 +5674,13 @@ impl AstNode for WhileExpr {
 }
 impl AstNode for WildcardPat {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        WILDCARD_PAT
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4631,6 +5695,13 @@ impl AstNode for WildcardPat {
 }
 impl AstNode for YeetExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        YEET_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4645,6 +5716,13 @@ impl AstNode for YeetExpr {
 }
 impl AstNode for YieldExpr {
     #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        YIELD_EXPR
+    }
+    #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option<Self> {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index eb96ab6ef59..76b39c3b73f 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -8,7 +8,10 @@
 //! Keep in mind that `from_text` functions should be kept private. The public
 //! API should require to assemble every node piecewise. The trick of
 //! `parse(format!())` we use internally is an implementation detail -- long
-//! term, it will be replaced with direct tree manipulation.
+//! term, it will be replaced with `quote!`. Do not add more usages to `from_text` -
+//! use `quote!` instead.
+
+mod quote;
 
 use itertools::Itertools;
 use parser::{Edition, T};
@@ -16,7 +19,7 @@ use rowan::NodeOrToken;
 use stdx::{format_to, format_to_acc, never};
 
 use crate::{
-    ast::{self, Param},
+    ast::{self, make::quote::quote, Param},
     utils::is_raw_identifier,
     AstNode, SourceFile, SyntaxKind, SyntaxToken,
 };
@@ -118,7 +121,11 @@ pub fn name(name: &str) -> ast::Name {
 }
 pub fn name_ref(name_ref: &str) -> ast::NameRef {
     let raw_escape = raw_ident_esc(name_ref);
-    ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}"))
+    quote! {
+        NameRef {
+            [IDENT format!("{raw_escape}{name_ref}")]
+        }
+    }
 }
 fn raw_ident_esc(ident: &str) -> &'static str {
     if is_raw_identifier(ident, Edition::CURRENT) {
@@ -135,7 +142,11 @@ pub fn lifetime(text: &str) -> ast::Lifetime {
         tmp = format!("'{text}");
         text = &tmp;
     }
-    ast_from_text(&format!("fn f<{text}>() {{ }}"))
+    quote! {
+        Lifetime {
+            [LIFETIME_IDENT text]
+        }
+    }
 }
 
 // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
@@ -175,63 +186,37 @@ pub fn ty_alias(
     where_clause: Option<ast::WhereClause>,
     assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
 ) -> ast::TypeAlias {
-    let mut s = String::new();
-    s.push_str(&format!("type {ident}"));
-
-    if let Some(list) = generic_param_list {
-        s.push_str(&list.to_string());
-    }
-
-    if let Some(list) = type_param_bounds {
-        s.push_str(&format!(" : {list}"));
-    }
-
-    if let Some(cl) = where_clause {
-        s.push_str(&format!(" {cl}"));
-    }
-
-    if let Some(exp) = assignment {
-        if let Some(cl) = exp.1 {
-            s.push_str(&format!(" = {} {cl}", exp.0));
-        } else {
-            s.push_str(&format!(" = {}", exp.0));
+    let (assignment_ty, assignment_where) = assignment.unzip();
+    let assignment_where = assignment_where.flatten();
+    quote! {
+        TypeAlias {
+            [type] " "
+                Name { [IDENT ident] }
+                #generic_param_list
+                #(" " [:] " " #type_param_bounds)*
+                #(" " #where_clause)*
+                #(" " [=] " " #assignment_ty)*
+                #(" " #assignment_where)*
+            [;]
         }
     }
-
-    s.push(';');
-    ast_from_text(&s)
 }
 
 pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
-    for_lifetime_list: Option<ast::GenericParamList>,
     is_unsafe: bool,
     abi: Option<ast::Abi>,
-    params: I,
+    mut params: I,
     ret_type: Option<ast::RetType>,
 ) -> ast::FnPtrType {
-    let mut s = String::from("type __ = ");
-
-    if let Some(list) = for_lifetime_list {
-        format_to!(s, "for{} ", list);
-    }
-
-    if is_unsafe {
-        s.push_str("unsafe ");
-    }
-
-    if let Some(abi) = abi {
-        format_to!(s, "{} ", abi)
-    }
-
-    s.push_str("fn");
-
-    format_to!(s, "({})", params.map(|p| p.to_string()).join(", "));
-
-    if let Some(ret_type) = ret_type {
-        format_to!(s, " {}", ret_type);
+    let is_unsafe = is_unsafe.then_some(());
+    let first_param = params.next();
+    quote! {
+        FnPtrType {
+            #(#is_unsafe [unsafe] " ")* #(#abi " ")* [fn]
+                ['('] #first_param #([,] " " #params)* [')']
+                #(" " #ret_type)*
+        }
     }
-
-    ast_from_text(&s)
 }
 
 pub fn assoc_item_list() -> ast::AssocItemList {
@@ -480,15 +465,16 @@ pub fn block_expr(
     stmts: impl IntoIterator<Item = ast::Stmt>,
     tail_expr: Option<ast::Expr>,
 ) -> ast::BlockExpr {
-    let mut buf = "{\n".to_owned();
-    for stmt in stmts.into_iter() {
-        format_to!(buf, "    {stmt}\n");
-    }
-    if let Some(tail_expr) = tail_expr {
-        format_to!(buf, "    {tail_expr}\n");
+    quote! {
+        BlockExpr {
+            StmtList {
+                ['{'] "\n"
+                #("    " #stmts "\n")*
+                #("    " #tail_expr "\n")*
+                ['}']
+            }
+        }
     }
-    buf += "}";
-    ast_from_text(&format!("fn f() {buf}"))
 }
 
 pub fn async_move_block_expr(
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs
new file mode 100644
index 00000000000..300ef25c137
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make/quote.rs
@@ -0,0 +1,191 @@
+//! A `quote!`-like API for crafting AST nodes.
+
+pub(crate) use rowan::{GreenNode, GreenToken, NodeOrToken, SyntaxKind as RSyntaxKind};
+
+macro_rules! quote_impl_ {
+    ( @append $children:ident ) => {}; // Base case.
+
+    ( @append $children:ident
+        $node:ident {
+            $($tree:tt)*
+        }
+        $($rest:tt)*
+    ) => {
+        {
+            #[allow(unused_mut)]
+            let mut inner_children = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
+                $crate::ast::make::quote::GreenNode,
+                $crate::ast::make::quote::GreenToken,
+            >>::new();
+            $crate::ast::make::quote::quote_impl!( @append inner_children
+                $($tree)*
+            );
+            let kind = <$crate::ast::$node as $crate::ast::AstNode>::kind();
+            let node = $crate::ast::make::quote::GreenNode::new($crate::ast::make::quote::RSyntaxKind(kind as u16), inner_children);
+            $children.push($crate::ast::make::quote::NodeOrToken::Node(node));
+        }
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    ( @append $children:ident
+        [ $token_kind:ident $token_text:expr ]
+        $($rest:tt)*
+    ) => {
+        $children.push($crate::ast::make::quote::NodeOrToken::Token(
+            $crate::ast::make::quote::GreenToken::new(
+                $crate::ast::make::quote::RSyntaxKind($crate::SyntaxKind::$token_kind as u16),
+                &$token_text,
+            ),
+        ));
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    ( @append $children:ident
+        [$($token:tt)+]
+        $($rest:tt)*
+    ) => {
+        $children.push($crate::ast::make::quote::NodeOrToken::Token(
+            $crate::ast::make::quote::GreenToken::new(
+                $crate::ast::make::quote::RSyntaxKind($crate::T![ $($token)+ ] as u16),
+                const { $crate::T![ $($token)+ ].text() },
+            ),
+        ));
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    ( @append $children:ident
+        $whitespace:literal
+        $($rest:tt)*
+    ) => {
+        const { $crate::ast::make::quote::verify_only_whitespaces($whitespace) };
+        $children.push($crate::ast::make::quote::NodeOrToken::Token(
+            $crate::ast::make::quote::GreenToken::new(
+                $crate::ast::make::quote::RSyntaxKind($crate::SyntaxKind::WHITESPACE as u16),
+                $whitespace,
+            ),
+        ));
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    ( @append $children:ident
+        # $var:ident
+        $($rest:tt)*
+    ) => {
+        $crate::ast::make::quote::ToNodeChild::append_node_child($var, &mut $children);
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    ( @append $children:ident
+        #( $($repetition:tt)+ )*
+        $($rest:tt)*
+    ) => {
+        $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
+            [] [] $($repetition)*
+        );
+        $crate::ast::make::quote::quote_impl!( @append $children $($rest)* );
+    };
+
+    // Base case - no repetition var.
+    ( @extract_pounded_in_repetition $children:ident
+        [ $($repetition:tt)* ] [ ]
+    ) => {
+        ::std::compile_error!("repetition in `ast::make::quote!()` without variable");
+    };
+
+    // Base case - repetition var found.
+    ( @extract_pounded_in_repetition $children:ident
+        [ $($repetition:tt)* ] [ $repetition_var:ident ]
+    ) => {
+        ::std::iter::IntoIterator::into_iter($repetition_var).for_each(|$repetition_var| {
+            $crate::ast::make::quote::quote_impl!( @append $children $($repetition)* );
+        });
+    };
+
+    ( @extract_pounded_in_repetition $children:ident
+        [ $($repetition:tt)* ] [ $repetition_var1:ident ] # $repetition_var2:ident $($rest:tt)*
+    ) => {
+        ::std::compile_error!("repetition in `ast::make::quote!()` with more than one variable");
+    };
+
+    ( @extract_pounded_in_repetition $children:ident
+        [ $($repetition:tt)* ] [ ] # $repetition_var:ident $($rest:tt)*
+    ) => {
+        $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
+            [ $($repetition)* # $repetition_var ] [ $repetition_var ] $($rest)*
+        );
+    };
+
+    ( @extract_pounded_in_repetition $children:ident
+        [ $($repetition:tt)* ] [ $($repetition_var:tt)* ] $non_repetition_var:tt $($rest:tt)*
+    ) => {
+        $crate::ast::make::quote::quote_impl!( @extract_pounded_in_repetition $children
+            [ $($repetition)* $non_repetition_var ] [ $($repetition_var)* ] $($rest)*
+        );
+    };
+}
+pub(crate) use quote_impl_ as quote_impl;
+
+/// A `quote!`-like API for crafting AST nodes.
+///
+/// Syntax: AST nodes are created with `Node { children }`, where `Node` is the node name in `ast` (`ast::Node`).
+/// Tokens are creates with their syntax enclosed by brackets, e.g. `[::]` or `['{']`. Alternatively, tokens can
+/// be created with the syntax `[token_kind token_text]`, where `token_kind` is a variant of `SyntaxKind` (e.g.
+/// `IDENT`) and `token_text` is an expression producing `String` or `&str`. Whitespaces can be added
+/// as string literals (i.e. `"\n    "` is a whitespace token). Interpolation is allowed with `#` (`#variable`),
+/// from `AstNode`s and `Option`s of them. Repetition is also supported, with only one repeating variable
+/// and no separator (`#("\n" #variable [>])*`), for any `IntoIterator`. Note that `Option`s are also `IntoIterator`,
+/// which can help when you want to conditionally include something along with an optional node.
+///
+/// There needs to be one root node, and its type is returned.
+///
+/// Be careful to closely match the Ungrammar AST, there is no validation for this!
+macro_rules! quote_ {
+    ( $root:ident { $($tree:tt)* } ) => {{
+        #[allow(unused_mut)]
+        let mut root = ::std::vec::Vec::<$crate::ast::make::quote::NodeOrToken<
+            $crate::ast::make::quote::GreenNode,
+            $crate::ast::make::quote::GreenToken,
+        >>::with_capacity(1);
+        $crate::ast::make::quote::quote_impl!( @append root $root { $($tree)* } );
+        let root = root.into_iter().next().unwrap();
+        let root = $crate::SyntaxNode::new_root(root.into_node().unwrap());
+        <$crate::ast::$root as $crate::ast::AstNode>::cast(root).unwrap()
+    }};
+}
+pub(crate) use quote_ as quote;
+
+use crate::AstNode;
+
+pub(crate) trait ToNodeChild {
+    fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>);
+}
+
+impl<N: AstNode> ToNodeChild for N {
+    fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {
+        children.push((*self.syntax().clone_subtree().green()).to_owned().into());
+    }
+}
+
+impl<C: ToNodeChild> ToNodeChild for Option<C> {
+    fn append_node_child(self, children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {
+        if let Some(child) = self {
+            child.append_node_child(children);
+        }
+    }
+}
+
+// This is useful when you want conditionally, based on some `bool`, to emit some code.
+impl ToNodeChild for () {
+    fn append_node_child(self, _children: &mut Vec<NodeOrToken<GreenNode, GreenToken>>) {}
+}
+
+pub(crate) const fn verify_only_whitespaces(text: &str) {
+    let text = text.as_bytes();
+    let mut i = 0;
+    while i < text.len() {
+        if !text[i].is_ascii_whitespace() {
+            panic!("non-whitespace found in whitespace token");
+        }
+        i += 1;
+    }
+}
diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
index e7534582f2b..035891dcbee 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs
@@ -163,6 +163,13 @@ fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String {
                 quote! {
                     impl AstNode for #name {
                         #[inline]
+                        fn kind() -> SyntaxKind
+                        where
+                            Self: Sized
+                        {
+                            #kind
+                        }
+                        #[inline]
                         fn can_cast(kind: SyntaxKind) -> bool {
                             kind == #kind
                         }
@@ -397,6 +404,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
     });
     let punctuation =
         grammar.punct.iter().map(|(_token, name)| format_ident!("{}", name)).collect::<Vec<_>>();
+    let punctuation_texts = grammar.punct.iter().map(|&(text, _name)| text);
 
     let fmt_kw_as_variant = |&name| match name {
         "Self" => format_ident!("SELF_TYPE_KW"),
@@ -422,6 +430,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
             quote! { #kw if #ed <= edition }
         })
         .collect::<Vec<_>>();
+    let edition_dependent_keywords = grammar.edition_dependent_keywords.iter().map(|&(it, _)| it);
     let edition_dependent_keywords_variants = grammar
         .edition_dependent_keywords
         .iter()
@@ -495,6 +504,20 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String {
         use self::SyntaxKind::*;
 
         impl SyntaxKind {
+            #[allow(unreachable_patterns)]
+            pub const fn text(self) -> &'static str {
+                match self {
+                    TOMBSTONE | EOF | __LAST
+                    #( | #literals )*
+                    #( | #nodes )*
+                    #( | #tokens )* => panic!("no text for these `SyntaxKind`s"),
+                    #( #punctuation => #punctuation_texts ,)*
+                    #( #strict_keywords_variants => #strict_keywords ,)*
+                    #( #contextual_keywords_variants => #contextual_keywords ,)*
+                    #( #edition_dependent_keywords_variants => #edition_dependent_keywords ,)*
+                }
+            }
+
             /// Checks whether this syntax kind is a strict keyword for the given edition.
             /// Strict keywords are identifiers that are always considered keywords.
             pub fn is_strict_keyword(self, edition: Edition) -> bool {