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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user