{"record":{"id":"06eef6425d9ea756","repo":"rust-lang/rust-analyzer","slug":"dynamic-syntaxkind-for-astnode-kind","errorCode":null,"errorMessage":"dynamic `SyntaxKind` for `AstNode::kind()`","messagePattern":"dynamic `SyntaxKind` for `AstNode::kind\\(\\)`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/syntax/src/ast.rs","lineNumber":50,"sourceCode":"    token_ext::{AnyComment, AnyString, CommentKind, CommentShape, IsString, QuoteOffsets, Radix},\n    traits::{\n        AttrsIter, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody,\n        HasModuleItem, HasName, HasTypeBounds, HasVisibility, attrs_including_inner,\n        attrs_with_doc_including_inner,\n    },\n};\n\n/// The main trait to go from untyped `SyntaxNode`  to a typed ast. The\n/// conversion itself has zero runtime cost: ast and syntax nodes have exactly\n/// the same representation: a pointer to the tree root and a pointer to the\n/// node itself.\npub trait AstNode {\n    /// This panics if the `SyntaxKind` is not statically known.\n    fn kind() -> SyntaxKind\n    where\n        Self: Sized,\n    {\n        panic!(\"dynamic `SyntaxKind` for `AstNode::kind()`\")\n    }\n\n    fn can_cast(kind: SyntaxKind) -> bool\n    where\n        Self: Sized;\n\n    fn cast(syntax: SyntaxNode) -> Option<Self>\n    where\n        Self: Sized;\n\n    fn syntax(&self) -> &SyntaxNode;\n    fn clone_subtree(&self) -> Self\n    where\n        Self: Sized,\n    {\n        Self::cast(self.syntax().clone_subtree()).unwrap()\n    }\n}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/syntax/src/ast.rs#L32-L68","documentation":"This panic is the default body of `AstNode::kind()` in the syntax crate. The method can only return a `SyntaxKind` statically when the node type has a fixed kind; AST enums (dynamic nodes like `ast::Expr`, `ast::Pat`) do not, so calling `kind()` on them panics. It is an API-contract error, not a data error.","triggerScenarios":"Calling `AstNode::kind()` on a dynamic AST enum type such as `ast::Expr`, `ast::Stmt`, `ast::Pat`, or `ast::Adt` — any generated type without a constant kind — via the blanket default implementation.","commonSituations":"Generic code like `fn f<N: AstNode>() { let k = N::kind(); }` instantiated with an AST enum; calling `T::kind()` after refactoring a concrete node (e.g. `ast::PathExpr`) into a generic parameter; relying on `ast::Expr::kind()` in tests.","solutions":["Only call `AstNode::kind()` on concrete node types (e.g. `ast::PathExpr`, `ast::Fn`) whose kind is statically known.","For dynamic nodes, get the kind at runtime from an instance via `node.syntax().kind()`.","Dispatch on the enum's own runtime accessors (e.g. `Expr::is_ref_like`, `can_cast`) or match on `SyntaxKind` yourself.","In generic code, add a bound/documentation that `N` must be a statically-known node type."],"exampleFix":"// before\nfn describe<N: AstNode>(n: &N) -> SyntaxKind { N::kind() } // panics for ast::Expr\n// after\nfn describe(n: &syntax::SyntaxNode) -> syntax::SyntaxKind { n.kind() }","handlingStrategy":"type-guard","validationCode":"// Prefer runtime kinds on instances; only concrete generated node types have a static kind.\nfn use_runtime_kind(node: &syntax::SyntaxNode) -> syntax::SyntaxKind {\n    node.kind()\n}","typeGuard":"fn static_kind_of<N: syntax::AstNode>() -> Option<syntax::SyntaxKind> {\n    // Only valid for concrete node types; enums like ast::Expr return None here\n    // by construction — avoid N::kind() and use node.syntax().kind() instead.\n    None\n}","tryCatchPattern":null,"preventionTips":["Never call `AstNode::kind()` on AST enums (`ast::Expr`, `ast::Pat`, `ast::Stmt`, ...).","Use `node.syntax().kind()` for runtime kinds on instances.","In generic code, require concrete node types or document the static-kind requirement.","Check syntax/src/ast/generated/nodes.rs to know which types have static kinds."],"tags":["ast","syntax-kind","panic","api-misuse"],"backgroundTag":"dynamic-syntax-kind-not-supported","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}