@@ -192,7 +192,18 @@ impl Transform for SinkLets {
192192 Some ( x) => x; return ) ;
193193
194194 let mut new_stmts = place_here. iter ( )
195- . map ( |& id| mk ( ) . local_stmt ( & locals[ & id] . local ) )
195+ . map ( |& id| {
196+ let local = & locals[ & id] . local ;
197+ // Set the statement's span to match the local's span.
198+ //
199+ // By default, mk().local_stmt() creates a Stmt with DUMMY_SP. The rewrite system
200+ // uses stmt.span (via the Splice trait) to extract source text for recovery during
201+ // the print/reparse cycle. Without a valid span, source extraction fails.
202+ //
203+ // Setting stmt.span = local.span provides a valid source location. The Splice
204+ // implementation in print.rs will extend this to cover any attributes.
205+ mk ( ) . span ( local. span ) . local_stmt ( local)
206+ } )
196207 . collect :: < Vec < _ > > ( ) ;
197208 new_stmts. append ( & mut b. stmts ) ;
198209 b. stmts = new_stmts;
@@ -415,7 +426,21 @@ impl Transform for FoldLetAssign {
415426 let local_mark = local_pos. remove ( & hir_id) . unwrap ( ) ;
416427 let mut l = local. clone ( ) ;
417428 l. kind = LocalKind :: Init ( init) ;
418- curs. replace ( |_| mk ( ) . local_stmt ( l) ) ;
429+
430+ // Preserve the original local's span when creating the combined statement.
431+ //
432+ // fold_let_assign transforms:
433+ // let x; <- original local
434+ // x = expr; <- assignment
435+ // into:
436+ // let x = expr; <- combined local
437+ //
438+ // The combined Local keeps l.span from the original declaration. Setting
439+ // stmt.span = l.span allows the rewrite system to extract source text using
440+ // the Splice trait. Without this, stmt.span would be DUMMY_SP and source
441+ // extraction would fail.
442+ let stmt_span = l. span ;
443+ curs. replace ( move |_| mk ( ) . span ( stmt_span) . local_stmt ( l) ) ;
419444
420445 let here = curs. mark ( ) ;
421446 curs. seek ( local_mark) ;
@@ -514,6 +539,7 @@ impl Transform for RemoveRedundantLetTypes {
514539 let pat = mcx. parse_stmts ( "let $pat:Pat : $ty:Ty = $init:Expr;" ) ;
515540 let repl = mcx. parse_stmts ( "let $pat = $init;" ) ;
516541 mut_visit_match_with ( mcx, pat, krate, |ast, mcx| {
542+ let orig_span = ast. get ( 0 ) . map ( |s| s. span ) ;
517543 let e = mcx. bindings . get :: < _ , P < Expr > > ( "$init" ) . unwrap ( ) ;
518544 let e_ty = cx. adjusted_node_type ( e. id ) ;
519545 let e_ty = tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , e_ty) ;
@@ -523,6 +549,14 @@ impl Transform for RemoveRedundantLetTypes {
523549 let t_ty = tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , t_ty) ;
524550 if e_ty == t_ty {
525551 * ast = repl. clone ( ) . subst ( st, cx, & mcx. bindings ) ;
552+ // Preserve the original statement's span after replacement.
553+ //
554+ // The subst() call creates a new Stmt from the replacement pattern, which has
555+ // a synthetic span from the pattern parse. Restoring the original span allows
556+ // the rewrite system to extract source text via the Splice trait.
557+ if let ( Some ( span) , Some ( first) ) = ( orig_span, ast. get_mut ( 0 ) ) {
558+ first. span = span;
559+ }
526560 }
527561 } )
528562 }
0 commit comments