fix(stdlib/E4): type-fn head gate selects the TYPE-FUNCTION author (ordinary fn must not vouch)

attempt-7 made the type-fn head gate kind-aware (a non-function no longer
vouches), but it still accepted ANY function author: a directly-visible
ORDINARY function (`Make :: () -> s32`, zero `$`-params) authorized a hidden
2-flat-hop type-function head (`Make :: ($T) -> Type`), so `size_of(Make(s64))`
silently instantiated the 2-hop type-fn and printed `size=8` at exit 0.

Narrow the author view from "any fn_decl" to "a TYPE-FUNCTION" via a new
`typeFnAuthor` predicate (`fnDeclOfRaw` + `type_params.len > 0`), the same
discriminator every instantiation site uses to recognize a type-fn head. Both
`flatFnAuthorVisible` and `flatFnAuthorAmbiguous` now count only type-fn
authors, so a same-name ordinary function — which cannot be the type head being
instantiated — does not vouch for a 2-hop type-fn head.

Regression 0771: main -> b (`Make :: () -> s32` ordinary fn + flat-imports c)
-> c (`Make :: ($T) -> Type`); `size_of(Make(s64))` -> "type 'Make' is not
visible", exit 1 (fail-before on 94c3cd7: size=8 exit 0). 0770 (non-fn vouch),
0769 (type-fn ambiguity), 0768/0767/0766-0763, 0208/0210 (valid type-fn heads),
0544/0706/0105 and FFI all green & byte-identical.
This commit is contained in:
agra
2026-06-08 16:43:01 +03:00
parent 94c3cd7507
commit 566de96821
7 changed files with 74 additions and 13 deletions

View File

@@ -0,0 +1,25 @@
// A type-returning FUNCTION head (`Make(s64)` where `Make :: ($T) -> Type`) is
// NON-transitive even when a DIRECT flat import authors the same name as an
// ORDINARY (non-type-returning) function. `main` flat-imports `b.sx`; `b.sx`
// declares `Make :: () -> s32` (a plain function, NOT a type-fn) AND flat-imports
// `c.sx`, whose `Make` IS the type-returning function. The only TYPE-FN author of
// `Make` is two flat hops away (main → b → c), so the bare `Make(s64)` head must
// emit the "type 'Make' is not visible" diagnostic and poison — the visible 1-hop
// ordinary `Make :: () -> s32` must NOT vouch for it.
//
// Regression (Phase E4 attempt-8, finding E4-type-fn-head-hidden-by-visible-
// nontypefn): attempt-7's `headFnLeak` decided visibility from any FUNCTION
// author (`fnDeclOfRaw != null`), so the visible ordinary `Make` function (which
// CANNOT be the type head being instantiated) still vouched — the global
// `fn_ast_map` type-fn silently instantiated and `size_of(Make(s64))` printed 8
// at exit 0 instead of the visibility diagnostic. The fix narrows the author view
// to TYPE-FUNCTIONS (`typeFnAuthor`: a `fn_decl` with ≥1 `$`-param), the same
// discriminator every instantiation site uses to recognize a type-fn head.
#import "modules/std.sx";
#import "0771-modules-type-fn-head-ordinary-fn-no-vouch/b.sx";
main :: () -> s32 {
print("size={}\n", size_of(Make(s64)));
0
}

View File

@@ -0,0 +1,7 @@
// The directly-imported (1-hop) author of the NAME `Make` — but as an ORDINARY
// function (`() -> s32`), NOT a type-returning function. It flat-imports c.sx
// (where the real `Make` type-fn lives, two hops from a file that imports b.sx).
// A same-name ordinary function must not vouch for the 2-hop type-fn head: it has
// zero `$`-params, so it cannot be the type head `Make(s64)` is instantiating.
#import "c.sx";
Make :: () -> s32 { return 7; }

View File

@@ -0,0 +1,5 @@
// The real type-returning function `Make`, two flat hops from a file that
// imports b.sx. A file importing only b.sx must NOT see this head.
Make :: ($T: Type) -> Type {
return struct { x: T; };
}

View File

@@ -0,0 +1,5 @@
error: type 'Make' is not visible; #import the module that declares it
--> examples/0771-modules-type-fn-head-ordinary-fn-no-vouch.sx:23:32
|
23 | print("size={}\n", size_of(Make(s64)));
| ^^^^