diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 88948782..f2181347 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -12327,14 +12327,33 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { s = scopelookup(c.cur, nm); }; }; - if (s == nil) { return nil; }; - if (s.skind != skind.SK_FN) { return nil; }; - if (s.decl == nil) { return 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 + // callee node's own type instead: autodereference + dealias to + // the TY_FN, then take its result. Mirrors harec's check_expr_call + // `expr->result = type_dealias(check_autodereference(lvalue-> + // result))->func.result` (ref/harec/src/check.c:1566-1581). The + // name path stays primary because a fn-NAME callee node in wwstage + // already carries its RETURN type (fn-decl.lhs), not its fn-type — + // so a `fn make() fn() void` callee would otherwise mis-yield void. + let ct: *node = resolvealias(c, unwrapbang(exprtype(c, callee, nil))); + for (ct != nil && ct.kind == nkind.N_TPTR) { + ct = resolvealias(c, unwrapbang(ct.lhs)); + }; + if (ct != nil) { if (ct.kind == nkind.N_TFN) { + let res: *node = ct.lhs; + e.type_ = tinfofornode(c, res): *void; + return res; + }; }; + return nil; }; if (k == nkind.N_DOT) { // A.6.1.5a — fold cases only. Mirrors cstage cmd/wcc/check.c diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 913ad10e..db5747b7 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -2297,14 +2297,33 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { s = scopelookup(c.cur, nm); }; }; - if (s == nil) { return nil; }; - if (s.skind != skind.SK_FN) { return nil; }; - if (s.decl == nil) { return 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 + // callee node's own type instead: autodereference + dealias to + // the TY_FN, then take its result. Mirrors harec's check_expr_call + // `expr->result = type_dealias(check_autodereference(lvalue-> + // result))->func.result` (ref/harec/src/check.c:1566-1581). The + // name path stays primary because a fn-NAME callee node in wwstage + // already carries its RETURN type (fn-decl.lhs), not its fn-type — + // so a `fn make() fn() void` callee would otherwise mis-yield void. + let ct: *node = resolvealias(c, unwrapbang(exprtype(c, callee, nil))); + for (ct != nil && ct.kind == nkind.N_TPTR) { + ct = resolvealias(c, unwrapbang(ct.lhs)); + }; + if (ct != nil) { if (ct.kind == nkind.N_TFN) { + let res: *node = ct.lhs; + e.type_ = tinfofornode(c, res): *void; + return res; + }; }; + return nil; }; if (k == nkind.N_DOT) { // A.6.1.5a — fold cases only. Mirrors cstage cmd/wcc/check.c diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 96ca22e2..10833299 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -12327,14 +12327,33 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { s = scopelookup(c.cur, nm); }; }; - if (s == nil) { return nil; }; - if (s.skind != skind.SK_FN) { return nil; }; - if (s.decl == nil) { return 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 + // callee node's own type instead: autodereference + dealias to + // the TY_FN, then take its result. Mirrors harec's check_expr_call + // `expr->result = type_dealias(check_autodereference(lvalue-> + // result))->func.result` (ref/harec/src/check.c:1566-1581). The + // name path stays primary because a fn-NAME callee node in wwstage + // already carries its RETURN type (fn-decl.lhs), not its fn-type — + // so a `fn make() fn() void` callee would otherwise mis-yield void. + let ct: *node = resolvealias(c, unwrapbang(exprtype(c, callee, nil))); + for (ct != nil && ct.kind == nkind.N_TPTR) { + ct = resolvealias(c, unwrapbang(ct.lhs)); + }; + if (ct != nil) { if (ct.kind == nkind.N_TFN) { + let res: *node = ct.lhs; + e.type_ = tinfofornode(c, res): *void; + return res; + }; }; + return nil; }; if (k == nkind.N_DOT) { // A.6.1.5a — fold cases only. Mirrors cstage cmd/wcc/check.c diff --git a/test/wcc/901_asserttyped_gap.c b/test/wcc/901_asserttyped_gap.c index afd5b77a..0d252a71 100644 --- a/test/wcc/901_asserttyped_gap.c +++ b/test/wcc/901_asserttyped_gap.c @@ -21,7 +21,7 @@ * * Gap classes (counts verified empirically at this revision): * A module-qual N_DOT call result checked_test 0 (closed) - * B fn-ptr struct-field call smoke 3 + * B fn-ptr struct-field call smoke 0 (closed) * C abort intrinsic callee utf8 8 * D module-leaf == type/fn name fnmatch 0 (closed) * D module-leaf == type/fn name random 0 (closed) @@ -109,7 +109,7 @@ main(void) { "lib/math/checked/checked_test.combined.ww", "A module-qual N_DOT call result", 0 }, { "selfhost/test/smoke.combined.ww", - "B fn-ptr struct-field call", 3 }, + "B fn-ptr struct-field call", 0 }, { "lib/encoding/utf8/utf8.combined.ww", "C abort intrinsic callee", 8 }, { "lib/fnmatch/fnmatchtest.combined.ww", @@ -151,6 +151,6 @@ main(void) return 1; } printf("asserttyped_gap: ww-stage checker warn set matches manifest " - "on %d gap-corpus fixtures (B+C pinned, A+D closed)\n", n); + "on %d gap-corpus fixtures (C pinned, A+B+D closed)\n", n); return 0; }