attempt-3 closed the MAIN-file value-param-as-type quadrant (0172) in the
UnknownTypeChecker, but the checker only walks main-file decls — an IMPORTED
generic struct's field with a bad type name was never checked. Worse, the
generic-struct INSTANTIATION resolved its field type nodes in the (possibly
cross-module) instantiation site's source context, not the template's module.
So for `Bad :: struct($N: u32) { x: N; }` declared in an imported module and
used as `Bad(3)` from main, the field `x: N` resolved against the main file:
the value-param-as-type leaf poisoned it with `.unresolved` and PANICKED at
LLVM emission, and the genuinely-undeclared sibling (`y: Missing` in a generic
import, distinct from the non-generic 0759 case) silently fabricated a 0-field
stub.
Root cause + uniform fix: capture the declaring module on each StructTemplate
and resolve its field type nodes in THAT source context during
instantiateGenericStruct. The source-aware nominal leaf then classifies main vs
imported by the TEMPLATE's file, so both failure modes are diagnosed at the
right authority for every quadrant — main + imported, undeclared name + value
param used as a type:
- imported `.undeclared` field → the existing leaf emits "unknown type 'X'"
(now reached because `from` is the template's module, not main).
- imported value-param-as-type → the `is_generic` leaf, when the name is bound
as a comptime VALUE (`comptime_value_bindings`), emits the tailored
"'N' is a value parameter, not a type" hint (gated to non-main; the
UnknownTypeChecker owns the main-file case). Caught in every type position
(`x: N`, `*N`, `[3]N`, `?N`). A genuinely-unbound type param (`$R`) stays a
silent `.unresolved`.
No `.unresolved` reaches LLVM for these cases (hasErrors halts after lowering);
the emit_llvm `.unresolved` @panic tripwire stays as the last-resort sentinel.
Valid value-param VALUE positions (`[N]u8` dim, `Vector(N,T)` lane) and
`$T:Type`/`$T:Protocol` type-param fields still resolve.
Regressions:
- 0760-modules-imported-generic-value-param-as-field-type (panic-before / clean
diagnostic-after).
- 0761-modules-imported-generic-undeclared-field (silent-compile-before / clean
diagnostic-after).
0171/0172/0759 stay green; main-file quadrants emit exactly one error.
Gate: zig build; zig build test (423/423 + LSP corpus sweep); run_examples 501
passed / 0 failed (prior 499 byte-identical); m3te ios-sim build exit 0.
20 lines
856 B
Plaintext
20 lines
856 B
Plaintext
// A genuinely-undeclared type in an IMPORTED GENERIC struct field must emit
|
|
// "unknown type" even when the struct is instantiated from the main file —
|
|
// 0759 only covered a non-generic imported struct instantiated in-module.
|
|
// Before the fix the generic template's fields resolved in the main-file
|
|
// instantiation context, so the leaf trusted them as main-file decls and
|
|
// silently stubbed `Missing` (the program compiled and printed `b.x`). The
|
|
// template's fields now resolve in the template's own source context, so the
|
|
// undeclared name surfaces.
|
|
//
|
|
// Expected: `error: unknown type 'Missing'` pointing into lib.sx; exit 1.
|
|
// Regression (stdlib E3).
|
|
#import "modules/std.sx";
|
|
#import "0761-modules-imported-generic-undeclared-field/lib.sx";
|
|
|
|
main :: () -> s32 {
|
|
b : Bad(s32) = .{ x = 1, y = 2 };
|
|
print("{}\n", b.x);
|
|
return 0;
|
|
}
|