astgen: fix globalVarDecl coercion, nameStratExpr, and error diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
188
astgen.c
188
astgen.c
@@ -2325,11 +2325,15 @@ static void blockExprStmts(
|
||||
GenZir* gz, Scope* scope, const uint32_t* statements, uint32_t stmt_count);
|
||||
static uint32_t fullBodyExpr(
|
||||
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,
|
||||
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,
|
||||
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(
|
||||
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.ctx = RI_CTX_RETURN;
|
||||
// TODO: nameStratExpr(gz, scope, ret_rl, operand_node, .func) when
|
||||
// containerDecl supports name_strategy parameter.
|
||||
uint32_t operand = reachableExpr(gz, scope, ret_rl, operand_node, node);
|
||||
// nameStratExpr with .func name strategy (AstGen.zig:8185).
|
||||
uint32_t operand;
|
||||
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
|
||||
// (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_ENUM_TAG:
|
||||
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).
|
||||
case AST_NODE_TRY:
|
||||
return tryExpr(gz, scope, rl, node);
|
||||
@@ -9534,12 +9542,69 @@ static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub,
|
||||
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,
|
||||
uint32_t* decl_idx, uint32_t node) {
|
||||
const Ast* tree = ag->tree;
|
||||
VarDeclInfo vd = extractVarDecl(tree, node);
|
||||
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(ag, node);
|
||||
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;
|
||||
(*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).
|
||||
GenZir 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.
|
||||
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;
|
||||
memset(&align_gz, 0, sizeof(align_gz));
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
memset(&linksection_gz, 0, sizeof(linksection_gz));
|
||||
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;
|
||||
|
||||
if (vd.section_node != 0) {
|
||||
uint32_t ls_inst
|
||||
= expr(&linksection_gz, &linksection_gz.base, vd.section_node);
|
||||
// coerced_linksection_ri = { .rl = .{ .coerced_ty =
|
||||
// .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);
|
||||
}
|
||||
|
||||
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;
|
||||
memset(&addrspace_gz, 0, sizeof(addrspace_gz));
|
||||
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;
|
||||
|
||||
if (vd.addrspace_node != 0) {
|
||||
uint32_t as_inst
|
||||
= expr(&addrspace_gz, &addrspace_gz.base, vd.addrspace_node);
|
||||
// Upstream: addBuiltinValue(addrspace_node, .address_space) then
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
memset(&value_gz, 0, sizeof(value_gz));
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
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,
|
||||
(SetDeclArgs) { .src_line = ag->source_line,
|
||||
.src_column = decl_column,
|
||||
@@ -10011,7 +10125,8 @@ static void wipMembersBodiesAppendWithFixups(
|
||||
// --- containerDecl (AstGen.zig:5468) ---
|
||||
// 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;
|
||||
const Ast* tree = ag->tree;
|
||||
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;
|
||||
switch (kw_tag) {
|
||||
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;
|
||||
case TOKEN_KEYWORD_ENUM:
|
||||
decl_inst
|
||||
= enumDeclInner(ag, gz, node, members, members_len, arg_node);
|
||||
decl_inst = enumDeclInner(
|
||||
ag, gz, node, members, members_len, arg_node, name_strategy);
|
||||
break;
|
||||
default:
|
||||
// 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;
|
||||
}
|
||||
(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.
|
||||
|
||||
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;
|
||||
|
||||
// --- 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(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);
|
||||
|
||||
@@ -10363,7 +10481,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
// --- structDeclInner (AstGen.zig:4926) ---
|
||||
|
||||
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;
|
||||
uint32_t decl_inst = reserveInstructionIndex(ag);
|
||||
gzAppendInstruction(gz, decl_inst);
|
||||
@@ -10372,6 +10490,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
|
||||
if (members_len == 0) {
|
||||
StructDeclSmall small;
|
||||
memset(&small, 0, sizeof(small));
|
||||
small.name_strategy = name_strategy;
|
||||
setStruct(ag, decl_inst, node, small, 0, 0, 0);
|
||||
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_default_inits = any_default_inits;
|
||||
small.any_aligned_fields = any_aligned_fields;
|
||||
small.name_strategy = name_strategy;
|
||||
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
|
||||
|
||||
// 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;
|
||||
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).
|
||||
writeImports(&ag);
|
||||
|
||||
Reference in New Issue
Block a user