lang: generic $R type-arg resolution + receiver-driven ufcs overload (issues 0156, 0157)

0156 Part 1: a single-type generic $R (parsed as comptime_pack_ref)
used as a type-arg in a pack-fn body (Box($R), size_of(Box($R))) hit a
missing arm in resolveTypeWithBindings -> .unresolved -> LLVM panic.
Fix: mirror resolveTypeArg's comptime_pack_ref arm (look up
type_bindings, else a loud diagnostic). Regression: examples/generics/0216.
(Part 2 -- deferred .. spread crashes -- reframed OPEN/non-blocking.)

0157: a user generic ufcs method whose name collides with a stdlib
re-export resolved via last-wins fn_ast_map with no receiver filtering,
so the wrong overload won, $R never bound, and .unresolved reached LLVM.
Fix: selectUfcsGenericByReceiver enumerates all module authors, keeps
the receiver-binding ones, picks the most receiver-specific (concrete >
bare $T), dedups re-exports, and flags a genuine tie as a deterministic
'ambiguous -- qualify' diagnostic. Regression: examples/generics/0217.
This commit is contained in:
agra
2026-06-21 18:43:49 +03:00
parent b1e06f21e3
commit d3944570b9
13 changed files with 443 additions and 2 deletions

View File

@@ -853,6 +853,27 @@ pub const Lowering = struct {
}
return .unresolved;
}
// Bare `$<name>` in a type position. The parser tags EVERY `$name`
// expression as `comptime_pack_ref` — including a single-type generic
// binding (`$R: Type` in `Closure(..$args) -> $R`), which is NOT a
// value pack. Such a binding lives in `type_bindings`; resolve it the
// same way `resolveTypeArg` does (so `Box($R)` / `size_of(Box($R))` /
// a bare `-> $R` return inside a pack-fn mono resolve `$R` to its bound
// TypeId). Without this arm the node fell through to the catch-all
// `else` → `type_bridge` → `.unresolved` → an LLVM-emission panic
// (issue 0156). A name that is genuinely a value PACK (no single-type
// binding) used where one type is required is a real error — diagnose
// it, never silently fabricate a default type.
if (node.data == .comptime_pack_ref) {
const cpr = node.data.comptime_pack_ref;
if (self.type_bindings) |tb| {
if (tb.get(cpr.pack_name)) |ty| return ty;
}
if (self.diagnostics) |diags| {
diags.addFmt(.err, node.span, "pack '{s}' used where a single type is required", .{cpr.pack_name});
}
return .unresolved;
}
// `*Self` substitution inside runtime-class member declarations
// — both runtime and sx-defined — resolves to the class's own
// 0-field stub struct (i.e. the opaque Obj-C pointer type).
@@ -1854,6 +1875,8 @@ pub const Lowering = struct {
// --- moved to lower/call.zig (lower_call) ---
pub const CaptureInfo = lower_closure.CaptureInfo;
pub const lowerCall = lower_call.lowerCall;
pub const ufcsGenericBindsAll = lower_call.ufcsGenericBindsAll;
pub const selectUfcsGenericByReceiver = lower_call.selectUfcsGenericByReceiver;
pub const diagnoseMissingContext = lower_call.diagnoseMissingContext;
pub const allocViaContext = lower_call.allocViaContext;
pub const callExtern = lower_call.callExtern;