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:
168
astgen.c
168
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user