wcc: route deref-call N_CALL to fn-VALUE fallback (#181)
Pre-fix the wwstage checker bailed asserttyped on the N_CALL whose
callee was N_UN TK_STAR over a *fn — selfhost/cmd/wcc/check.ww
exprtype's N_CALL arm only resolved IDENT/DOT-named callees and
early-returned nil for any other shape, leaving e.type_ unstamped
so the post-checker invariant fired. cstage worked because cexpr
recurses on the callee — TK_STAR's unop arm returns t->sub which
IS the TY_FN, no name path needed.
Fix: replace the `if (nm.len == 0) return nil` early-bail with
`if (nm.len > 0) { name-lookup }`, so non-named callees fall
through to the existing fn-VALUE fallback below (peel TPTR /
dealias to TFN / stamp the result type). Mirrors harec
check_autodereference at ref/harec/src/check.c:1566. cgen post
-#180+#185 already lowers the deref-call correctly, so lifting
the asserttyped bail is silent-SIGSEGV-safe per drew + ken.
Combined.ww regenerated for selfhost/cmd/{w6c,wwdump}/main
.combined.ww per #110 freshness gate.
Probe: test/wcc/766_star_fn_deref_call.c, 5 rows table-driven —
minimal / branched-callee / alias-chain / fn-with-args / fn
-tuple-return. Gate flip from 765: every row now gates BOTH
stages — cstage runtime, wwstage runtime, AND cs.s == ww.s byte
-id. This is the runtime coverage 765 deferred plus the symmetry
gate that proves both stages emit identical asm for the deref
-call shape. Closes the full c-cluster (#180 + #185 + #181 all 3
commits working together end-to-end).
This commit is contained in:
@@ -12408,7 +12408,6 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||
if (nm.len == 0) { return nil; };
|
||||
// #56: bare-leaf N_IDENT calls go through scopelookupprefer so
|
||||
// `foo()` inside module M binds to M.foo rather than another
|
||||
// module's same-leaf foo at the head of the flat scope bucket.
|
||||
@@ -12438,31 +12437,41 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
// that coexists in the same scope (coexistence-equivalent of
|
||||
// cstage's use_alias; see lib/ww/sym.ww + memory
|
||||
// module_type_name_collision).
|
||||
let s: *sym = nil;
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
s = scopelookupprefer(c.cur, c.curmod, nm);
|
||||
} else {
|
||||
let ms: *sym = nil;
|
||||
if (callee.lhs != nil && callee.lhs.kind == nkind.N_IDENT) {
|
||||
ms = scopelookupprefer(c.cur, c.curmod, callee.lhs.str);
|
||||
if (ms != nil && ms.skind != skind.SK_USE) {
|
||||
let mu: *sym = scopelookupuselocal(ms.scope, callee.lhs.str);
|
||||
if (mu != nil) { ms = mu; };
|
||||
//
|
||||
// #181: a non-named callee (N_UN TK_STAR deref of a *fn local,
|
||||
// `(*f)(...)`; or any other expression-as-callee shape) has no
|
||||
// leaf to resolve here — skip the SK_FN name-lookup and let the
|
||||
// fn-VALUE fallback below peel TPTR / dealias to TFN. Mirrors
|
||||
// harec check_autodereference at ref/harec/src/check.c:1566.
|
||||
// cgen post-#180+#185 already lowers the deref-call correctly,
|
||||
// so lifting the asserttyped bail is silent-SIGSEGV-safe.
|
||||
if (nm.len > 0) {
|
||||
let s: *sym = nil;
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
s = scopelookupprefer(c.cur, c.curmod, nm);
|
||||
} else {
|
||||
let ms: *sym = nil;
|
||||
if (callee.lhs != nil && callee.lhs.kind == nkind.N_IDENT) {
|
||||
ms = scopelookupprefer(c.cur, c.curmod, callee.lhs.str);
|
||||
if (ms != nil && ms.skind != skind.SK_USE) {
|
||||
let mu: *sym = scopelookupuselocal(ms.scope, callee.lhs.str);
|
||||
if (mu != nil) { ms = mu; };
|
||||
};
|
||||
};
|
||||
if (ms != nil && ms.skind == skind.SK_USE) {
|
||||
s = scopelookupinmodule(c.cur, callee.lhs.str, nm);
|
||||
} else {
|
||||
s = scopelookup(c.cur, nm);
|
||||
};
|
||||
};
|
||||
if (ms != nil && ms.skind == skind.SK_USE) {
|
||||
s = scopelookupinmodule(c.cur, callee.lhs.str, nm);
|
||||
} else {
|
||||
s = scopelookup(c.cur, nm);
|
||||
};
|
||||
if (s != nil) { if (s.skind == skind.SK_FN) { if (s.decl != nil) {
|
||||
// fn-decl's lhs is the return-type AST node. Mirrors cstage
|
||||
// cmd/wcc/check.c:984+ regular-CALL `n->type =
|
||||
// build_fn_type(c, s->decl)->ret` shape.
|
||||
e.type_ = tinfofornode(c, s.decl.lhs): *void;
|
||||
return s.decl.lhs;
|
||||
}; }; };
|
||||
};
|
||||
if (s != nil) { if (s.skind == skind.SK_FN) { if (s.decl != nil) {
|
||||
// fn-decl's lhs is the return-type AST node. Mirrors cstage
|
||||
// cmd/wcc/check.c:984+ regular-CALL `n->type =
|
||||
// build_fn_type(c, s->decl)->ret` shape.
|
||||
e.type_ = tinfofornode(c, s.decl.lhs): *void;
|
||||
return s.decl.lhs;
|
||||
}; }; };
|
||||
// A callee that is a fn-VALUE — a fn-pointer struct field
|
||||
// (`w.emit(...)`), local, or param — has no free SK_FN entry, so
|
||||
// the name lookup above misses. Read the result off the checked
|
||||
|
||||
Reference in New Issue
Block a user