From 0fbd1d257a7cf9ab5f94a9db74ca52c68af4aca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Sat, 14 Feb 2026 00:04:53 +0000 Subject: [PATCH] astgen: fix ifExpr payload_is_ref, bool coercion, ensure_err_union_payload_void, and discard handling Co-Authored-By: Claude Opus 4.6 --- astgen.c | 168 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 54 deletions(-) diff --git a/astgen.c b/astgen.c index ff10954748..9b74a1ba8f 100644 --- a/astgen.c +++ b/astgen.c @@ -2327,6 +2327,7 @@ static uint32_t fullBodyExpr( GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, uint8_t name_strategy, uint32_t* out_ref); +static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token); static uint32_t containerDecl( GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy); static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, @@ -5572,19 +5573,19 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { then_node = nd.rhs; else_node = 0; } else { - // AST_NODE_IF: rhs is index into extra → If{then_expr, else_expr} + // AST_NODE_IF: rhs is index into extra -> If{then_expr, else_expr} then_node = tree->extra_data.arr[nd.rhs]; else_node = tree->extra_data.arr[nd.rhs + 1]; } // Detect payload capture: if (cond) |x| (AstGen.zig Ast.fullIf). - // payload_pipe = lastToken(cond_expr) + 2; if pipe → payload_token + 1. + // payload_pipe = lastToken(cond_expr) + 2; if pipe -> payload_token + 1. uint32_t payload_token = 0; // 0 = no payload uint32_t last_cond_tok = lastToken(tree, cond_node); uint32_t pipe_tok = last_cond_tok + 2; if (pipe_tok < tree->tokens.len && tree->tokens.tags[pipe_tok] == TOKEN_PIPE) { - payload_token = pipe_tok + 1; // identifier token + payload_token = pipe_tok + 1; // identifier or * token } // Detect error token: then_expr else |e| (AstGen.zig Ast.fullIf). @@ -5597,6 +5598,10 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { } } + // Detect payload_is_ref: if payload_token is '*' (AstGen.zig:6330-6333). + bool payload_is_ref = (payload_token != 0 + && tree->tokens.tags[payload_token] == TOKEN_ASTERISK); + // Create block_scope (AstGen.zig:6326-6328). GenZir block_scope = makeSubBlock(gz, scope); @@ -5605,26 +5610,37 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { // so the dbg_stmt ends up in block_scope's range (shared array). emitDbgNode(gz, cond_node); - // Evaluate condition (AstGen.zig:6335-6363). + // Evaluate condition (AstGen.zig:6336-6363). uint32_t cond_inst; // the value (optional/err-union/bool) uint32_t bool_bit; // the boolean for condbr if (error_token != 0) { // Error union condition: if (err_union) |val| else |err|. - // (AstGen.zig:6341). - ResultLoc cond_rl = RL_NONE_VAL; + // (AstGen.zig:6340-6347). + ResultLoc cond_rl = payload_is_ref ? RL_REF_VAL : RL_NONE_VAL; cond_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; cond_inst = exprRl(&block_scope, &block_scope.base, cond_rl, cond_node); - bool_bit = addUnNode( - &block_scope, ZIR_INST_IS_NON_ERR, cond_inst, cond_node); + ZirInstTag cond_tag + = payload_is_ref ? ZIR_INST_IS_NON_ERR_PTR : ZIR_INST_IS_NON_ERR; + bool_bit = addUnNode(&block_scope, cond_tag, cond_inst, cond_node); } else if (payload_token != 0) { - // Optional condition: if (optional) |val|. - cond_inst = expr(&block_scope, &block_scope.base, cond_node); - bool_bit = addUnNode( - &block_scope, ZIR_INST_IS_NON_NULL, cond_inst, cond_node); + // Optional condition: if (optional) |val| (AstGen.zig:6348-6355). + ResultLoc cond_rl = payload_is_ref ? RL_REF_VAL : RL_NONE_VAL; + cond_inst + = exprRl(&block_scope, &block_scope.base, cond_rl, cond_node); + ZirInstTag cond_tag + = payload_is_ref ? ZIR_INST_IS_NON_NULL_PTR : ZIR_INST_IS_NON_NULL; + bool_bit = addUnNode(&block_scope, cond_tag, cond_inst, cond_node); } else { // Bool condition (AstGen.zig:6356-6362). - cond_inst = expr(&block_scope, &block_scope.base, cond_node); + ResultLoc coerced_bool_ri = { + .tag = RL_COERCED_TY, + .data = ZIR_REF_BOOL_TYPE, + .src_node = 0, + .ctx = RI_CTX_NONE, + }; + cond_inst = exprRl( + &block_scope, &block_scope.base, coerced_bool_ri, cond_node); bool_bit = cond_inst; } @@ -5640,35 +5656,68 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { memset(&payload_val_scope, 0, sizeof(payload_val_scope)); if (error_token != 0 && payload_token != 0) { - // Error union with payload: unwrap payload (AstGen.zig:6379-6407). - uint32_t payload_inst = addUnNode(&then_scope, - ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE, cond_inst, then_node); - uint32_t ident_name = identAsString(ag, payload_token); - payload_val_scope = (ScopeLocalVal) { - .base = { .tag = SCOPE_LOCAL_VAL }, - .parent = &then_scope.base, - .gen_zir = &then_scope, - .inst = payload_inst, - .token_src = payload_token, - .name = ident_name, - }; - addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); - then_sub_scope = &payload_val_scope.base; + // Error union with payload: unwrap payload (AstGen.zig:6379-6403). + ZirInstTag unwrap_tag = payload_is_ref + ? ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE_PTR + : ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE; + uint32_t payload_inst + = addUnNode(&then_scope, unwrap_tag, cond_inst, then_node); + uint32_t name_token = payload_token + (payload_is_ref ? 1u : 0u); + if (tokenIsUnderscore(tree, name_token)) { + // Discard (AstGen.zig:6389-6391). + if (payload_is_ref) { + SET_ERROR(ag); + return ZIR_REF_VOID_VALUE; + } + // then_sub_scope stays as &then_scope.base + } else { + uint32_t ident_name = identAsString(ag, name_token); + payload_val_scope = (ScopeLocalVal) { + .base = { .tag = SCOPE_LOCAL_VAL }, + .parent = &then_scope.base, + .gen_zir = &then_scope, + .inst = payload_inst, + .token_src = name_token, + .name = ident_name, + }; + addDbgVar( + &then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); + then_sub_scope = &payload_val_scope.base; + } + } else if (error_token != 0) { + // Error union without payload: ensure payload is void + // (AstGen.zig:6404-6406). + addUnNode(&then_scope, ZIR_INST_ENSURE_ERR_UNION_PAYLOAD_VOID, + cond_inst, node); } else if (payload_token != 0) { // Optional with payload: unwrap optional (AstGen.zig:6408-6431). - uint32_t payload_inst = addUnNode(&then_scope, - ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE, cond_inst, then_node); - uint32_t ident_name = identAsString(ag, payload_token); - payload_val_scope = (ScopeLocalVal) { - .base = { .tag = SCOPE_LOCAL_VAL }, - .parent = &then_scope.base, - .gen_zir = &then_scope, - .inst = payload_inst, - .token_src = payload_token, - .name = ident_name, - }; - addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); - then_sub_scope = &payload_val_scope.base; + uint32_t ident_token = payload_token + (payload_is_ref ? 1u : 0u); + if (tokenIsUnderscore(tree, ident_token)) { + // Discard (AstGen.zig:6415-6417). + if (payload_is_ref) { + SET_ERROR(ag); + return ZIR_REF_VOID_VALUE; + } + // then_sub_scope stays as &then_scope.base + } else { + ZirInstTag unwrap_tag = payload_is_ref + ? ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE_PTR + : ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE; + uint32_t payload_inst + = addUnNode(&then_scope, unwrap_tag, cond_inst, then_node); + uint32_t ident_name = identAsString(ag, ident_token); + payload_val_scope = (ScopeLocalVal) { + .base = { .tag = SCOPE_LOCAL_VAL }, + .parent = &then_scope.base, + .gen_zir = &then_scope, + .inst = payload_inst, + .token_src = ident_token, + .name = ident_name, + }; + addDbgVar( + &then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); + then_sub_scope = &payload_val_scope.base; + } } // Use fullBodyExpr for then body (AstGen.zig:6437). @@ -5694,19 +5743,27 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { if (error_token != 0) { // Error capture: else |err| (AstGen.zig:6452-6475). - uint32_t err_inst = addUnNode( - &else_scope, ZIR_INST_ERR_UNION_CODE, cond_inst, cond_node); - uint32_t err_name = identAsString(ag, error_token); - error_val_scope = (ScopeLocalVal) { - .base = { .tag = SCOPE_LOCAL_VAL }, - .parent = &else_scope.base, - .gen_zir = &else_scope, - .inst = err_inst, - .token_src = error_token, - .name = err_name, - }; - addDbgVar(&else_scope, ZIR_INST_DBG_VAR_VAL, err_name, err_inst); - else_sub_scope = &error_val_scope.base; + ZirInstTag err_tag = payload_is_ref ? ZIR_INST_ERR_UNION_CODE_PTR + : ZIR_INST_ERR_UNION_CODE; + uint32_t err_inst + = addUnNode(&else_scope, err_tag, cond_inst, cond_node); + if (tokenIsUnderscore(tree, error_token)) { + // Discard |_| (AstGen.zig:6461-6462). + // else_sub_scope stays as &else_scope.base + } else { + uint32_t err_name = identAsString(ag, error_token); + error_val_scope = (ScopeLocalVal) { + .base = { .tag = SCOPE_LOCAL_VAL }, + .parent = &else_scope.base, + .gen_zir = &else_scope, + .inst = err_inst, + .token_src = error_token, + .name = err_name, + }; + addDbgVar( + &else_scope, ZIR_INST_DBG_VAR_VAL, err_name, err_inst); + else_sub_scope = &error_val_scope.base; + } } // Use fullBodyExpr for else body (AstGen.zig:6478). @@ -5721,7 +5778,10 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { (int32_t)else_node - (int32_t)gz->decl_node_index); } } else { - addBreak(&else_scope, ZIR_INST_BREAK, block_inst, ZIR_REF_VOID_VALUE, + // No else branch (AstGen.zig:6486-6488). + uint32_t else_result + = rvalue(&else_scope, rl, ZIR_REF_VOID_VALUE, node); + addBreak(&else_scope, ZIR_INST_BREAK, block_inst, else_result, AST_NODE_OFFSET_NONE); }