astgen: fix globalVarDecl coercion, nameStratExpr, and error diagnostics

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 23:58:59 +00:00
parent 1fd8dace86
commit 9345c89d43

188
astgen.c
View File

@@ -2325,11 +2325,15 @@ static void blockExprStmts(
GenZir* gz, Scope* scope, const uint32_t* statements, uint32_t stmt_count); GenZir* gz, Scope* scope, const uint32_t* statements, uint32_t stmt_count);
static uint32_t fullBodyExpr( static uint32_t fullBodyExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node); static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
uint32_t node, uint8_t name_strategy, uint32_t* out_ref);
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, static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
const uint32_t* members, uint32_t members_len); const uint32_t* members, uint32_t members_len, uint8_t name_strategy);
static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
const uint32_t* members, uint32_t members_len, uint32_t arg_node); const uint32_t* members, uint32_t members_len, uint32_t arg_node,
uint8_t name_strategy);
static uint32_t blockExprExpr( static uint32_t blockExprExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
@@ -3737,9 +3741,12 @@ static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) {
ret_rl.data = ag->fn_ret_ty; ret_rl.data = ag->fn_ret_ty;
} }
ret_rl.ctx = RI_CTX_RETURN; ret_rl.ctx = RI_CTX_RETURN;
// TODO: nameStratExpr(gz, scope, ret_rl, operand_node, .func) when // nameStratExpr with .func name strategy (AstGen.zig:8185).
// containerDecl supports name_strategy parameter. uint32_t operand;
uint32_t operand = reachableExpr(gz, scope, ret_rl, operand_node, node); if (!nameStratExpr(
gz, scope, ret_rl, operand_node, 1 /* func */, &operand)) {
operand = reachableExpr(gz, scope, ret_rl, operand_node, node);
}
// Emit RESTORE_ERR_RET_INDEX based on nodeMayEvalToError // Emit RESTORE_ERR_RET_INDEX based on nodeMayEvalToError
// (AstGen.zig:8188-8253). // (AstGen.zig:8188-8253).
@@ -4554,7 +4561,8 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
case AST_NODE_TAGGED_UNION_TWO_TRAILING: case AST_NODE_TAGGED_UNION_TWO_TRAILING:
case AST_NODE_TAGGED_UNION_ENUM_TAG: case AST_NODE_TAGGED_UNION_ENUM_TAG:
case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING:
return rvalue(gz, rl, containerDecl(gz, scope, node), node); return rvalue(
gz, rl, containerDecl(gz, scope, node, 2 /* anon */), node);
// try (AstGen.zig:1115). // try (AstGen.zig:1115).
case AST_NODE_TRY: case AST_NODE_TRY:
return tryExpr(gz, scope, rl, node); return tryExpr(gz, scope, rl, node);
@@ -9534,12 +9542,69 @@ static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub,
return DECL_ID_VAR_SIMPLE; return DECL_ID_VAR_SIMPLE;
} }
// Mirrors nameStratExpr (AstGen.zig:1160-1199).
// Checks if node is a container decl or @Type builtin; if so, dispatches
// with the given name_strategy. Returns true if handled (result stored in
// *out_ref), false if caller should fall back to expr().
static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
uint32_t node, uint8_t name_strategy, uint32_t* out_ref) {
const AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
AstNodeTag tag = tree->nodes.tags[node];
(void)rl; // Used by builtinReify (not yet implemented).
switch (tag) {
case AST_NODE_CONTAINER_DECL:
case AST_NODE_CONTAINER_DECL_TRAILING:
case AST_NODE_CONTAINER_DECL_TWO:
case AST_NODE_CONTAINER_DECL_TWO_TRAILING:
case AST_NODE_CONTAINER_DECL_ARG:
case AST_NODE_CONTAINER_DECL_ARG_TRAILING:
case AST_NODE_TAGGED_UNION:
case AST_NODE_TAGGED_UNION_TRAILING:
case AST_NODE_TAGGED_UNION_TWO:
case AST_NODE_TAGGED_UNION_TWO_TRAILING:
case AST_NODE_TAGGED_UNION_ENUM_TAG:
case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING:
*out_ref = containerDecl(gz, scope, node, name_strategy);
return true;
// @Type builtin: upstream calls builtinReify (AstGen.zig:1186-1196).
// Not yet implemented; fall through to expr().
default:
return false;
}
}
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
uint32_t* decl_idx, uint32_t node) { uint32_t* decl_idx, uint32_t node) {
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
VarDeclInfo vd = extractVarDecl(tree, node); VarDeclInfo vd = extractVarDecl(tree, node);
uint32_t name_token = vd.mut_token + 1; uint32_t name_token = vd.mut_token + 1;
// "threadlocal variable cannot be constant" (AstGen.zig:4526-4528).
if (vd.is_threadlocal && !vd.is_mutable) {
SET_ERROR(ag);
return;
}
// lib_name validation (AstGen.zig:4531-4540).
uint32_t lib_name = UINT32_MAX;
if (vd.lib_name_token != UINT32_MAX) {
uint32_t li, ll;
strLitAsString(ag, vd.lib_name_token, &li, &ll);
// "library name cannot contain null bytes" (AstGen.zig:4534-4535).
if (memchr(ag->string_bytes + li, 0, ll) != NULL) {
SET_ERROR(ag);
return;
}
// "library name cannot be empty" (AstGen.zig:4536-4537).
if (ll == 0) {
SET_ERROR(ag);
return;
}
lib_name = li;
}
// advanceSourceCursorToNode before makeDeclaration (AstGen.zig:4542-4546). // advanceSourceCursorToNode before makeDeclaration (AstGen.zig:4542-4546).
advanceSourceCursorToNode(ag, node); advanceSourceCursorToNode(ag, node);
uint32_t decl_column = ag->source_column; uint32_t decl_column = ag->source_column;
@@ -9548,6 +9613,26 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
wip_decl_insts[*decl_idx] = decl_inst; wip_decl_insts[*decl_idx] = decl_inst;
(*decl_idx)++; (*decl_idx)++;
// "extern variables have no initializers" (AstGen.zig:4549-4556).
if (vd.init_node != UINT32_MAX && vd.init_node != 0) {
if (vd.is_extern) {
SET_ERROR(ag);
return;
}
} else {
// "variables must be initialized" (AstGen.zig:4557-4561).
if (!vd.is_extern) {
SET_ERROR(ag);
return;
}
}
// "unable to infer variable type" (AstGen.zig:4563-4565).
if (vd.is_extern && vd.type_node == 0) {
SET_ERROR(ag);
return;
}
// Set up type sub-block (AstGen.zig:4574-4582). // Set up type sub-block (AstGen.zig:4574-4582).
GenZir type_gz; GenZir type_gz;
memset(&type_gz, 0, sizeof(type_gz)); memset(&type_gz, 0, sizeof(type_gz));
@@ -9567,7 +9652,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
// Record type_gz boundary for slicing. // Record type_gz boundary for slicing.
uint32_t type_top = ag->scratch_inst_len; uint32_t type_top = ag->scratch_inst_len;
// Align sub-block (AstGen.zig:4592-4596). // Align sub-block (AstGen.zig:4585-4591).
GenZir align_gz; GenZir align_gz;
memset(&align_gz, 0, sizeof(align_gz)); memset(&align_gz, 0, sizeof(align_gz));
align_gz.base.tag = SCOPE_GEN_ZIR; align_gz.base.tag = SCOPE_GEN_ZIR;
@@ -9579,13 +9664,20 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
align_gz.any_defer_node = UINT32_MAX; align_gz.any_defer_node = UINT32_MAX;
if (vd.align_node != 0) { if (vd.align_node != 0) {
uint32_t align_inst = expr(&align_gz, &align_gz.base, vd.align_node); // coerced_align_ri = { .rl = .{ .coerced_ty = .u29_type } }
// (AstGen.zig:389, 4589).
ResultLoc align_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_U29_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t align_inst
= exprRl(&align_gz, &align_gz.base, align_rl, vd.align_node);
makeBreakInline(&align_gz, decl_inst, align_inst, 0); makeBreakInline(&align_gz, decl_inst, align_inst, 0);
} }
uint32_t align_top = ag->scratch_inst_len; uint32_t align_top = ag->scratch_inst_len;
// Linksection sub-block (AstGen.zig:4598-4602). // Linksection sub-block (AstGen.zig:4593-4599).
GenZir linksection_gz; GenZir linksection_gz;
memset(&linksection_gz, 0, sizeof(linksection_gz)); memset(&linksection_gz, 0, sizeof(linksection_gz));
linksection_gz.base.tag = SCOPE_GEN_ZIR; linksection_gz.base.tag = SCOPE_GEN_ZIR;
@@ -9597,14 +9689,20 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
linksection_gz.any_defer_node = UINT32_MAX; linksection_gz.any_defer_node = UINT32_MAX;
if (vd.section_node != 0) { if (vd.section_node != 0) {
uint32_t ls_inst // coerced_linksection_ri = { .rl = .{ .coerced_ty =
= expr(&linksection_gz, &linksection_gz.base, vd.section_node); // .slice_const_u8_type } } (AstGen.zig:390, 4597).
ResultLoc ls_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_SLICE_CONST_U8_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t ls_inst = exprRl(
&linksection_gz, &linksection_gz.base, ls_rl, vd.section_node);
makeBreakInline(&linksection_gz, decl_inst, ls_inst, 0); makeBreakInline(&linksection_gz, decl_inst, ls_inst, 0);
} }
uint32_t linksection_top = ag->scratch_inst_len; uint32_t linksection_top = ag->scratch_inst_len;
// Addrspace sub-block (AstGen.zig:4604-4608). // Addrspace sub-block (AstGen.zig:4601-4608).
GenZir addrspace_gz; GenZir addrspace_gz;
memset(&addrspace_gz, 0, sizeof(addrspace_gz)); memset(&addrspace_gz, 0, sizeof(addrspace_gz));
addrspace_gz.base.tag = SCOPE_GEN_ZIR; addrspace_gz.base.tag = SCOPE_GEN_ZIR;
@@ -9616,14 +9714,22 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
addrspace_gz.any_defer_node = UINT32_MAX; addrspace_gz.any_defer_node = UINT32_MAX;
if (vd.addrspace_node != 0) { if (vd.addrspace_node != 0) {
uint32_t as_inst // Upstream: addBuiltinValue(addrspace_node, .address_space) then
= expr(&addrspace_gz, &addrspace_gz.base, vd.addrspace_node); // coerced_ty with that result (AstGen.zig:4605-4606).
uint32_t addrspace_ty = addBuiltinValue(
&addrspace_gz, vd.addrspace_node, ZIR_BUILTIN_VALUE_ADDRESS_SPACE);
ResultLoc as_rl = { .tag = RL_COERCED_TY,
.data = addrspace_ty,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t as_inst = exprRl(
&addrspace_gz, &addrspace_gz.base, as_rl, vd.addrspace_node);
makeBreakInline(&addrspace_gz, decl_inst, as_inst, 0); makeBreakInline(&addrspace_gz, decl_inst, as_inst, 0);
} }
uint32_t addrspace_top = ag->scratch_inst_len; uint32_t addrspace_top = ag->scratch_inst_len;
// Value sub-block (AstGen.zig:4610-4620). // Value sub-block (AstGen.zig:4610-4621).
GenZir value_gz; GenZir value_gz;
memset(&value_gz, 0, sizeof(value_gz)); memset(&value_gz, 0, sizeof(value_gz));
value_gz.base.tag = SCOPE_GEN_ZIR; value_gz.base.tag = SCOPE_GEN_ZIR;
@@ -9635,7 +9741,23 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
value_gz.any_defer_node = UINT32_MAX; value_gz.any_defer_node = UINT32_MAX;
if (vd.init_node != UINT32_MAX && vd.init_node != 0) { if (vd.init_node != UINT32_MAX && vd.init_node != 0) {
uint32_t init_ref = expr(&value_gz, &value_gz.base, vd.init_node); // Upstream: coerced_ty = decl_inst.toRef() when type_node present
// (AstGen.zig:4614-4616).
ResultLoc init_rl;
memset(&init_rl, 0, sizeof(init_rl));
if (vd.type_node != 0) {
init_rl.tag = RL_COERCED_TY;
init_rl.data = decl_inst + ZIR_REF_START_INDEX;
} else {
init_rl.tag = RL_NONE;
}
// nameStratExpr: check if init is container decl (AstGen.zig:4617).
uint32_t init_ref;
if (!nameStratExpr(&value_gz, &value_gz.base, init_rl, vd.init_node,
0 /* parent */, &init_ref)) {
init_ref
= exprRl(&value_gz, &value_gz.base, init_rl, vd.init_node);
}
makeBreakInline(&value_gz, decl_inst, init_ref, 0); makeBreakInline(&value_gz, decl_inst, init_ref, 0);
} }
@@ -9666,14 +9788,6 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
vd.is_extern, vd.is_export, vd.is_threadlocal, has_type_body, vd.is_extern, vd.is_export, vd.is_threadlocal, has_type_body,
has_special_body, has_lib_name); has_special_body, has_lib_name);
// Compute lib_name string index.
uint32_t lib_name = UINT32_MAX;
if (has_lib_name) {
uint32_t li, ll;
strLitAsString(ag, vd.lib_name_token, &li, &ll);
lib_name = li;
}
setDeclaration(ag, decl_inst, setDeclaration(ag, decl_inst,
(SetDeclArgs) { .src_line = ag->source_line, (SetDeclArgs) { .src_line = ag->source_line,
.src_column = decl_column, .src_column = decl_column,
@@ -10011,7 +10125,8 @@ static void wipMembersBodiesAppendWithFixups(
// --- containerDecl (AstGen.zig:5468) --- // --- containerDecl (AstGen.zig:5468) ---
// Handles container declarations as expressions (struct{}, enum{}, etc.). // Handles container declarations as expressions (struct{}, enum{}, etc.).
static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node) { static uint32_t containerDecl(
GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy) {
AstGenCtx* ag = gz->astgen; AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
AstNodeTag tag = tree->nodes.tags[node]; AstNodeTag tag = tree->nodes.tags[node];
@@ -10085,15 +10200,17 @@ static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node) {
uint32_t decl_inst; uint32_t decl_inst;
switch (kw_tag) { switch (kw_tag) {
case TOKEN_KEYWORD_STRUCT: case TOKEN_KEYWORD_STRUCT:
decl_inst = structDeclInner(ag, gz, node, members, members_len); decl_inst = structDeclInner(
ag, gz, node, members, members_len, name_strategy);
break; break;
case TOKEN_KEYWORD_ENUM: case TOKEN_KEYWORD_ENUM:
decl_inst decl_inst = enumDeclInner(
= enumDeclInner(ag, gz, node, members, members_len, arg_node); ag, gz, node, members, members_len, arg_node, name_strategy);
break; break;
default: default:
// union/opaque: fall back to struct for now. // union/opaque: fall back to struct for now.
decl_inst = structDeclInner(ag, gz, node, members, members_len); decl_inst = structDeclInner(
ag, gz, node, members, members_len, name_strategy);
break; break;
} }
(void)scope; (void)scope;
@@ -10201,7 +10318,8 @@ static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token) {
// arg_node: the tag type expression node (e.g. u8 in enum(u8)), 0 if none. // arg_node: the tag type expression node (e.g. u8 in enum(u8)), 0 if none.
static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
const uint32_t* members, uint32_t members_len, uint32_t arg_node) { const uint32_t* members, uint32_t members_len, uint32_t arg_node,
uint8_t name_strategy) {
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// --- First pass: count fields, values, decls, detect nonexhaustive --- // --- First pass: count fields, values, decls, detect nonexhaustive ---
@@ -10334,7 +10452,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// setEnum (AstGen.zig:5705-5715). // setEnum (AstGen.zig:5705-5715).
setEnum(ag, decl_inst, node, arg_inst, 0 /* captures_len */, body_len, setEnum(ag, decl_inst, node, arg_inst, 0 /* captures_len */, body_len,
total_fields, decl_count, nonexhaustive, 0 /* name_strategy */); total_fields, decl_count, nonexhaustive, name_strategy);
wipMembersFinishBitsEnum(&wm); wipMembersFinishBitsEnum(&wm);
@@ -10363,7 +10481,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// --- structDeclInner (AstGen.zig:4926) --- // --- structDeclInner (AstGen.zig:4926) ---
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
const uint32_t* members, uint32_t members_len) { const uint32_t* members, uint32_t members_len, uint8_t name_strategy) {
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
uint32_t decl_inst = reserveInstructionIndex(ag); uint32_t decl_inst = reserveInstructionIndex(ag);
gzAppendInstruction(gz, decl_inst); gzAppendInstruction(gz, decl_inst);
@@ -10372,6 +10490,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
if (members_len == 0) { if (members_len == 0) {
StructDeclSmall small; StructDeclSmall small;
memset(&small, 0, sizeof(small)); memset(&small, 0, sizeof(small));
small.name_strategy = name_strategy;
setStruct(ag, decl_inst, node, small, 0, 0, 0); setStruct(ag, decl_inst, node, small, 0, 0, 0);
return decl_inst; return decl_inst;
} }
@@ -10570,6 +10689,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
small.any_comptime_fields = any_comptime_fields; small.any_comptime_fields = any_comptime_fields;
small.any_default_inits = any_default_inits; small.any_default_inits = any_default_inits;
small.any_aligned_fields = any_aligned_fields; small.any_aligned_fields = any_aligned_fields;
small.name_strategy = name_strategy;
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count); setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
// Append: captures (none), backing_int (none), decls, fields, bodies // Append: captures (none), backing_int (none), decls, fields, bodies
@@ -11853,7 +11973,7 @@ Zir astGen(const Ast* ast) {
const uint32_t* members = ast->extra_data.arr + members_start; const uint32_t* members = ast->extra_data.arr + members_start;
uint32_t members_len = members_end - members_start; uint32_t members_len = members_end - members_start;
structDeclInner(&ag, &gen_scope, 0, members, members_len); structDeclInner(&ag, &gen_scope, 0, members, members_len, 0 /* parent */);
// Write imports list (AstGen.zig:227-244). // Write imports list (AstGen.zig:227-244).
writeImports(&ag); writeImports(&ag);