// issue 0132 — protocol method return/param type resolves to the WRONG // same-name type (visibility-unaware registration). // // ROOT CAUSE (corrected — see the .md): `registerProtocolDecl` resolves // the method return type `Event` through a flat, visibility-UNAWARE lookup // (type_bridge.resolveAstType → findByName). The user's `Event` enum // collides by NAME with the stdlib `std/event.sx` `Event :: struct` // (pulled in by `#import "modules/std.sx"`, namespaced as `event`). The // flat lookup picks the stdlib struct, so `ev := g_plat.one_event()` is // typed as a fieldless struct; the `case .key_up:(e)` payload then binds // `.unresolved`, and `.escape` has no destination type. // // EXPECT (today): build FAILS — // error: enum literal '.escape' has no destination type to resolve against // EXPECT (after fix): prints `escape!`, exit 0. // // Proof it's a name collision: rename `Event` -> `Evt` everywhere and the // inferred form compiles and prints `escape!`. Annotating // `ev : Event = g_plat.one_event();` also sidesteps it (the annotation // path is visibility-aware). See the .md for the full bisection. #import "modules/std.sx"; Keycode :: enum { unknown; escape; enter; } KeyData :: struct { key: Keycode; } Event :: enum { none; key_up: KeyData; } Plat :: protocol { one_event :: () -> Event; } Impl :: struct { dummy: i64; } impl Plat for Impl { one_event :: (self: *Impl) -> Event { return .key_up(.{ key = .escape }); } } main :: () { impl : Impl = .{ dummy = 0 }; g_plat : Plat = xx @impl; ev := g_plat.one_event(); // type INFERRED from protocol return if ev == { case .key_up: (e) { if e.key == .escape { print("escape!\n"); } // <-- errors here } } }