astgen: fix ifExpr payload_is_ref, bool coercion, ensure_err_union_payload_void, and discard handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 00:04:53 +00:00
parent 9345c89d43
commit 0fbd1d257a

116
astgen.c
View File

@@ -2327,6 +2327,7 @@ static uint32_t fullBodyExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl, static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
uint32_t node, uint8_t name_strategy, uint32_t* out_ref); 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( static uint32_t containerDecl(
GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy); GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy);
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, 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; then_node = nd.rhs;
else_node = 0; else_node = 0;
} else { } 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]; then_node = tree->extra_data.arr[nd.rhs];
else_node = tree->extra_data.arr[nd.rhs + 1]; else_node = tree->extra_data.arr[nd.rhs + 1];
} }
// Detect payload capture: if (cond) |x| (AstGen.zig Ast.fullIf). // 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 payload_token = 0; // 0 = no payload
uint32_t last_cond_tok = lastToken(tree, cond_node); uint32_t last_cond_tok = lastToken(tree, cond_node);
uint32_t pipe_tok = last_cond_tok + 2; uint32_t pipe_tok = last_cond_tok + 2;
if (pipe_tok < tree->tokens.len if (pipe_tok < tree->tokens.len
&& tree->tokens.tags[pipe_tok] == TOKEN_PIPE) { && 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). // 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). // Create block_scope (AstGen.zig:6326-6328).
GenZir block_scope = makeSubBlock(gz, scope); 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). // so the dbg_stmt ends up in block_scope's range (shared array).
emitDbgNode(gz, cond_node); 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 cond_inst; // the value (optional/err-union/bool)
uint32_t bool_bit; // the boolean for condbr uint32_t bool_bit; // the boolean for condbr
if (error_token != 0) { if (error_token != 0) {
// Error union condition: if (err_union) |val| else |err|. // Error union condition: if (err_union) |val| else |err|.
// (AstGen.zig:6341). // (AstGen.zig:6340-6347).
ResultLoc cond_rl = RL_NONE_VAL; ResultLoc cond_rl = payload_is_ref ? RL_REF_VAL : RL_NONE_VAL;
cond_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; cond_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR;
cond_inst cond_inst
= exprRl(&block_scope, &block_scope.base, cond_rl, cond_node); = exprRl(&block_scope, &block_scope.base, cond_rl, cond_node);
bool_bit = addUnNode( ZirInstTag cond_tag
&block_scope, ZIR_INST_IS_NON_ERR, cond_inst, cond_node); = 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) { } else if (payload_token != 0) {
// Optional condition: if (optional) |val|. // Optional condition: if (optional) |val| (AstGen.zig:6348-6355).
cond_inst = expr(&block_scope, &block_scope.base, cond_node); ResultLoc cond_rl = payload_is_ref ? RL_REF_VAL : RL_NONE_VAL;
bool_bit = addUnNode( cond_inst
&block_scope, ZIR_INST_IS_NON_NULL, cond_inst, cond_node); = 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 { } else {
// Bool condition (AstGen.zig:6356-6362). // 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; bool_bit = cond_inst;
} }
@@ -5640,36 +5656,69 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
memset(&payload_val_scope, 0, sizeof(payload_val_scope)); memset(&payload_val_scope, 0, sizeof(payload_val_scope));
if (error_token != 0 && payload_token != 0) { if (error_token != 0 && payload_token != 0) {
// Error union with payload: unwrap payload (AstGen.zig:6379-6407). // Error union with payload: unwrap payload (AstGen.zig:6379-6403).
uint32_t payload_inst = addUnNode(&then_scope, ZirInstTag unwrap_tag = payload_is_ref
ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE, cond_inst, then_node); ? ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE_PTR
uint32_t ident_name = identAsString(ag, payload_token); : 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) { payload_val_scope = (ScopeLocalVal) {
.base = { .tag = SCOPE_LOCAL_VAL }, .base = { .tag = SCOPE_LOCAL_VAL },
.parent = &then_scope.base, .parent = &then_scope.base,
.gen_zir = &then_scope, .gen_zir = &then_scope,
.inst = payload_inst, .inst = payload_inst,
.token_src = payload_token, .token_src = name_token,
.name = ident_name, .name = ident_name,
}; };
addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); addDbgVar(
&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst);
then_sub_scope = &payload_val_scope.base; 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) { } else if (payload_token != 0) {
// Optional with payload: unwrap optional (AstGen.zig:6408-6431). // Optional with payload: unwrap optional (AstGen.zig:6408-6431).
uint32_t payload_inst = addUnNode(&then_scope, uint32_t ident_token = payload_token + (payload_is_ref ? 1u : 0u);
ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE, cond_inst, then_node); if (tokenIsUnderscore(tree, ident_token)) {
uint32_t ident_name = identAsString(ag, payload_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) { payload_val_scope = (ScopeLocalVal) {
.base = { .tag = SCOPE_LOCAL_VAL }, .base = { .tag = SCOPE_LOCAL_VAL },
.parent = &then_scope.base, .parent = &then_scope.base,
.gen_zir = &then_scope, .gen_zir = &then_scope,
.inst = payload_inst, .inst = payload_inst,
.token_src = payload_token, .token_src = ident_token,
.name = ident_name, .name = ident_name,
}; };
addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); addDbgVar(
&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst);
then_sub_scope = &payload_val_scope.base; then_sub_scope = &payload_val_scope.base;
} }
}
// Use fullBodyExpr for then body (AstGen.zig:6437). // Use fullBodyExpr for then body (AstGen.zig:6437).
uint32_t then_result uint32_t then_result
@@ -5694,8 +5743,14 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
if (error_token != 0) { if (error_token != 0) {
// Error capture: else |err| (AstGen.zig:6452-6475). // Error capture: else |err| (AstGen.zig:6452-6475).
uint32_t err_inst = addUnNode( ZirInstTag err_tag = payload_is_ref ? ZIR_INST_ERR_UNION_CODE_PTR
&else_scope, ZIR_INST_ERR_UNION_CODE, cond_inst, cond_node); : 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); uint32_t err_name = identAsString(ag, error_token);
error_val_scope = (ScopeLocalVal) { error_val_scope = (ScopeLocalVal) {
.base = { .tag = SCOPE_LOCAL_VAL }, .base = { .tag = SCOPE_LOCAL_VAL },
@@ -5705,9 +5760,11 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
.token_src = error_token, .token_src = error_token,
.name = err_name, .name = err_name,
}; };
addDbgVar(&else_scope, ZIR_INST_DBG_VAR_VAL, err_name, err_inst); addDbgVar(
&else_scope, ZIR_INST_DBG_VAR_VAL, err_name, err_inst);
else_sub_scope = &error_val_scope.base; else_sub_scope = &error_val_scope.base;
} }
}
// Use fullBodyExpr for else body (AstGen.zig:6478). // Use fullBodyExpr for else body (AstGen.zig:6478).
uint32_t else_result uint32_t else_result
@@ -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); (int32_t)else_node - (int32_t)gz->decl_node_index);
} }
} else { } 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); AST_NODE_OFFSET_NONE);
} }