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:
2026-02-26 05:40:54 +00:00
parent e95f46eeff
commit 5174dd2146

View File

@@ -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]);