commit ea27893b8cb505c054e6c5da32271db74be6b18a (tree)
parent 808f7ef42f37b874de53db5b2ddf9b7783387199
Author: Motiejus <motiejus@jakstys.lt>
Date: Sat, 28 Feb 2026 01:35:49 +0000
sema: add enum_literal→enum coercion and fix ptr_nav child types
- 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 <noreply@anthropic.com>
Diffstat:
| M | stage0/sema.c | | | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
1 file changed, 89 insertions(+), 22 deletions(-)
diff --git 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 {