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:
@@ -13105,6 +13105,25 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == 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;
|
let t: *node = s.decl.lhs;
|
||||||
// Propagate the declared type's tinfo onto the use site so
|
// Propagate the declared type's tinfo onto the use site so
|
||||||
// downstream cgen walkers can read n.type_ off an ident.
|
// downstream cgen walkers can read n.type_ off an ident.
|
||||||
@@ -13596,6 +13615,17 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
||||||
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
||||||
if (fs != nil) { if (fs.decl != nil) {
|
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;
|
let tn: *node = fs.decl.lhs;
|
||||||
if (tn != nil) {
|
if (tn != nil) {
|
||||||
e.type_ = tinfofornode(c, tn): *void;
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
@@ -14565,6 +14595,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.
|
// Anything else: don't claim confidence.
|
||||||
*confident = false;
|
*confident = false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2685,6 +2685,25 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == 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;
|
let t: *node = s.decl.lhs;
|
||||||
// Propagate the declared type's tinfo onto the use site so
|
// Propagate the declared type's tinfo onto the use site so
|
||||||
// downstream cgen walkers can read n.type_ off an ident.
|
// 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) {
|
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
||||||
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
||||||
if (fs != nil) { if (fs.decl != nil) {
|
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;
|
let tn: *node = fs.decl.lhs;
|
||||||
if (tn != nil) {
|
if (tn != nil) {
|
||||||
e.type_ = tinfofornode(c, tn): *void;
|
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.
|
// Anything else: don't claim confidence.
|
||||||
*confident = false;
|
*confident = false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -13105,6 +13105,25 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
let s: *sym = scopelookupprefer(c.cur, c.curmod, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == 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;
|
let t: *node = s.decl.lhs;
|
||||||
// Propagate the declared type's tinfo onto the use site so
|
// Propagate the declared type's tinfo onto the use site so
|
||||||
// downstream cgen walkers can read n.type_ off an ident.
|
// downstream cgen walkers can read n.type_ off an ident.
|
||||||
@@ -13596,6 +13615,17 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
if (ms.skind == skind.SK_USE || ms.use_alias != 0i32) {
|
||||||
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
let fs: *sym = scopelookupinmodule(c.cur, lhsn.str, e.str);
|
||||||
if (fs != nil) { if (fs.decl != nil) {
|
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;
|
let tn: *node = fs.decl.lhs;
|
||||||
if (tn != nil) {
|
if (tn != nil) {
|
||||||
e.type_ = tinfofornode(c, tn): *void;
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
@@ -14565,6 +14595,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.
|
// Anything else: don't claim confidence.
|
||||||
*confident = false;
|
*confident = false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user