astgen: implement namespace scopes, identifier resolution across scope boundaries

Add ScopeNamespace struct with per-namespace declaration tables and
capture storage, replacing the flat decl_table on AstGenCtx. Implement
tunnelThroughClosure for cross-namespace captures (closure_get ZIR
instruction). Modify identifierExpr to walk past namespace scopes,
checking namespace decls and tracking num_namespaces_out for proper
closure tunneling.

Key changes:
- ScopeNamespace with decl_names/decl_nodes, capture_keys/capture_vals
- scanContainer populates per-namespace decls instead of flat table
- structDeclInner/enumDeclInner create namespace scopes, write captures
- globalVarDecl/fnDecl/testDecl/comptimeDecl receive scope parameter
- localVarRef properly tunnels through namespace boundaries
- scopeParent helper for generic scope chain walking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 12:51:38 +00:00
parent 285935bd41
commit a263259b1e
2 changed files with 451 additions and 125 deletions

View File

@@ -79,12 +79,6 @@ typedef struct {
ImportEntry* imports;
uint32_t imports_len;
uint32_t imports_cap;
// Namespace decl table: maps string indices to node indices.
// Populated by scanContainer, used by identifier resolution.
uint32_t* decl_names; // string indices
uint32_t* decl_nodes; // node indices
uint32_t decl_table_len;
uint32_t decl_table_cap;
// Shared dynamic array for GenZir instructions (AstGen.zig:11796).
// Sub-blocks share this array and track their slice via
// instructions_top.
@@ -304,6 +298,126 @@ typedef struct {
uint32_t block_inst; // instruction index (not ref)
} ScopeLabel;
// Scope.Namespace (AstGen.zig:11737-11762) — represents a type declaration
// scope (struct, enum, union, opaque) that has declarations in it.
typedef struct {
Scope base; // tag = SCOPE_NAMESPACE
Scope* parent;
uint32_t node; // AST node of the container decl
uint32_t inst; // instruction index of the container decl
GenZir* declaring_gz; // the GenZir containing this namespace
bool maybe_generic; // true if inside a function (astgen.within_fn)
// Per-namespace declaration table (maps name string index → node index).
uint32_t* decl_names;
uint32_t* decl_nodes;
uint32_t decl_len;
uint32_t decl_cap;
// Captures (populated by tunnelThroughClosure).
// Keys are packed Capture u32 values, values are NullTerminatedString.
uint32_t* capture_keys;
uint32_t* capture_vals;
uint32_t captures_len;
uint32_t captures_cap;
} ScopeNamespace;
// Initialize a ScopeNamespace on the stack.
static void scopeNamespaceInit(ScopeNamespace* ns, Scope* parent,
uint32_t node, uint32_t inst, GenZir* declaring_gz, bool maybe_generic) {
memset(ns, 0, sizeof(*ns));
ns->base.tag = SCOPE_NAMESPACE;
ns->parent = parent;
ns->node = node;
ns->inst = inst;
ns->declaring_gz = declaring_gz;
ns->maybe_generic = maybe_generic;
}
// Free dynamic arrays in a ScopeNamespace.
static void scopeNamespaceDeinit(ScopeNamespace* ns) {
free(ns->decl_names);
free(ns->decl_nodes);
free(ns->capture_keys);
free(ns->capture_vals);
}
// Add a declaration to a namespace's decl table.
static void scopeNamespaceAddDecl(
ScopeNamespace* ns, uint32_t name_str, uint32_t decl_node) {
if (ns->decl_len >= ns->decl_cap) {
uint32_t new_cap = ns->decl_cap > 0 ? ns->decl_cap * 2 : 8;
uint32_t* n = realloc(ns->decl_names, new_cap * sizeof(uint32_t));
uint32_t* d = realloc(ns->decl_nodes, new_cap * sizeof(uint32_t));
if (!n || !d)
exit(1);
ns->decl_names = n;
ns->decl_nodes = d;
ns->decl_cap = new_cap;
}
ns->decl_names[ns->decl_len] = name_str;
ns->decl_nodes[ns->decl_len] = decl_node;
ns->decl_len++;
}
// Look up a name in a namespace's decl table. Returns the node index,
// or UINT32_MAX if not found.
static uint32_t scopeNamespaceFindDecl(
const ScopeNamespace* ns, uint32_t name_str) {
for (uint32_t i = 0; i < ns->decl_len; i++) {
if (ns->decl_names[i] == name_str)
return ns->decl_nodes[i];
}
return UINT32_MAX;
}
// Add a capture to a namespace. Returns the capture index (position).
// If the capture already exists, returns the existing index.
// key is a packed Capture u32 (3-bit tag | 29-bit data).
static uint32_t scopeNamespaceAddCapture(
ScopeNamespace* ns, uint32_t key, uint32_t name_str) {
// Check for existing capture with same key.
for (uint32_t i = 0; i < ns->captures_len; i++) {
if (ns->capture_keys[i] == key)
return i;
}
if (ns->captures_len >= ns->captures_cap) {
uint32_t new_cap = ns->captures_cap > 0 ? ns->captures_cap * 2 : 4;
uint32_t* k = realloc(ns->capture_keys, new_cap * sizeof(uint32_t));
uint32_t* v = realloc(ns->capture_vals, new_cap * sizeof(uint32_t));
if (!k || !v)
exit(1);
ns->capture_keys = k;
ns->capture_vals = v;
ns->captures_cap = new_cap;
}
uint32_t idx = ns->captures_len;
ns->capture_keys[idx] = key;
ns->capture_vals[idx] = name_str;
ns->captures_len++;
return idx;
}
// Walk to a scope's parent. Returns NULL if there is no parent.
static Scope* scopeParent(Scope* s) {
switch (s->tag) {
case SCOPE_GEN_ZIR:
return ((GenZir*)s)->parent;
case SCOPE_LOCAL_VAL:
return ((ScopeLocalVal*)s)->parent;
case SCOPE_LOCAL_PTR:
return ((ScopeLocalPtr*)s)->parent;
case SCOPE_DEFER_NORMAL:
case SCOPE_DEFER_ERROR:
return ((ScopeDefer*)s)->parent;
case SCOPE_NAMESPACE:
return ((ScopeNamespace*)s)->parent;
case SCOPE_LABEL:
return ((ScopeLabel*)s)->parent;
case SCOPE_TOP:
return NULL;
}
return NULL;
}
// --- GenZir instruction helpers (AstGen.zig:11830-11850) ---
// Returns the number of instructions in this scope.
@@ -612,6 +726,25 @@ static uint32_t addNodeExtended(
return idx + ZIR_REF_START_INDEX;
}
// Mirrors GenZir.addExtendedNodeSmall (AstGen.zig:12479-12499).
// Creates an extended instruction with operand = node offset and custom small.
static uint32_t addNodeExtendedSmall(
GenZir* gz, uint16_t opcode, uint32_t src_node, uint16_t small) {
AstGenCtx* ag = gz->astgen;
ensureInstCapacity(ag, 1);
uint32_t idx = ag->inst_len;
ag->inst_tags[idx] = ZIR_INST_EXTENDED;
ZirInstData data;
data.extended.opcode = opcode;
data.extended.small = small;
data.extended.operand
= (uint32_t)((int32_t)src_node - (int32_t)gz->decl_node_index);
ag->inst_datas[idx] = data;
ag->inst_len++;
gzAppendInstruction(gz, idx);
return idx + ZIR_REF_START_INDEX;
}
// Mirrors GenZir.addExtendedPayload (AstGen.zig:12781).
// Creates an extended instruction with given payload_index and small=0.
static uint32_t addExtendedPayload(
@@ -1873,28 +2006,10 @@ static void setStruct(AstGenCtx* ag, uint32_t inst, uint32_t src_node,
// --- scanContainer (AstGen.zig:13384) ---
// Add a name→node entry to the decl table.
static void addDeclToTable(
AstGenCtx* ag, uint32_t name_str_index, uint32_t node) {
if (ag->decl_table_len >= ag->decl_table_cap) {
uint32_t new_cap = ag->decl_table_cap > 0 ? ag->decl_table_cap * 2 : 8;
uint32_t* n = realloc(ag->decl_names, new_cap * sizeof(uint32_t));
uint32_t* d = realloc(ag->decl_nodes, new_cap * sizeof(uint32_t));
if (!n || !d)
exit(1);
ag->decl_names = n;
ag->decl_nodes = d;
ag->decl_table_cap = new_cap;
}
ag->decl_names[ag->decl_table_len] = name_str_index;
ag->decl_nodes[ag->decl_table_len] = node;
ag->decl_table_len++;
}
// Mirrors scanContainer (AstGen.zig:13384).
// Also populates the decl table (namespace.decls) for identifier resolution.
static uint32_t scanContainer(
AstGenCtx* ag, const uint32_t* members, uint32_t member_count) {
// Populates the namespace's decl table for identifier resolution.
static uint32_t scanContainer(AstGenCtx* ag, ScopeNamespace* ns,
const uint32_t* members, uint32_t member_count) {
const Ast* tree = ag->tree;
uint32_t decl_count = 0;
for (uint32_t i = 0; i < member_count; i++) {
@@ -1908,7 +2023,7 @@ static uint32_t scanContainer(
decl_count++;
uint32_t name_token = tree->nodes.main_tokens[member] + 1;
uint32_t name_str = identAsString(ag, name_token);
addDeclToTable(ag, name_str, member);
scopeNamespaceAddDecl(ns, name_str, member);
break;
}
case AST_NODE_FN_PROTO_SIMPLE:
@@ -1919,7 +2034,7 @@ static uint32_t scanContainer(
decl_count++;
uint32_t name_token = tree->nodes.main_tokens[member] + 1;
uint32_t name_str = identAsString(ag, name_token);
addDeclToTable(ag, name_str, member);
scopeNamespaceAddDecl(ns, name_str, member);
break;
}
// Container fields: add field name to string table for ordering
@@ -3525,6 +3640,234 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node) {
return ZIR_REF_NONE;
}
// Capture tag values for packed Capture u32 (Zir.zig:3391-3435).
#define CAPTURE_TAG_NESTED 0
#define CAPTURE_TAG_INSTRUCTION 1
#define CAPTURE_TAG_INSTRUCTION_LOAD 2
#define CAPTURE_TAG_DECL_VAL 3
#define CAPTURE_TAG_DECL_REF 4
static uint32_t packCapture(uint32_t tag, uint32_t data) {
return (tag & 0x7u) | (data << 3);
}
// Mirrors tunnelThroughClosure (AstGen.zig:8526-8624).
// Access a ZIR instruction/decl through closure. May tunnel through
// arbitrarily many namespaces, adding closure captures as required.
// Returns the ref of the closure_get instruction added to gz.
//
// capture_tag: one of CAPTURE_TAG_* constants.
// capture_data: the instruction index or NullTerminatedString index.
static uint32_t tunnelThroughClosure(GenZir* gz, uint32_t inner_ref_node,
uint32_t num_tunnels, uint32_t capture_tag, uint32_t capture_data,
uint32_t name_str_index) {
// For trivial refs (instruction tag with data mapping to a non-index ref),
// no tunnel is needed. In the upstream, this checks if
// ref.toIndex()==null. A ref with index < ZIR_REF_START_INDEX is
// non-indexed (e.g. void, true).
if (capture_tag == CAPTURE_TAG_INSTRUCTION
&& capture_data + ZIR_REF_START_INDEX < ZIR_REF_START_INDEX) {
return capture_data + ZIR_REF_START_INDEX;
}
// Walk gz->parent to find the namespace scopes we're tunneling through.
// The root namespace is the outermost (first found when counting
// num_tunnels-1 intermediate tunnels from the inside).
// Allocate on the stack for typical small counts.
ScopeNamespace* intermediates[16];
ScopeNamespace** inter = intermediates;
ScopeNamespace** inter_heap = NULL;
if (num_tunnels > 17) {
inter_heap = malloc((num_tunnels - 1) * sizeof(ScopeNamespace*));
if (!inter_heap)
exit(1);
inter = inter_heap;
}
// Find the root namespace and intermediate tunnels (AstGen.zig:8568-8582).
ScopeNamespace* root_ns = NULL;
{
uint32_t remaining = num_tunnels - 1;
Scope* s = gz->parent;
while (s != NULL && remaining > 0) {
if (s->tag == SCOPE_NAMESPACE) {
remaining--;
inter[remaining] = (ScopeNamespace*)s;
}
s = scopeParent(s);
}
// Find the root namespace.
while (s != NULL) {
if (s->tag == SCOPE_NAMESPACE) {
root_ns = (ScopeNamespace*)s;
break;
}
s = scopeParent(s);
}
}
// root_ns must have been found — we are tunneling through at least one
// namespace, so there must be a root namespace in the scope chain.
if (root_ns == NULL) {
free(inter_heap);
SET_ERROR(gz->astgen);
return ZIR_REF_VOID_VALUE;
}
// Add the root capture (AstGen.zig:8584-8594).
uint32_t root_capture = packCapture(capture_tag, capture_data);
uint32_t cur_capture_index
= scopeNamespaceAddCapture(root_ns, root_capture, name_str_index);
// Chain through intermediate namespaces (AstGen.zig:8596-8616).
for (uint32_t i = 0; i < num_tunnels - 1; i++) {
uint32_t nested_capture
= packCapture(CAPTURE_TAG_NESTED, cur_capture_index);
cur_capture_index = scopeNamespaceAddCapture(
inter[i], nested_capture, name_str_index);
}
free(inter_heap);
// Add closure_get instruction (AstGen.zig:8622-8623).
return addNodeExtendedSmall(gz, (uint16_t)ZIR_EXT_CLOSURE_GET,
inner_ref_node, (uint16_t)cur_capture_index);
}
// Mirrors localVarRef (AstGen.zig:8367-8521).
static uint32_t localVarRef(GenZir* gz, Scope* scope, ResultLoc rl,
uint32_t node, uint32_t ident_token, uint32_t name_str) {
AstGenCtx* ag = gz->astgen;
uint32_t found_already = UINT32_MAX; // node index if found
bool found_needs_tunnel = false;
uint32_t found_namespaces_out = 0;
uint32_t num_namespaces_out = 0;
ScopeNamespace* capturing_namespace = NULL;
for (Scope* s = scope; s != NULL;) {
switch (s->tag) {
case SCOPE_LOCAL_VAL: {
ScopeLocalVal* lv = (ScopeLocalVal*)s;
if (lv->name == name_str) {
// Locals cannot shadow, no ambiguity check needed.
uint32_t value_inst;
if (num_namespaces_out != 0) {
value_inst = tunnelThroughClosure(gz, node,
num_namespaces_out, CAPTURE_TAG_INSTRUCTION,
lv->inst - ZIR_REF_START_INDEX, name_str);
} else {
value_inst = lv->inst;
}
return rvalueNoCoercePreRef(gz, rl, value_inst, node);
}
s = lv->parent;
continue;
}
case SCOPE_LOCAL_PTR: {
ScopeLocalPtr* lp = (ScopeLocalPtr*)s;
if (lp->name == name_str) {
// Can't close over a runtime variable
// (AstGen.zig:8424-8432).
if (num_namespaces_out != 0 && !lp->maybe_comptime
&& !gz->is_typeof) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
if (RL_IS_REF(rl)) {
uint32_t ptr_inst;
if (num_namespaces_out != 0) {
ptr_inst = tunnelThroughClosure(gz, node,
num_namespaces_out, CAPTURE_TAG_INSTRUCTION,
lp->ptr - ZIR_REF_START_INDEX, name_str);
} else {
ptr_inst = lp->ptr;
}
return ptr_inst;
} else {
uint32_t val_inst;
if (num_namespaces_out != 0) {
val_inst = tunnelThroughClosure(gz, node,
num_namespaces_out, CAPTURE_TAG_INSTRUCTION_LOAD,
lp->ptr - ZIR_REF_START_INDEX, name_str);
} else {
val_inst = addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
}
return rvalueNoCoercePreRef(gz, rl, val_inst, node);
}
}
s = lp->parent;
continue;
}
case SCOPE_GEN_ZIR: {
s = ((GenZir*)s)->parent;
continue;
}
case SCOPE_DEFER_NORMAL:
case SCOPE_DEFER_ERROR: {
s = ((ScopeDefer*)s)->parent;
continue;
}
case SCOPE_LABEL: {
s = ((ScopeLabel*)s)->parent;
continue;
}
case SCOPE_NAMESPACE: {
// Check namespace decls, then continue walking
// (AstGen.zig:8455-8472).
ScopeNamespace* ns = (ScopeNamespace*)s;
uint32_t decl_node = scopeNamespaceFindDecl(ns, name_str);
if (decl_node != UINT32_MAX) {
if (found_already != UINT32_MAX) {
// Ambiguous reference (AstGen.zig:8458-8462).
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
found_already = decl_node;
found_needs_tunnel = ns->maybe_generic;
found_namespaces_out = num_namespaces_out;
}
num_namespaces_out++;
capturing_namespace = ns;
s = ns->parent;
continue;
}
case SCOPE_TOP:
goto done_walk;
}
}
done_walk:
(void)capturing_namespace;
if (found_already == UINT32_MAX) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
// Decl references (AstGen.zig:8484-8520).
if (found_namespaces_out > 0 && found_needs_tunnel) {
if (RL_IS_REF(rl)) {
return tunnelThroughClosure(gz, node, found_namespaces_out,
CAPTURE_TAG_DECL_REF, name_str, name_str);
} else {
uint32_t result
= tunnelThroughClosure(gz, node, found_namespaces_out,
CAPTURE_TAG_DECL_VAL, name_str, name_str);
return rvalueNoCoercePreRef(gz, rl, result, node);
}
}
// Simple decl reference (AstGen.zig:8512-8520).
ZirInstData data;
data.str_tok.start = name_str;
data.str_tok.src_tok = tokenIndexToRelative(gz, ident_token);
if (RL_IS_REF(rl)) {
return addInstruction(gz, ZIR_INST_DECL_REF, data);
} else {
uint32_t result = addInstruction(gz, ZIR_INST_DECL_VAL, data);
return rvalueNoCoercePreRef(gz, rl, result, node);
}
}
static uint32_t identifierExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
AstGenCtx* ag = gz->astgen;
@@ -3535,68 +3878,10 @@ static uint32_t identifierExpr(
if (prim != ZIR_REF_NONE)
return rvalue(gz, rl, prim, node);
// Scope chain walk (AstGen.zig:8340-8461).
uint32_t name_str = identAsString(ag, ident_token);
for (Scope* s = scope; s != NULL;) {
switch (s->tag) {
case SCOPE_LOCAL_VAL: {
ScopeLocalVal* lv = (ScopeLocalVal*)s;
if (lv->name == name_str)
return rvalueNoCoercePreRef(gz, rl, lv->inst, node);
s = lv->parent;
continue;
}
case SCOPE_LOCAL_PTR: {
ScopeLocalPtr* lp = (ScopeLocalPtr*)s;
if (lp->name == name_str) {
if (RL_IS_REF(rl))
return lp->ptr;
uint32_t val = addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
return rvalueNoCoercePreRef(gz, rl, val, node);
}
s = lp->parent;
continue;
}
case SCOPE_GEN_ZIR: {
GenZir* gzs = (GenZir*)s;
s = gzs->parent;
continue;
}
case SCOPE_DEFER_NORMAL:
case SCOPE_DEFER_ERROR: {
ScopeDefer* sd = (ScopeDefer*)s;
s = sd->parent;
continue;
}
case SCOPE_LABEL: {
ScopeLabel* sl = (ScopeLabel*)s;
s = sl->parent;
continue;
}
case SCOPE_NAMESPACE:
case SCOPE_TOP:
goto decl_table;
}
}
decl_table:
// Decl table lookup (AstGen.zig:8462-8520).
for (uint32_t i = 0; i < ag->decl_table_len; i++) {
if (ag->decl_names[i] == name_str) {
ZirInstData data;
data.str_tok.start = name_str;
data.str_tok.src_tok = tokenIndexToRelative(gz, ident_token);
if (RL_IS_REF(rl)) {
return addInstruction(gz, ZIR_INST_DECL_REF, data);
} else {
uint32_t result = addInstruction(gz, ZIR_INST_DECL_VAL, data);
return rvalueNoCoercePreRef(gz, rl, result, node);
}
}
}
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
// Local variables and container-level declarations
// (AstGen.zig:8340-8365).
return localVarRef(
gz, scope, rl, node, ident_token, identAsString(ag, ident_token));
}
// --- fieldAccess (AstGen.zig:6154) ---
@@ -10598,8 +10883,8 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
// --- testDecl (AstGen.zig:4708) ---
static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
uint32_t* decl_idx, uint32_t node) {
static void testDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
const Ast* tree = ag->tree;
AstData nd = tree->nodes.datas[node];
uint32_t body_node = nd.rhs;
@@ -10640,7 +10925,7 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir decl_block;
memset(&decl_block, 0, sizeof(decl_block));
decl_block.base.tag = SCOPE_GEN_ZIR;
decl_block.parent = NULL;
decl_block.parent = scope;
decl_block.astgen = ag;
decl_block.decl_node_index = node;
decl_block.decl_line = decl_line;
@@ -10739,8 +11024,8 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
// Handles function declarations with bodies (fn_decl) and
// function prototypes without bodies (fn_proto*).
static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
uint32_t* decl_idx, uint32_t node) {
static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
const Ast* tree = ag->tree;
AstNodeTag node_tag = tree->nodes.tags[node];
AstData nd = tree->nodes.datas[node];
@@ -10873,7 +11158,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir decl_gz;
memset(&decl_gz, 0, sizeof(decl_gz));
decl_gz.base.tag = SCOPE_GEN_ZIR;
decl_gz.parent = NULL;
decl_gz.parent = scope;
decl_gz.astgen = ag;
decl_gz.decl_node_index = proto_node;
decl_gz.decl_line = decl_line;
@@ -11321,8 +11606,8 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
// --- comptimeDecl (AstGen.zig:4645) ---
static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
uint32_t* decl_idx, uint32_t node) {
static void comptimeDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) {
// makeDeclaration before advanceSourceCursorToNode (AstGen.zig:4663-4665).
uint32_t decl_inst = makeDeclaration(ag, node);
wip_decl_insts[*decl_idx] = decl_inst;
@@ -11337,7 +11622,7 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir value_gz;
memset(&value_gz, 0, sizeof(value_gz));
value_gz.base.tag = SCOPE_GEN_ZIR;
value_gz.parent = NULL;
value_gz.parent = scope;
value_gz.astgen = ag;
value_gz.decl_node_index = node;
value_gz.decl_line = decl_line;
@@ -11545,8 +11830,8 @@ static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
}
}
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
uint32_t* decl_idx, uint32_t node) {
static void globalVarDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
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;
@@ -11607,6 +11892,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir type_gz;
memset(&type_gz, 0, sizeof(type_gz));
type_gz.base.tag = SCOPE_GEN_ZIR;
type_gz.parent = scope;
type_gz.astgen = ag;
type_gz.decl_node_index = node;
type_gz.instructions_top = ag->scratch_inst_len;
@@ -11626,6 +11912,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir align_gz;
memset(&align_gz, 0, sizeof(align_gz));
align_gz.base.tag = SCOPE_GEN_ZIR;
align_gz.parent = scope;
align_gz.astgen = ag;
align_gz.decl_node_index = node;
align_gz.instructions_top = type_top;
@@ -11651,6 +11938,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir linksection_gz;
memset(&linksection_gz, 0, sizeof(linksection_gz));
linksection_gz.base.tag = SCOPE_GEN_ZIR;
linksection_gz.parent = scope;
linksection_gz.astgen = ag;
linksection_gz.decl_node_index = node;
linksection_gz.instructions_top = align_top;
@@ -11676,6 +11964,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir addrspace_gz;
memset(&addrspace_gz, 0, sizeof(addrspace_gz));
addrspace_gz.base.tag = SCOPE_GEN_ZIR;
addrspace_gz.parent = scope;
addrspace_gz.astgen = ag;
addrspace_gz.decl_node_index = node;
addrspace_gz.instructions_top = linksection_top;
@@ -11703,6 +11992,7 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
GenZir value_gz;
memset(&value_gz, 0, sizeof(value_gz));
value_gz.base.tag = SCOPE_GEN_ZIR;
value_gz.parent = scope;
value_gz.astgen = ag;
value_gz.decl_node_index = node;
value_gz.instructions_top = addrspace_top;
@@ -12334,16 +12624,21 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
uint32_t decl_inst = reserveInstructionIndex(ag);
gzAppendInstruction(gz, decl_inst);
// Create namespace scope (AstGen.zig:5618-5623).
ScopeNamespace namespace;
scopeNamespaceInit(
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node);
// scanContainer to register names in string table (AstGen.zig:5635).
scanContainer(ag, members, members_len);
scanContainer(ag, &namespace, members, members_len);
// Set up block_scope for tag value expressions (AstGen.zig:5624-5632).
GenZir block_scope;
memset(&block_scope, 0, sizeof(block_scope));
block_scope.base.tag = SCOPE_GEN_ZIR;
block_scope.parent = NULL;
block_scope.parent = &namespace.base;
block_scope.astgen = ag;
block_scope.decl_node_index = node;
block_scope.decl_line = ag->source_line;
@@ -12368,19 +12663,23 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
AstNodeTag mtag = tree->nodes.tags[member_node];
switch (mtag) {
case AST_NODE_COMPTIME:
comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
comptimeDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_SIMPLE_VAR_DECL:
case AST_NODE_GLOBAL_VAR_DECL:
case AST_NODE_LOCAL_VAR_DECL:
case AST_NODE_ALIGNED_VAR_DECL:
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_FN_DECL:
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_TEST_DECL:
testDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
testDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_CONTAINER_FIELD_INIT:
case AST_NODE_CONTAINER_FIELD_ALIGN:
@@ -12432,19 +12731,26 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len);
// setEnum (AstGen.zig:5705-5715).
setEnum(ag, decl_inst, node, arg_inst, 0 /* captures_len */, body_len,
setEnum(ag, decl_inst, node, arg_inst, namespace.captures_len, body_len,
total_fields, decl_count, nonexhaustive, name_strategy);
wipMembersFinishBitsEnum(&wm);
// Append trailing data (AstGen.zig:5718-5725):
// captures (none), decls, body, fields.
// captures, decls, body, fields.
uint32_t decls_len_out;
const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len_out);
uint32_t fields_len_out;
const uint32_t* fields_slice = wipMembersFieldsSlice(&wm, &fields_len_out);
ensureExtraCapacity(ag, decls_len_out + body_len + fields_len_out);
ensureExtraCapacity(ag,
namespace.captures_len * 2 + decls_len_out + body_len
+ fields_len_out);
// Captures (AstGen.zig:5721-5722).
for (uint32_t i = 0; i < namespace.captures_len; i++)
ag->extra[ag->extra_len++] = namespace.capture_keys[i];
for (uint32_t i = 0; i < namespace.captures_len; i++)
ag->extra[ag->extra_len++] = namespace.capture_vals[i];
for (uint32_t i = 0; i < decls_len_out; i++)
ag->extra[ag->extra_len++] = decls_slice[i];
// Body instructions with fixups (AstGen.zig:5724).
@@ -12456,6 +12762,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
gzUnstack(&block_scope);
wipMembersDeinit(&wm);
scopeNamespaceDeinit(&namespace);
return decl_inst;
}
@@ -12669,9 +12976,15 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
}
// Non-empty container (AstGen.zig:4973-5189).
// Create namespace scope (AstGen.zig:4973-4979).
ScopeNamespace namespace;
scopeNamespaceInit(
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node);
uint32_t decl_count = scanContainer(ag, members, members_len);
uint32_t decl_count = scanContainer(ag, &namespace, members, members_len);
uint32_t field_count = members_len - decl_count;
WipMembers wm = wipMembersInit(decl_count, field_count);
@@ -12681,7 +12994,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
GenZir block_scope;
memset(&block_scope, 0, sizeof(block_scope));
block_scope.base.tag = SCOPE_GEN_ZIR;
block_scope.parent = NULL;
block_scope.parent = &namespace.base;
block_scope.astgen = ag;
block_scope.decl_node_index = node;
block_scope.decl_line = gz->decl_line; // Fix #7: use gz->decl_line
@@ -12730,29 +13043,35 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
AstNodeTag mtag = tree->nodes.tags[member_node];
switch (mtag) {
case AST_NODE_COMPTIME:
comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
comptimeDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_SIMPLE_VAR_DECL:
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_TEST_DECL:
testDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
testDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_FN_DECL:
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
// fn_proto* dispatch (AstGen.zig:5809-5813, issue #9).
case AST_NODE_FN_PROTO_SIMPLE:
case AST_NODE_FN_PROTO_MULTI:
case AST_NODE_FN_PROTO_ONE:
case AST_NODE_FN_PROTO:
fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
fnDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_USINGNAMESPACE:
case AST_NODE_GLOBAL_VAR_DECL:
case AST_NODE_LOCAL_VAR_DECL:
case AST_NODE_ALIGNED_VAR_DECL:
globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node);
globalVarDecl(ag, gz, &namespace.base, wm.payload, &wm.decl_index,
member_node);
break;
case AST_NODE_CONTAINER_FIELD_INIT:
case AST_NODE_CONTAINER_FIELD_ALIGN:
@@ -12929,6 +13248,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// setStruct (AstGen.zig:5152-5166).
StructDeclSmall small;
memset(&small, 0, sizeof(small));
small.has_captures_len = (namespace.captures_len > 0);
small.has_decls_len = (decl_count > 0);
small.has_fields_len = (field_count > 0);
small.has_backing_int = (backing_int_ref != ZIR_REF_NONE);
@@ -12939,9 +13259,10 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
small.any_aligned_fields = any_aligned_fields;
small.layout = layout;
small.name_strategy = name_strategy;
setStruct(ag, decl_inst, node, small, 0, field_count, decl_count);
setStruct(ag, decl_inst, node, small, namespace.captures_len, field_count,
decl_count);
// Append: captures (none), backing_int, decls, fields, bodies
// Append: captures, backing_int, decls, fields, bodies
// (AstGen.zig:5172-5186).
uint32_t decls_len;
const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len);
@@ -12955,8 +13276,14 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
ag, backing_int_body_raw, backing_int_body_raw_len);
}
ensureExtraCapacity(ag,
(backing_int_ref != ZIR_REF_NONE ? backing_int_body_len + 2 : 0)
namespace.captures_len * 2
+ (backing_int_ref != ZIR_REF_NONE ? backing_int_body_len + 2 : 0)
+ decls_len + fields_len + wm.bodies_len);
// Captures (AstGen.zig:5174-5175).
for (uint32_t i = 0; i < namespace.captures_len; i++)
ag->extra[ag->extra_len++] = namespace.capture_keys[i];
for (uint32_t i = 0; i < namespace.captures_len; i++)
ag->extra[ag->extra_len++] = namespace.capture_vals[i];
// backing_int (AstGen.zig:5176-5183).
if (backing_int_ref != ZIR_REF_NONE) {
ag->extra[ag->extra_len++] = backing_int_body_len;
@@ -12977,6 +13304,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
gzUnstack(&block_scope);
wipMembersDeinit(&wm);
scopeNamespaceDeinit(&namespace);
return decl_inst;
}
@@ -14254,8 +14582,6 @@ Zir astGen(const Ast* ast) {
zir.has_compile_errors = ag.has_compile_errors;
free(ag.imports);
free(ag.decl_names);
free(ag.decl_nodes);
free(ag.scratch_instructions);
free(ag.scratch_extra);
free(ag.ref_table_keys);