fix: visibility-aware type-name resolution at registration time
Enum payloads, union fields, inline struct/enum/union field types, and named error-set references now resolve through the visibility-aware `inner` recursion hook (the same seam `resolveCompound` uses) instead of the flat `findByName`. A bare type name in any of these positions now selects the querying module's OWN author over a same-name namespaced import -- the own-wins rule already applied to top-level named references and struct fields. - buildEnumInfo / buildUnionInfo / resolveInlineEnum / resolveInlineStruct / resolveInlineUnion / resolveErrorType take the `inner: anytype` seam; registerEnumDecl / registerUnionDecl and the struct-const annotation pass `self` (visibility-aware); resolveAstType passes the stateless `si`. - resolveTypeWithBindings routes inline type decls and named error refs through `self` instead of delegating to flat resolveAstType. Regression tests: examples/0781 (top-level enum payload over a namespaced import), examples/0784 (inline struct field). Addresses issue 0132's broader latent class; the protocol-return case (0132 primary) is a separate registerProtocolDecl fix and stays open. The error-set reference path is in place but dormant pending error-set per-decl nominal identity (issue 0134).
This commit is contained in:
@@ -703,7 +703,7 @@ pub fn registerStructDecl(self: *Lowering, sd: *const ast.StructDecl, source_fil
|
||||
if (const_node.data == .const_decl) {
|
||||
const cd = const_node.data.const_decl;
|
||||
const qualified = std.fmt.allocPrint(self.alloc, "{s}.{s}", .{ sd.name, cd.name }) catch continue;
|
||||
const ty: ?TypeId = if (cd.type_annotation) |ta| type_bridge.resolveAstType(ta, table, &self.program_index.type_alias_map, &self.program_index.module_const_map) else null;
|
||||
const ty: ?TypeId = if (cd.type_annotation) |ta| self.resolveType(ta) else null;
|
||||
self.struct_const_map.put(qualified, .{ .value = cd.value, .ty = ty }) catch {};
|
||||
}
|
||||
}
|
||||
@@ -725,7 +725,12 @@ pub fn registerEnumDecl(self: *Lowering, ed: *const ast.EnumDecl) void {
|
||||
const name_id = table.internString(ed.name);
|
||||
const decl_key: *const anyopaque = @ptrCast(ed);
|
||||
const nominal_id: u32 = if (table.type_decl_tids.get(decl_key)) |id| nominalIdOf(table.get(id)) else self.shadowNominalId(name_id);
|
||||
const info = type_bridge.buildEnumInfo(ed, table, &self.program_index.type_alias_map, &self.program_index.module_const_map);
|
||||
// Pass `self` (the visibility-aware `Lowering` resolver) as the `inner`
|
||||
// recursion hook — the same seam `resolveCompound` uses — so a payload type
|
||||
// NAME resolves in the enum's OWN module visibility context (own author wins
|
||||
// over a namespaced same-name import), not via a global `findByName`
|
||||
// first-match (issue 0132's class).
|
||||
const info = type_bridge.buildEnumInfo(ed, table, self);
|
||||
_ = self.internNamedTypeDecl(decl_key, name_id, info, nominal_id);
|
||||
}
|
||||
|
||||
@@ -736,7 +741,8 @@ pub fn registerUnionDecl(self: *Lowering, ud: *const ast.UnionDecl) void {
|
||||
const name_id = table.internString(ud.name);
|
||||
const decl_key: *const anyopaque = @ptrCast(ud);
|
||||
const nominal_id: u32 = if (table.type_decl_tids.get(decl_key)) |id| nominalIdOf(table.get(id)) else self.shadowNominalId(name_id);
|
||||
const info = type_bridge.buildUnionInfo(ud, table, &self.program_index.type_alias_map, &self.program_index.module_const_map);
|
||||
// `self` as the visibility-aware `inner` hook — see `registerEnumDecl`.
|
||||
const info = type_bridge.buildUnionInfo(ud, table, self);
|
||||
_ = self.internNamedTypeDecl(decl_key, name_id, info, nominal_id);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user