fix: visibility-aware type resolution for protocol method signatures
`registerProtocolDecl` resolved each method's param/return type NAME
through the flat, visibility-unaware `type_bridge.resolveAstType`, so a
type name colliding across modules bound to the wrong author. In the
repro the user's `Event` enum collides with the stdlib `event.Event`
struct (pulled in by `modules/std.sx`): the protocol grabbed the stdlib
struct, typed an inferred `g_plat.one_event()` as a fieldless struct,
bound the `case .key_up:(e)` payload to `.unresolved`, and emitted
"enum literal '.escape' has no destination type to resolve against".
Resolve both param and return types through
`resolveTypeInSource(pd.source_file, …)` — the visibility-aware resolver
pinned to the protocol's own declaring module, keeping the `Self → *void`
short-circuit. Brings the non-parameterized path to parity with
`instantiateParamProtocol` and concrete-fn signatures. No silent default:
not-visible / ambiguous names still diagnose and poison with `.unresolved`.
Closes issue 0132 — the protocol-return case left open by f13f4ab (which
fixed the enum/union/inline/error-set registration class). Regression
test: examples/0417-protocols-protocol-return-name-collision.sx.
This commit is contained in:
@@ -284,19 +284,27 @@ pub const ProtocolResolver = struct {
|
||||
const id = if (table.findByName(name_id)) |existing| existing else table.intern(struct_info);
|
||||
table.updatePreservingKey(id, struct_info);
|
||||
|
||||
// Build protocol method info for dispatch
|
||||
// Build protocol method info for dispatch. Resolve each method's
|
||||
// param/return type NAMES in the protocol's OWN declaring module
|
||||
// (`pd.source_file`, stamped by `resolveImports`), via the
|
||||
// visibility-aware stateful resolver — NOT the flat, visibility-unaware
|
||||
// `type_bridge.resolveAstType`. The flat lookup picks the WRONG author
|
||||
// when the type name collides across modules (issue 0132: the user's
|
||||
// `Event` enum vs the stdlib `event.Event` struct pulled in by
|
||||
// `modules/std.sx`). This mirrors the parameterized-protocol path
|
||||
// (`instantiateParamProtocol`, lower/protocol.zig) and concrete-fn
|
||||
// signatures, which already pin to the defining module. `Self` short-
|
||||
// circuits to `*void` before the leaf, as before. `pd.source_file ==
|
||||
// null` (synthesized decl) falls back to the current context.
|
||||
var method_infos = std.ArrayList(ProtocolMethodInfo).empty;
|
||||
for (pd.methods) |method| {
|
||||
var ptypes = std.ArrayList(TypeId).empty;
|
||||
for (method.params) |p| {
|
||||
// Self → *void for protocol context; everything else
|
||||
// goes through `resolveAstType`, threaded with the canonical
|
||||
// alias map (`ProgramIndex.type_alias_map`).
|
||||
const pty = blk: {
|
||||
if (p.data == .type_expr and std.mem.eql(u8, p.data.type_expr.name, "Self")) {
|
||||
break :blk void_ptr_ty;
|
||||
}
|
||||
break :blk type_bridge.resolveAstType(p, table, &self.l.program_index.type_alias_map, &self.l.program_index.module_const_map);
|
||||
break :blk self.l.resolveTypeInSource(pd.source_file, p);
|
||||
};
|
||||
ptypes.append(self.l.alloc, pty) catch unreachable;
|
||||
}
|
||||
@@ -306,7 +314,7 @@ pub const ProtocolResolver = struct {
|
||||
ret_is_self = true;
|
||||
break :blk void_ptr_ty;
|
||||
}
|
||||
break :blk type_bridge.resolveAstType(rt, table, &self.l.program_index.type_alias_map, &self.l.program_index.module_const_map);
|
||||
break :blk self.l.resolveTypeInSource(pd.source_file, rt);
|
||||
} else .void;
|
||||
method_infos.append(self.l.alloc, .{
|
||||
.name = method.name,
|
||||
|
||||
Reference in New Issue
Block a user