{"id":"9da4f4357138331b","repo":"rust-lang/rust","slug":"cloning-statement-nodeid-s-is-prohibited-by-defau","errorCode":null,"errorMessage":"cloning statement `NodeId`s is prohibited by default, the visitor should implement custom statement visiting","messagePattern":"cloning statement `NodeId`s is prohibited by default, the visitor should implement custom statement visiting","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_ast/src/mut_visit.rs","lineNumber":356,"sourceCode":"\npub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: Box<Expr>) -> Option<Box<Expr>> {\n    vis.visit_expr(&mut e);\n    Some(e)\n}\n\npub fn walk_flat_map_stmt<T: MutVisitor>(\n    vis: &mut T,\n    Stmt { kind, span, mut id }: Stmt,\n) -> SmallVec<[Stmt; 1]> {\n    vis.visit_id(&mut id);\n    let mut stmts: SmallVec<[Stmt; 1]> = walk_flat_map_stmt_kind(vis, kind)\n        .into_iter()\n        .map(|kind| Stmt { id, kind, span })\n        .collect();\n    match &mut stmts[..] {\n        [] => {}\n        [stmt] => vis.visit_span(&mut stmt.span),\n        _ => panic!(\n            \"cloning statement `NodeId`s is prohibited by default, \\\n             the visitor should implement custom statement visiting\"\n        ),\n    }\n    stmts\n}\n\npub fn walk_flat_map_stmt_kind<T: MutVisitor>(\n    vis: &mut T,\n    kind: StmtKind,\n) -> SmallVec<[StmtKind; 1]> {\n    match kind {\n        StmtKind::Let(mut local) => smallvec![StmtKind::Let({\n            vis.visit_local(&mut local);\n            local\n        })],\n        StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(),\n        StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(),","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_ast/src/mut_visit.rs#L338-L374","documentation":"This panic in `walk_flat_map_stmt` fires when a `MutVisitor`'s `flat_map_stmt` expands a single statement into *multiple* statements (more than one element in the returned `SmallVec`). The default `NodeId`-cloning behavior would assign the same `NodeId` to all resulting statements, which corrupts node identity; the visitor must instead override statement visiting to assign fresh ids.","triggerScenarios":"A `MutVisitor` implementation whose default `walk_flat_map_stmt` returns more than one `Stmt` (via `flat_map_stmt_kind` producing multiple `StmtKind`s). This happens when a visitor's `flat_map_item` / `filter_map_expr` (called from `walk_flat_map_stmt_kind`) expands a single `Item`/`Expr` statement into several — e.g., desugaring one stmt into many, or macro-like rewrites.","commonSituations":"Custom lints, AST rewriters, or desugaring passes in rustc that expand statements but forget to implement the matching `visit_stmt` / `flat_map_stmt` override. Refactors that add expansion behavior to an existing visitor. Hit most often when porting `MutVisitor`-based transformations.","solutions":["Override `flat_map_stmt` (or `visit_stmt`) on your `MutVisitor` to assign distinct `NodeId`s to each output statement (e.g., via `NodeId` reservation / `rustc_session`'s id allocator).","Avoid expanding a single statement into multiple in the default walk — restructure so the visitor emits one statement per input, or pre-expands outside the flat-map.","Reproduce with `RUST_BACKTRACE=1` to confirm which `flat_map_*` is multiplying statements."],"exampleFix":"// before\nimpl<'a> MutVisitor for MyVis { /* no flat_map_stmt override; default walk expands */ }\n\n// after\nimpl<'a> MutVisitor for MyVis {\n    fn flat_map_stmt(&mut self, mut st: Stmt) -> SmallVec<[Stmt; 1]> {\n        // assign fresh ids to each expanded statement\n        ...\n    }\n}","handlingStrategy":"validation","validationCode":"// The default flat_map visitor clones NodeId when one stmt expands to many.\n// Override statement visiting in your MutVisitor:\nimpl MutVisitor for MyVisitor {\n    fn visit_stmt(&mut self, stmt: &mut Stmt) {\n        // assign fresh Node_id, or fold flat_map yourself\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Implement `visit_stmt` (or `flat_map_stmt`) on your `MutVisitor` whenever an AST rewrite can split one statement into several — that is the only sanctioned way to handle NodeId cloning.","Do not rely on `walk_flat_map_stmt_kind` for transformations that change the statement count.","If a single stmt must yield >1 stmt, mint new `NodeId`s explicitly rather than reusing the source id."],"tags":["rustc","internals","mut-visitor","node-id","invariant"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}