rust-lang/rust-analyzer · error
dynamic `SyntaxKind` for `AstNode::kind()`
Error message
dynamic `SyntaxKind` for `AstNode::kind()`
What it means
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.
Source
Thrown at crates/syntax/src/ast.rs:50
token_ext::{AnyComment, AnyString, CommentKind, CommentShape, IsString, QuoteOffsets, Radix},
traits::{
AttrsIter, HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody,
HasModuleItem, HasName, HasTypeBounds, HasVisibility, attrs_including_inner,
attrs_with_doc_including_inner,
},
};
/// The main trait to go from untyped `SyntaxNode` to a typed ast. The
/// conversion itself has zero runtime cost: ast and syntax nodes have exactly
/// 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;
fn cast(syntax: SyntaxNode) -> Option<Self>
where
Self: Sized;
fn syntax(&self) -> &SyntaxNode;
fn clone_subtree(&self) -> Self
where
Self: Sized,
{
Self::cast(self.syntax().clone_subtree()).unwrap()
}
}View on GitHub (pinned to e8f7e90aa3)
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.
Example fix
// before
fn describe<N: AstNode>(n: &N) -> SyntaxKind { N::kind() } // panics for ast::Expr
// after
fn describe(n: &syntax::SyntaxNode) -> syntax::SyntaxKind { n.kind() } Defensive patterns
Strategy: type-guard
Validate before calling
// Prefer runtime kinds on instances; only concrete generated node types have a static kind.
fn use_runtime_kind(node: &syntax::SyntaxNode) -> syntax::SyntaxKind {
node.kind()
} Type guard
fn static_kind_of<N: syntax::AstNode>() -> Option<syntax::SyntaxKind> {
// Only valid for concrete node types; enums like ast::Expr return None here
// by construction — avoid N::kind() and use node.syntax().kind() instead.
None
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid delimiter `{delimiter:?}`
- Can't find SyntaxNodePtr {:?} in AstIdMap: {:?}
- AstIdMap node mismatch with node `{ptr:?}`
- Can't find ast id {:?} in AstIdMap: {:?}
- Failed to make expr node `{node}` from text `{text}`
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/06eef6425d9ea756.
Report an issue: GitHub.