diff --git a/stage0/sema.c b/stage0/sema.c index f0286bee1d..555d7b9869 100644 --- a/stage0/sema.c +++ b/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]);