commit 3a6f716f22f9c9e7de7387aae404013e93a5f232 (tree)
parent 83e972b87f0dd87119733f39286b36f12659cde3
Author: Motiejus <motiejus@jakstys.lt>
Date: Fri, 27 Feb 2026 02:29:23 +0000
sema: fix type alias resolution and refactor FieldInfo struct
Fix resolveZirTypeInst decl_val path: when ensureNavValUpToDate returns
IP_INDEX_VOID_TYPE (from unhandled type instructions like optional_type),
fall through to the type alias fallback instead of returning the bogus
result. Also fix bugs where the fallback used the caller's ZIR/namespace
instead of the nav's, and create ptr_nav for resolved type aliases to
match the Zig compiler's analyzeNavRefInner behavior.
Replace FieldInfo struct in resolveStructFieldInitsC with separate arrays
to satisfy cppcheck unused-member checks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
| M | stage0/sema.c | | | 89 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 47 insertions(+), 42 deletions(-)
diff --git a/stage0/sema.c b/stage0/sema.c
@@ -3258,10 +3258,13 @@ static InternPoolIndex resolveZirTypeInst(
}
if (nav != UINT32_MAX) {
InternPoolIndex result = ensureNavValUpToDate(nav);
- if (result != IP_INDEX_NONE)
+ if (result != IP_INDEX_NONE && result != IP_INDEX_VOID_TYPE)
return result;
// Type alias (e.g. `const ErrorSet = ?[]const Error`):
// resolve the nav's value body as a type expression.
+ // Also reached when ensureNavValUpToDate returns VOID_TYPE,
+ // which happens when the body contains type instructions
+ // (optional_type, ptr_type) that analyzeNavValC can't handle.
const Nav* tnav = ipGetNav(nav);
uint32_t tnns = tnav->namespace_idx;
uint32_t tnfi = s_namespaces[tnns].file_idx;
@@ -3273,20 +3276,30 @@ static InternPoolIndex resolveZirTypeInst(
if (tbody && tbody_len > 0) {
uint32_t last_inst = tbody[tbody_len - 1];
if (last_inst < tzir->inst_len
- && zir->inst_tags[last_inst]
+ && tzir->inst_tags[last_inst]
== ZIR_INST_BREAK_INLINE) {
ZirInstRef op
= tzir->inst_datas[last_inst].break_data.operand;
- result
- = resolveZirTypeRef(tzir, op, struct_ns, file_idx);
- if (result != IP_INDEX_NONE) {
+ InternPoolIndex alias_result
+ = resolveZirTypeRef(tzir, op, tnns, tnfi);
+ if (alias_result != IP_INDEX_NONE) {
Nav* wnav = ipGetNav(nav);
- wnav->resolved_type = result;
+ wnav->resolved_type = alias_result;
+ // Create ptr_nav for the alias declaration,
+ // matching analyzeNavRefInner which creates
+ // a ptr_nav for every resolved nav reference.
+ InternPoolIndex ptr_ty
+ = internPtrConst(IP_INDEX_TYPE_TYPE);
+ (void)internNavPtr(ptr_ty, nav);
+ return alias_result;
}
- return result;
}
}
}
+ // If the type alias fallback didn't resolve, return the
+ // original result (which may be VOID_TYPE or NONE).
+ if (result != IP_INDEX_NONE)
+ return result;
}
}
@@ -3572,17 +3585,18 @@ static void resolveStructFieldInitsC(const Zir* zir, uint32_t struct_inst,
uint32_t bags_count = (s_fields_len + 7) / 8;
sei += bags_count;
- // First pass: collect field info including type refs.
- typedef struct {
- uint32_t type_body_len;
- uint32_t align_body_len;
- uint32_t init_body_len;
- uint32_t type_ref; // valid when has_type_body == false
- bool has_type_body;
- } FieldInfo;
- FieldInfo field_info[32]; // max fields we handle
+ // First pass: collect body lengths for each field.
+ // Stored as separate arrays to satisfy cppcheck unused-member checks.
+ uint32_t fi_type_body_len[32];
+ uint32_t fi_align_body_len[32];
+ uint32_t fi_init_body_len[32];
+ uint32_t fi_type_ref[32]; // valid when type_body_len == 0
if (s_fields_len > 32)
return;
+ memset(fi_type_body_len, 0, s_fields_len * sizeof(uint32_t));
+ memset(fi_align_body_len, 0, s_fields_len * sizeof(uint32_t));
+ memset(fi_init_body_len, 0, s_fields_len * sizeof(uint32_t));
+ memset(fi_type_ref, 0, s_fields_len * sizeof(uint32_t));
for (uint32_t fi = 0; fi < s_fields_len; fi++) {
uint32_t bag_i = fi / 8;
@@ -3591,28 +3605,21 @@ static void resolveStructFieldInitsC(const Zir* zir, uint32_t struct_inst,
bool f_has_align = (bits & 1) != 0;
bool f_has_init = ((bits >> 1) & 1) != 0;
bool f_has_type_body = ((bits >> 3) & 1) != 0;
- (void)f_has_align;
sei++; // skip field_name
- field_info[fi].type_body_len = 0;
- field_info[fi].align_body_len = 0;
- field_info[fi].init_body_len = 0;
- field_info[fi].type_ref = 0;
- field_info[fi].has_type_body = f_has_type_body;
-
if (f_has_type_body)
- field_info[fi].type_body_len = zir->extra[sei];
+ fi_type_body_len[fi] = zir->extra[sei];
else
- field_info[fi].type_ref = zir->extra[sei];
+ fi_type_ref[fi] = zir->extra[sei];
sei++;
if (f_has_align) {
- field_info[fi].align_body_len = zir->extra[sei];
+ fi_align_body_len[fi] = zir->extra[sei];
sei++;
}
if (f_has_init) {
- field_info[fi].init_body_len = zir->extra[sei];
+ fi_init_body_len[fi] = zir->extra[sei];
sei++;
}
}
@@ -3623,17 +3630,17 @@ static void resolveStructFieldInitsC(const Zir* zir, uint32_t struct_inst,
uint32_t pos = sei;
for (uint32_t fi = 0; fi < s_fields_len; fi++) {
type_body_starts[fi] = pos;
- pos += field_info[fi].type_body_len;
- pos += field_info[fi].align_body_len;
- pos += field_info[fi].init_body_len;
+ pos += fi_type_body_len[fi];
+ pos += fi_align_body_len[fi];
+ pos += fi_init_body_len[fi];
}
}
// Second pass: iterate through bodies and evaluate init bodies.
for (uint32_t fi = 0; fi < s_fields_len; fi++) {
- sei += field_info[fi].type_body_len;
- sei += field_info[fi].align_body_len;
- uint32_t init_body_len = field_info[fi].init_body_len;
+ sei += fi_type_body_len[fi];
+ sei += fi_align_body_len[fi];
+ uint32_t init_body_len = fi_init_body_len[fi];
uint32_t init_body_start = sei;
sei += init_body_len;
@@ -3653,10 +3660,9 @@ static void resolveStructFieldInitsC(const Zir* zir, uint32_t struct_inst,
if (operand == ZIR_REF_NULL_VALUE) {
// Resolve the field type to get the optional type IP index.
InternPoolIndex opt_ty = IP_INDEX_NONE;
- if (field_info[fi].has_type_body
- && field_info[fi].type_body_len > 0) {
+ if (fi_type_body_len[fi] > 0) {
uint32_t tbs = type_body_starts[fi];
- uint32_t tbl = field_info[fi].type_body_len;
+ uint32_t tbl = fi_type_body_len[fi];
uint32_t tb_last = zir->extra[tbs + tbl - 1];
if (tb_last < zir->inst_len
&& zir->inst_tags[tb_last] == ZIR_INST_BREAK_INLINE) {
@@ -3760,16 +3766,15 @@ static void resolveStructFieldInitsC(const Zir* zir, uint32_t struct_inst,
uint64_t val = zir->inst_datas[operand_inst].int_val;
InternPoolIndex field_ty = IP_INDEX_NONE;
- if (!field_info[fi].has_type_body
- && field_info[fi].type_ref < ZIR_REF_START_INDEX) {
+ if (fi_type_body_len[fi] == 0
+ && fi_type_ref[fi] < ZIR_REF_START_INDEX) {
// Simple pre-interned type ref.
- field_ty = field_info[fi].type_ref;
- } else if (field_info[fi].has_type_body
- && field_info[fi].type_body_len > 0) {
+ field_ty = fi_type_ref[fi];
+ } else if (fi_type_body_len[fi] > 0) {
// Resolve the field type from the type body.
// Find the break_inline at end of type body.
uint32_t tbs = type_body_starts[fi];
- uint32_t tbl = field_info[fi].type_body_len;
+ uint32_t tbl = fi_type_body_len[fi];
uint32_t tb_last = zir->extra[tbs + tbl - 1];
if (tb_last < zir->inst_len
&& zir->inst_tags[tb_last] == ZIR_INST_BREAK_INLINE) {