@@ -1210,9 +1210,29 @@ let transformTryCatch com (ctx: Context) r returnStrategy (body, catch: (Fable.I
12101210 // try .. catch statements cannot be tail call optimized
12111211 let ctx = { ctx with TailCallOpportunity = None }
12121212
1213- let makeHandler exnType handlerBody identifier =
1214- let transformedBody = transformBlock com ctx returnStrategy handlerBody
1215- ExceptHandler.exceptHandler ( `` type `` = Some exnType, name = identifier, body = transformedBody)
1213+ let makeHandler exnType handlerBody ( param : Fable.Ident ) identifier =
1214+ let ( Identifier identName ) = identifier
1215+
1216+ // Python's `except E as name:` deletes `name` at the end of the except block.
1217+ // If the exception variable is used (e.g., captured in a deferred closure), copy
1218+ // it to a safe local with a unique name that Python won't delete, and rename all
1219+ // body references to use the safe copy.
1220+ if isIdentUsed param.Name handlerBody then
1221+ let safeIdentName = getUniqueNameInDeclarationScope ctx ( identName + " _" )
1222+ let safeParam = { param with Name = safeIdentName }
1223+
1224+ let renamedBody =
1225+ FableTransforms.replaceValues ( Map [ param.Name, Fable.IdentExpr safeParam ]) handlerBody
1226+
1227+ let transformedBody = transformBlock com ctx returnStrategy renamedBody
1228+ // Annotated assignment: ex_: ExceptionType = ex
1229+ let saveStmt =
1230+ Statement.assign ( identAsExpr com ctx safeParam, exnType, value = Expression.name identName)
1231+
1232+ ExceptHandler.exceptHandler ( `` type `` = Some exnType, name = identifier, body = saveStmt :: transformedBody)
1233+ else
1234+ let transformedBody = transformBlock com ctx returnStrategy handlerBody
1235+ ExceptHandler.exceptHandler ( `` type `` = Some exnType, name = identifier, body = transformedBody)
12161236
12171237 let handlers , handlerStmts =
12181238 match catch with
@@ -1228,7 +1248,8 @@ let transformTryCatch com (ctx: Context) r returnStrategy (body, catch: (Fable.I
12281248 // No type tests found, use Exception to match F#/.NET semantics.
12291249 // Users can explicitly catch KeyboardInterrupt, SystemExit, GeneratorExit
12301250 // using type tests if needed.
1231- let handler = makeHandler ( Expression.identifier " Exception" ) catchBody identifier
1251+ let handler =
1252+ makeHandler ( Expression.identifier " Exception" ) catchBody param identifier
12321253
12331254 Some [ handler ], []
12341255
@@ -1239,7 +1260,7 @@ let transformTryCatch com (ctx: Context) r returnStrategy (body, catch: (Fable.I
12391260 |> List.choose ( fun ( typ , handlerBody ) ->
12401261 getExceptionTypeExpr com ctx typ
12411262 |> Option.map ( fun ( exnTypeExpr , stmts ) ->
1242- makeHandler exnTypeExpr handlerBody identifier, stmts
1263+ makeHandler exnTypeExpr handlerBody param identifier, stmts
12431264 )
12441265 )
12451266 |> List.unzip
@@ -1249,7 +1270,9 @@ let transformTryCatch com (ctx: Context) r returnStrategy (body, catch: (Fable.I
12491270 let fallbackHandlers =
12501271 match fallback with
12511272 | Some fallbackExpr when not ( ExceptionHandling.isReraise fallbackExpr) ->
1252- [ makeHandler ( Expression.identifier " Exception" ) fallbackExpr identifier ]
1273+ [
1274+ makeHandler ( Expression.identifier " Exception" ) fallbackExpr param identifier
1275+ ]
12531276 | _ -> []
12541277
12551278 Some( handlers @ fallbackHandlers), List.concat stmts
0 commit comments