From ea27893b8cb505c054e6c5da32271db74be6b18a Mon Sep 17 00:00:00 2001 From: Motiejus Date: Sat, 28 Feb 2026 01:35:49 +0000 Subject: [PATCH] =?UTF-8?q?sema:=20add=20enum=5Fliteral=E2=86=92enum=20coe?= =?UTF-8?q?rcion=20and=20fix=20ptr=5Fnav=20child=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add enum_literal + enum → enum peer type resolution in semaResolvePeerTypes. - Add enum_literal → enum coercion in semaCoerce: looks up the literal name in the target enum type's ZIR to create an enum_tag entry. - Make comptime CMP_EQ coerce through peer types before comparing, matching the Zig compiler's analyzeCmp → resolvePeerTypes → coerce path. This creates enum_tag IP entries as side effects. - Fix ptr_nav child type: use typeOf(val) instead of always type_type. During main analysis, all navs get ptr_type(child=typeOf(val)) + ptr_nav entries. During preamble, only type declarations (struct/enum/union) get ptr_nav. This matches analyzeNavRefInner. - Remove debug instrumentation (s_dbg_trace_body, instruction traces). - Add forward declarations for findEnumFieldByName, getEnumFieldIntVal, findEnumDeclForNav, internEnumTag. Co-Authored-By: Claude Opus 4.6 --- stage0/sema.c | 111 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/stage0/sema.c b/stage0/sema.c index 0b8319f80c..6baeca387c 100644 --- a/stage0/sema.c +++ b/stage0/sema.c @@ -370,6 +370,13 @@ static uint32_t semaAddExtra(Sema* sema, uint32_t value) { // --- Forward declarations --- static TypeIndex semaTypeOf(Sema* sema, AirInstRef ref); +static uint32_t findEnumFieldByName( + const Zir* zir, uint32_t enum_inst, const char* name); +static InternPoolIndex getEnumFieldIntVal( + const Zir* zir, uint32_t enum_inst, uint32_t field_idx); +static uint32_t findEnumDeclForNav(uint32_t nav_idx, const Zir** out_zir); +static InternPoolIndex internEnumTag( + InternPoolIndex enum_ty, InternPoolIndex int_val); // --- ZIR instruction handlers --- // Ported from src/Sema.zig instruction handlers. @@ -802,6 +809,14 @@ static TypeIndex semaResolvePeerTypes( return lhs_ty; return rhs_ty; } + // enum_literal + enum → enum. + // Ported from src/Sema.zig peer type resolution for enum_literal. + if (lhs_ty == IP_INDEX_ENUM_LITERAL_TYPE + && sema->ip->items[rhs_ty].tag == IP_KEY_ENUM_TYPE) + return rhs_ty; + if (rhs_ty == IP_INDEX_ENUM_LITERAL_TYPE + && sema->ip->items[lhs_ty].tag == IP_KEY_ENUM_TYPE) + return lhs_ty; // Unhandled combination (e.g. void×type in comptime analysis). // Return lhs as fallback; this path doesn't produce runtime AIR. return lhs_ty; @@ -849,6 +864,39 @@ static AirInstRef semaCoerce( key.data.undef = target_ty; return AIR_REF_FROM_IP(ipIntern(sema->ip, key)); } + // enum_literal → enum coercion: look up the literal in the enum type + // and create an enum_tag entry. + // Ported from src/Sema.zig coerce .enum → .enum_literal path. + if (src_ty == IP_INDEX_ENUM_LITERAL_TYPE && AIR_REF_IS_IP(ref) + && sema->ip->items[target_ty].tag == IP_KEY_ENUM_TYPE) { + InternPoolIndex lit_ip = AIR_REF_TO_IP(ref); + uint32_t lit_str = sema->ip->items[lit_ip].data.enum_literal; + const char* lit_name = (const char*)&sema->ip->string_bytes[lit_str]; + // Find the nav whose resolved_type matches the enum type. + uint32_t enum_nav = UINT32_MAX; + for (uint32_t ni = 0; ni < ipNavCount(); ni++) { + if (ipGetNav(ni)->resolved_type == target_ty) { + enum_nav = ni; + break; + } + } + if (enum_nav != UINT32_MAX) { + const Zir* enum_zir = NULL; + uint32_t enum_inst = findEnumDeclForNav(enum_nav, &enum_zir); + if (enum_inst != UINT32_MAX && enum_zir != NULL) { + uint32_t fidx + = findEnumFieldByName(enum_zir, enum_inst, lit_name); + if (fidx != UINT32_MAX) { + InternPoolIndex int_val + = getEnumFieldIntVal(enum_zir, enum_inst, fidx); + if (int_val != IP_INDEX_NONE) { + return AIR_REF_FROM_IP( + internEnumTag(target_ty, int_val)); + } + } + } + } + } // Comptime int→int coercion: re-intern with target type. if (AIR_REF_IS_IP(ref) && isIntegerType(sema->ip, src_ty) && isIntegerType(sema->ip, target_ty)) { @@ -1382,9 +1430,15 @@ static AirInstRef zirArithmetic( return internComptimeInt(sema, result_ty, r_lo, r_hi); } - // Comptime equality for non-integer IP values (e.g. enum_literal). + // Comptime equality for non-integer IP values (e.g. enum_tag, + // enum_literal). Coerce through peer types first so that enum_literal + // → enum coercion creates the enum_tag IP entry (matching the Zig + // compiler's analyzeCmp → resolvePeerTypes → coerce path). if (AIR_REF_IS_IP(lhs) && AIR_REF_IS_IP(rhs) && (air_tag == AIR_INST_CMP_EQ || air_tag == AIR_INST_CMP_NEQ)) { + TypeIndex peer_ty = semaResolvePeerTypes(sema, lhs, rhs); + lhs = semaCoerce(sema, block, peer_ty, lhs); + rhs = semaCoerce(sema, block, peer_ty, rhs); bool eq = (AIR_REF_TO_IP(lhs) == AIR_REF_TO_IP(rhs)); return AIR_REF_FROM_IP((eq == (air_tag == AIR_INST_CMP_EQ)) ? IP_INDEX_BOOL_TRUE @@ -3347,15 +3401,22 @@ static InternPoolIndex resolveZirTypeInst( if (nav != UINT32_MAX) { InternPoolIndex result = ensureNavValUpToDate(nav); if (result != IP_INDEX_NONE && result != IP_INDEX_VOID_TYPE) { - // Create ptr_nav as side effect, matching Zig's - // zirDeclVal → analyzeNavRef → analyzeNavRefInner. + // Create ptr_type + ptr_nav matching analyzeNavRefInner. + // During main analysis: all navs, typeOf(val) child. + // During preamble: type decls only, type_type child. if (result < s_module_ip->items_len) { - InternPoolKeyTag kt = s_module_ip->items[result].tag; - if (kt == IP_KEY_STRUCT_TYPE || kt == IP_KEY_ENUM_TYPE - || kt == IP_KEY_UNION_TYPE) { - InternPoolIndex dv_ptr_ty - = internPtrConst(IP_INDEX_TYPE_TYPE); + if (s_in_main_analysis) { + InternPoolIndex val_ty = ipTypeOf(s_module_ip, result); + InternPoolIndex dv_ptr_ty = internPtrConst(val_ty); (void)internNavPtr(dv_ptr_ty, nav); + } else { + InternPoolKeyTag kt = s_module_ip->items[result].tag; + if (kt == IP_KEY_STRUCT_TYPE || kt == IP_KEY_ENUM_TYPE + || kt == IP_KEY_UNION_TYPE) { + InternPoolIndex dv_ptr_ty + = internPtrConst(IP_INDEX_TYPE_TYPE); + (void)internNavPtr(dv_ptr_ty, nav); + } } } return result; @@ -3428,16 +3489,22 @@ static InternPoolIndex resolveZirTypeInst( if (member_nav != UINT32_MAX) { InternPoolIndex result = ensureNavValUpToDate(member_nav); if (result != IP_INDEX_NONE) { - // Create ptr_nav for type declarations only, matching - // analyzeNavRefInner. Value declarations (comptime ints - // etc.) don't get ptr_nav during field_val resolution. + // Create ptr_type + ptr_nav matching analyzeNavRefInner. + // During main analysis, create for ALL navs using + // typeOf(val). During preamble, only for type decls. if (result < s_module_ip->items_len) { - InternPoolKeyTag kt = s_module_ip->items[result].tag; - if (kt == IP_KEY_STRUCT_TYPE || kt == IP_KEY_ENUM_TYPE - || kt == IP_KEY_UNION_TYPE) { - InternPoolIndex nav_ptr_ty - = internPtrConst(IP_INDEX_TYPE_TYPE); + if (s_in_main_analysis) { + InternPoolIndex val_ty = ipTypeOf(s_module_ip, result); + InternPoolIndex nav_ptr_ty = internPtrConst(val_ty); (void)internNavPtr(nav_ptr_ty, member_nav); + } else { + InternPoolKeyTag kt = s_module_ip->items[result].tag; + if (kt == IP_KEY_STRUCT_TYPE || kt == IP_KEY_ENUM_TYPE + || kt == IP_KEY_UNION_TYPE) { + InternPoolIndex nav_ptr_ty + = internPtrConst(IP_INDEX_TYPE_TYPE); + (void)internNavPtr(nav_ptr_ty, member_nav); + } } } return result; @@ -14631,12 +14698,12 @@ static bool analyzeBodyInner( InternPoolIndex val = ensureNavValUpToDate(nav); if (val != IP_INDEX_NONE) { resolved = val; - // Create ptr_nav matching Zig's - // analyzeNavRefInner. In Zig, zirDeclVal - // creates ptr_type + ptr_nav for every - // declaration access. - InternPoolIndex pt - = internPtrConst(IP_INDEX_TYPE_TYPE); + // Create ptr_type + ptr_nav matching + // analyzeNavRefInner. Uses typeOf(val) as + // the child type (not always type_type). + InternPoolIndex vt + = ipTypeOf(s_module_ip, val); + InternPoolIndex pt = internPtrConst(vt); (void)internNavPtr(pt, nav); } } else {