wcc/ww: exprtype stamps bare fn rvalue with its fn type, not return type
For an SK_FN sym, exprtype's N_IDENT and N_DOT arms returned decl.lhs (the return type), so a bare fn rvalue compared as its return type — latent silent mis-accept of mismatched-signature fn assignment (the 706/768 over-reject under any general check was the visible face). Synthesize the N_TFN instead (mirror of assignableaddrfn's synth), and add the N_TFN-vs-N_TFN confident-mismatch reject in isassignable. harec: resolve_function check.c:4279-4288 (obj->type=fntype), EXP_ACCESS check.c:341-343 (bare ident yields obj->type, no decay), call check.c:1573, assignability types.c:1001; cstage twin check.c:1313 + build_fn_type check.c:2611. cgen is name-keyed on fn rvalues (never reads the stamp): zero asm delta, byte-id held.
This commit is contained in:
@@ -2685,6 +2685,25 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
||||
if (s == nil) { return nil; };
|
||||
if (s.decl == nil) { return nil; };
|
||||
// #34: a bare fn-name rvalue types as its FN TYPE, not its return
|
||||
// type. decl.lhs is the RETURN type for an N_FNDECL, so synthesize
|
||||
// the N_TFN over (ret=decl.lhs, params=decl.list) — the shape
|
||||
// assignableaddrfn builds (:3841). Mirrors cstage: build_fn_type at
|
||||
// fn-decl install (cmd/wcc/check.c:2915/2931) stored on the sym and
|
||||
// returned verbatim by cexpr N_IDENT (check.c:1313); harec EXP_ACCESS
|
||||
// yields the fn object's type with NO decay (ref/harec/src/check.c
|
||||
// :341-343; the fn obj is built .storage=STORAGE_FUNCTION at :4279-
|
||||
// 4288, assignable iff dealias-equal fn types, types.c:1001). Was the
|
||||
// root of the #24 fn-family over-rejects (`let p: fn()i32 = g` compared
|
||||
// i32 vs the fn type). cgen lowers a fn rvalue name-keyed via
|
||||
// fnretlookup (cgenexpr.ww:1100), never off this stamp → byte-id-neutral.
|
||||
if (s.skind == skind.SK_FN) {
|
||||
let ft: *node = newnode(nkind.N_TFN, "", 0, 0);
|
||||
ft.lhs = s.decl.lhs;
|
||||
ft.list = s.decl.list;
|
||||
e.type_ = tinfofornode(c, ft): *void;
|
||||
return ft;
|
||||
};
|
||||
let t: *node = s.decl.lhs;
|
||||
// Propagate the declared type's tinfo onto the use site so
|
||||
// downstream cgen walkers can read n.type_ off an ident.
|
||||
@@ -3176,6 +3195,17 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
||||
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
||||
if (fs != nil) { if (fs.decl != nil) {
|
||||
// #34: a module-qualified bare fn rvalue `mod.fn` types as
|
||||
// its FN TYPE (twin of the N_IDENT arm, :2688); decl.lhs is
|
||||
// the RETURN type for an N_FNDECL. Pins 706 (`let p1: fn()i32
|
||||
// = mod1.ping`).
|
||||
if (fs.skind == skind.SK_FN) {
|
||||
let ft: *node = newnode(nkind.N_TFN, "", 0, 0);
|
||||
ft.lhs = fs.decl.lhs;
|
||||
ft.list = fs.decl.list;
|
||||
e.type_ = tinfofornode(c, ft): *void;
|
||||
return ft;
|
||||
};
|
||||
let tn: *node = fs.decl.lhs;
|
||||
if (tn != nil) {
|
||||
e.type_ = tinfofornode(c, tn): *void;
|
||||
@@ -4145,6 +4175,21 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #34: two bare fn types reaching here are NOT structurally equal
|
||||
// (typeeqast returned true at the top otherwise) — the fn signatures
|
||||
// differ, a confident reject mirroring cstage's structural fn
|
||||
// type_assignable (`init fn() str not assignable to declared fn() i32`;
|
||||
// harec types.c:1001 dealias-equal fn types). Manifests only now that
|
||||
// S1/S2 stamp a bare fn rvalue with its fn type: `let p: fn()i32 = h`
|
||||
// (h: fn()str) was a silent mis-accept via the lenient catch-all below.
|
||||
// The matched-sig case already returned true via typeeqast at the top.
|
||||
// The `&fn` (*fn) vs bare-fn KIND mismatch (du N_TFN, su N_TPTR) is a
|
||||
// different shape, closed by c3's aggregate-kind reject, not here.
|
||||
if (du.kind == nkind.N_TFN) {
|
||||
if (su.kind == nkind.N_TFN) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
// Anything else: don't claim confidence.
|
||||
*confident = false;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user