diff --git a/src/c_backend.bux b/src/c_backend.bux index 2f0a470..8396c46 100644 --- a/src/c_backend.bux +++ b/src/c_backend.bux @@ -76,6 +76,7 @@ struct CEmitter { sb: StringBuilder, indent: int, mod: *HirModule, + checkedFunc: bool, deferCount: int, defer0: *HirNode, defer1: *HirNode, @@ -1081,6 +1082,7 @@ func CBackend_Generate(mod: *HirModule) -> String { CBE_EmitFuncDecl(cbe, &mod.funcs[i]); StringBuilder_Append(&cbe.sb, " {\n"); // Body + cbe.checkedFunc = mod.funcs[i].checkedFunc; var hasReturn: bool = false; cbe.indent = 1; CBE_EmitExpr(cbe, body); diff --git a/src/hir.bux b/src/hir.bux index 4a913a5..57bae94 100644 --- a/src/hir.bux +++ b/src/hir.bux @@ -114,6 +114,7 @@ struct HirFunc { captureType7: int; envStructName: String; envInstanceName: String; + checkedFunc: bool; } // --------------------------------------------------------------------------- diff --git a/src/hir_lower.bux b/src/hir_lower.bux index 1512a4e..1f6e724 100644 --- a/src/hir_lower.bux +++ b/src/hir_lower.bux @@ -973,6 +973,34 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { storeNode.child1 = alloca; storeNode.child2 = init; + // Auto-Drop for Array in @[Checked] functions + var deferNode: *HirNode = null as *HirNode; + if ctx.checkedFunc && !String_Eq(alloca.typeName, "") { + if String_StartsWith(alloca.typeName, "Array_") { + let elemType: String = bux_str_slice(alloca.typeName, 6, bux_strlen(alloca.typeName) - 6); + // Generate Array_Free instance + let genFree: *Decl = Lcx_FindGenericFunc(ctx, "Array_Free"); + if genFree != null as *Decl { + Lcx_GenerateFuncInstance(ctx, genFree, elemType, "", 1); + } + // Build defer Array_Free_T(&var) + let varRef: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; + varRef.kind = hVar; + varRef.strValue = stmt.strValue; + let addrNode: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; + addrNode.kind = hUnary; + addrNode.intValue = tkAmp; + addrNode.child1 = varRef; + let callNode: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; + callNode.kind = hCall; + callNode.strValue = String_Concat("Array_Free_", elemType); + callNode.child1 = addrNode; + deferNode = bux_alloc(sizeof(HirNode)) as *HirNode; + deferNode.kind = hDefer; + deferNode.child1 = callNode; + } + } + // If init is a closure with captures, emit capture assignments before the let if stmt.child1 != null as *Expr && stmt.child1.kind == ekClosure && stmt.child1.captureCount > 0 { let closureIdx: int = ctx.funcCount - 1; @@ -1029,9 +1057,24 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { lastStmt.child3 = storeNode; lastStmt = storeNode; } + // Append auto-Drop defer if present + if deferNode != null as *HirNode { + lastStmt.child3 = deferNode; + lastStmt = deferNode; + } blockNode.child1 = firstStmt; return blockNode; } + // Non-closure: wrap with defer if present + if deferNode != null as *HirNode { + storeNode.child3 = deferNode; + let blockNode: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; + blockNode.kind = hBlock; + blockNode.line = line; + blockNode.column = col; + blockNode.child1 = storeNode; + return blockNode; + } return storeNode; } @@ -1625,6 +1668,7 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc { let f: *HirFunc = bux_alloc(sizeof(HirFunc)) as *HirFunc; f.name = decl.strValue; f.isPublic = decl.isPublic; + f.checkedFunc = ctx.checkedFunc; f.paramCount = decl.paramCount; f.param0 = bux_alloc(sizeof(HirParam)) as *HirParam; Lcx_LowerParam(f.param0, &decl.param0, ctx);