diff --git a/stage0/astgen.c b/stage0/astgen.c index d01fdc6108..4ad7237e7a 100644 --- a/stage0/astgen.c +++ b/stage0/astgen.c @@ -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); diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig index 33b2dfd659..7c68ae82f8 100644 --- a/stage0/astgen_test.zig +++ b/stage0/astgen_test.zig @@ -853,7 +853,7 @@ test "astgen: corpus astgen_test.zig" { } test "astgen: corpus array_list.zig" { - if (true) return error.SkipZigTest; // TODO: identifier resolution across namespace scopes (fn params in returned struct) + if (true) return error.SkipZigTest; // TODO: missing assign_destructure handler const gpa = std.testing.allocator; try corpusCheck(gpa, @embedFile("../lib/std/array_list.zig")); }