sema: add union/struct type resolution, resolve CallingConvention
Add resolveUnionDeclFromZir and resolveStructDeclFromZir to handle ZIR_EXT_UNION_DECL and ZIR_EXT_STRUCT_DECL in ensureNavValUpToDate. Union resolution creates: type_union, ptr_nav for the union nav, resolves inner declarations (creating type_struct + ptr_nav for each sub-type), then creates tag enum field values (int_u8) and the tag enum type for auto_enum_tag unions. Add CallingConvention to resolveBuiltinDeclTypes, creating IP entries $253-$348 (type_union, 5 struct types for CommonOptions etc., 83 int_u8 tag values, and tag enum). Also add resolved_type caching in ensureNavValUpToDate to prevent duplicate resolution of the same nav. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
194
stage0/sema.c
194
stage0/sema.c
@@ -2704,6 +2704,10 @@ static InternPoolIndex coerceIntToTagType(
|
||||
return ipIntern(s_module_ip, key);
|
||||
}
|
||||
|
||||
// Forward declarations for mutually recursive type resolvers.
|
||||
static InternPoolIndex ensureNavValUpToDate(uint32_t nav_idx);
|
||||
static InternPoolIndex internTypedInt(InternPoolIndex tag_type, uint64_t val);
|
||||
|
||||
// --- resolveEnumDeclFromZir ---
|
||||
// Parse an enum_decl extended ZIR instruction and create IP entries.
|
||||
// Creates: type_enum_* entry, int entries for field values, ptr_nav.
|
||||
@@ -2878,6 +2882,185 @@ static InternPoolIndex resolveEnumDeclFromZir(
|
||||
return enum_ip;
|
||||
}
|
||||
|
||||
// --- resolveStructDeclFromZir ---
|
||||
// Parse a struct_decl extended ZIR instruction and create IP entries.
|
||||
// Creates: type_struct IP entry, namespace, scanNamespace, ptr_nav.
|
||||
// Returns the IP index of the struct type, or IP_INDEX_NONE on failure.
|
||||
// Ported from Sema.zig zirStructDecl (minimal: type + namespace only).
|
||||
static InternPoolIndex resolveStructDeclFromZir(
|
||||
const Zir* zir, uint32_t struct_inst, uint32_t nav_idx) {
|
||||
if (zir->inst_tags[struct_inst] != ZIR_INST_EXTENDED)
|
||||
return IP_INDEX_NONE;
|
||||
if (zir->inst_datas[struct_inst].extended.opcode != ZIR_EXT_STRUCT_DECL)
|
||||
return IP_INDEX_NONE;
|
||||
|
||||
uint16_t small = zir->inst_datas[struct_inst].extended.small;
|
||||
uint32_t operand = zir->inst_datas[struct_inst].extended.operand;
|
||||
|
||||
// Skip 6 u32 header (fields_hash×4, src_line, src_node).
|
||||
uint32_t extra_index = operand + 6;
|
||||
|
||||
// Parse StructDecl.Small flags.
|
||||
bool has_captures_len = (small & (1 << 0)) != 0;
|
||||
bool has_fields_len = (small & (1 << 1)) != 0;
|
||||
bool has_decls_len = (small & (1 << 2)) != 0;
|
||||
|
||||
uint32_t captures_len = 0;
|
||||
if (has_captures_len) {
|
||||
captures_len = zir->extra[extra_index++];
|
||||
}
|
||||
if (has_fields_len) {
|
||||
extra_index++; // skip fields_len
|
||||
}
|
||||
uint32_t decls_len = 0;
|
||||
if (has_decls_len) {
|
||||
decls_len = zir->extra[extra_index++];
|
||||
}
|
||||
|
||||
extra_index += captures_len * 2; // skip captures
|
||||
|
||||
// Create type_struct IP entry.
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_STRUCT_TYPE;
|
||||
key.data.struct_type = s_next_struct_hash++;
|
||||
InternPoolIndex struct_ip = ipIntern(s_module_ip, key);
|
||||
|
||||
// Create namespace for the struct.
|
||||
const Nav* nav = ipGetNav(nav_idx);
|
||||
uint32_t ns_idx = createNamespace(
|
||||
struct_ip, s_namespaces[nav->namespace_idx].file_idx);
|
||||
|
||||
// Scan namespace declarations.
|
||||
const uint32_t* decl_insts = &zir->extra[extra_index];
|
||||
scanNamespaceC(ns_idx, decl_insts, decls_len, zir);
|
||||
|
||||
// Set the Nav's resolved type and create ptr_nav.
|
||||
{
|
||||
Nav* wnav = ipGetNav(nav_idx);
|
||||
wnav->resolved_type = struct_ip;
|
||||
InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE);
|
||||
(void)internNavPtr(ptr_type, nav_idx);
|
||||
}
|
||||
|
||||
return struct_ip;
|
||||
}
|
||||
|
||||
// --- resolveUnionDeclFromZir ---
|
||||
// Parse a union_decl extended ZIR instruction and create IP entries.
|
||||
// Creates: type_union IP entry, namespace, scanNamespace for declarations,
|
||||
// then resolves declarations (sub-types like CommonOptions).
|
||||
// For tagged unions, also creates the tag enum and field values.
|
||||
// Returns the IP index of the union type, or IP_INDEX_NONE on failure.
|
||||
// Ported from Sema.zig zirUnionDecl + resolveDeclaredUnionInner.
|
||||
static InternPoolIndex resolveUnionDeclFromZir(
|
||||
const Zir* zir, uint32_t union_inst, uint32_t nav_idx) {
|
||||
if (zir->inst_tags[union_inst] != ZIR_INST_EXTENDED)
|
||||
return IP_INDEX_NONE;
|
||||
if (zir->inst_datas[union_inst].extended.opcode != ZIR_EXT_UNION_DECL)
|
||||
return IP_INDEX_NONE;
|
||||
|
||||
uint16_t small = zir->inst_datas[union_inst].extended.small;
|
||||
uint32_t operand = zir->inst_datas[union_inst].extended.operand;
|
||||
|
||||
// Parse UnionDecl.Small flags.
|
||||
bool has_tag_type = (small & (1 << 0)) != 0;
|
||||
bool has_captures_len = (small & (1 << 1)) != 0;
|
||||
bool has_body_len = (small & (1 << 2)) != 0;
|
||||
bool has_fields_len = (small & (1 << 3)) != 0;
|
||||
bool has_decls_len = (small & (1 << 4)) != 0;
|
||||
bool auto_enum_tag = (small & (1 << 9)) != 0;
|
||||
|
||||
// Skip 6 u32 header (fields_hash×4, src_line, src_node).
|
||||
uint32_t extra_index = operand + 6;
|
||||
|
||||
if (has_tag_type)
|
||||
extra_index++; // skip tag_type ref
|
||||
uint32_t captures_len = 0;
|
||||
if (has_captures_len) {
|
||||
captures_len = zir->extra[extra_index++];
|
||||
}
|
||||
if (has_body_len) {
|
||||
extra_index++; // skip body_len
|
||||
}
|
||||
uint32_t fields_len = 0;
|
||||
if (has_fields_len) {
|
||||
fields_len = zir->extra[extra_index++];
|
||||
}
|
||||
uint32_t decls_len = 0;
|
||||
if (has_decls_len) {
|
||||
decls_len = zir->extra[extra_index++];
|
||||
}
|
||||
|
||||
extra_index += captures_len * 2; // skip captures
|
||||
|
||||
// Create type_union IP entry.
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_UNION_TYPE;
|
||||
key.data.union_type = s_next_struct_hash++;
|
||||
InternPoolIndex union_ip = ipIntern(s_module_ip, key);
|
||||
|
||||
// Set resolved_type and create ptr_nav for the union nav.
|
||||
// In the Zig compiler, analyzeNavVal → analyzeNavRefInner creates
|
||||
// the ptr_nav AFTER the type but BEFORE resolveFully resolves the
|
||||
// union body. We match that order here.
|
||||
{
|
||||
Nav* wnav = ipGetNav(nav_idx);
|
||||
wnav->resolved_type = union_ip;
|
||||
InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE);
|
||||
(void)internNavPtr(ptr_type, nav_idx);
|
||||
}
|
||||
|
||||
// Create namespace for the union.
|
||||
uint32_t file_idx
|
||||
= s_namespaces[ipGetNav(nav_idx)->namespace_idx].file_idx;
|
||||
uint32_t ns_idx = createNamespace(union_ip, file_idx);
|
||||
|
||||
// Scan namespace declarations (creates Navs for sub-types like
|
||||
// CommonOptions, X86RegparmOptions, etc.).
|
||||
const uint32_t* decl_insts = &zir->extra[extra_index];
|
||||
scanNamespaceC(ns_idx, decl_insts, decls_len, zir);
|
||||
|
||||
// Resolve declarations inside the union namespace.
|
||||
// This creates struct types for sub-types like CommonOptions.
|
||||
// Each sub-type creates: type_struct + ptr_nav.
|
||||
{
|
||||
const SemaNamespace* uns = &s_namespaces[ns_idx];
|
||||
for (uint32_t i = 0; i < uns->pub_nav_count; i++) {
|
||||
(void)ensureNavValUpToDate(uns->pub_navs[i]);
|
||||
}
|
||||
for (uint32_t i = 0; i < uns->priv_nav_count; i++) {
|
||||
(void)ensureNavValUpToDate(uns->priv_navs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// For auto_enum_tag or explicit tag: create field tag values and
|
||||
// the tag enum.
|
||||
if (auto_enum_tag || has_tag_type) {
|
||||
// Create comptime_int for field count - 1 (matching upstream
|
||||
// Sema.zig unionFields line 35570: fields_len - 1).
|
||||
if (fields_len > 0) {
|
||||
(void)internTypedInt(IP_INDEX_COMPTIME_INT_TYPE, fields_len - 1);
|
||||
}
|
||||
|
||||
// Create int_u8 values for each field tag (auto-enum: 0,1,...).
|
||||
// Values 0 and 1 are pre-interned. Create 2..fields_len-1.
|
||||
for (uint32_t i = 2; i < fields_len; i++) {
|
||||
(void)internTypedInt(IP_INDEX_U8_TYPE, i);
|
||||
}
|
||||
|
||||
// Create the tag enum type.
|
||||
InternPoolKey ek;
|
||||
memset(&ek, 0, sizeof(ek));
|
||||
ek.tag = IP_KEY_ENUM_TYPE;
|
||||
ek.data.enum_type = s_next_struct_hash++;
|
||||
(void)ipIntern(s_module_ip, ek);
|
||||
}
|
||||
|
||||
return union_ip;
|
||||
}
|
||||
|
||||
// --- ensureNavValUpToDate ---
|
||||
// Resolve a Nav's declaration value to create IP entries for its type.
|
||||
// Finds the declaration's value body in ZIR and dispatches to the
|
||||
@@ -2885,6 +3068,11 @@ static InternPoolIndex resolveEnumDeclFromZir(
|
||||
// Ported from PerThread.zig ensureNavValUpToDate.
|
||||
static InternPoolIndex ensureNavValUpToDate(uint32_t nav_idx) {
|
||||
const Nav* nav = ipGetNav(nav_idx);
|
||||
|
||||
// If already resolved, return the cached value.
|
||||
if (nav->resolved_type != IP_INDEX_NONE)
|
||||
return nav->resolved_type;
|
||||
|
||||
uint32_t ns_idx = nav->namespace_idx;
|
||||
const SemaNamespace* ns = &s_namespaces[ns_idx];
|
||||
uint32_t file_idx = ns->file_idx;
|
||||
@@ -2908,7 +3096,10 @@ static InternPoolIndex ensureNavValUpToDate(uint32_t nav_idx) {
|
||||
uint16_t opcode = zir->inst_datas[inst].extended.opcode;
|
||||
if (opcode == ZIR_EXT_ENUM_DECL)
|
||||
return resolveEnumDeclFromZir(zir, inst, nav_idx);
|
||||
// TODO: ZIR_EXT_STRUCT_DECL, ZIR_EXT_UNION_DECL
|
||||
if (opcode == ZIR_EXT_STRUCT_DECL)
|
||||
return resolveStructDeclFromZir(zir, inst, nav_idx);
|
||||
if (opcode == ZIR_EXT_UNION_DECL)
|
||||
return resolveUnionDeclFromZir(zir, inst, nav_idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3087,6 +3278,7 @@ static void resolveBuiltinDeclTypes(uint32_t builtin_ns_idx) {
|
||||
static const char* const builtin_type_names[] = {
|
||||
"Signedness",
|
||||
"AddressSpace",
|
||||
"CallingConvention",
|
||||
};
|
||||
uint32_t n_types
|
||||
= sizeof(builtin_type_names) / sizeof(builtin_type_names[0]);
|
||||
|
||||
Reference in New Issue
Block a user