wcc/check: #14 nominal typeeqast (aliassym) closes A6 cross-module variant identity (wwstage)
typeeqast's N_TNAME arm compared variant types by SURFACE string (streq(aa.str, bb.str)), so a cross-module type referenced bare (oserror) vs qualified (os.oserror) mis-compared unequal -> A6: concrete->tagged silently mis-identified the variant. Resolve each name to its canonical type sym before comparing: keep the streq fast-path, else aliassym(c,aa)==aliassym(c,bb) (ww's existing resolver maps bare [#53] and qualified [#51] to the same SK_TYPE sym). AST analog of cstage type.c:278 TY_NAMED a==b / harec types.c:579 ident_equal -- NO interning. `c` threaded into 21 typeeqast sites. B-full Layer 1: closes A6/#14; Layer 2 (A7 tagged->tagged subset reject) stays deferred to the #199b flatten arc. Byte-id-neutral; graduates shlex #59.15 (989 M_WWREJECT->M_ID). test/wcc/839 pins both-stage symmetry (discriminating teeth = 989 #59.15, per 839 doc).
This commit is contained in:
@@ -11121,23 +11121,33 @@ fn resolvealias(c: *checker, n: *node) *node = {
|
||||
|
||||
// typeeqast — structural equality on AST type expressions, mod
|
||||
// the `!` wrapper. Mirrors variant_match in cgen + check.c: NAMED
|
||||
// types compare by string (the closest stand-in for pointer
|
||||
// identity at the AST level); other nodes recurse by kind.
|
||||
fn typeeqast(a: *node, b: *node) bool = {
|
||||
// types compare by string fast-path, else by resolved-decl identity
|
||||
// (the AST analog of cstage type.c:278 `TY_NAMED: a == b` and harec
|
||||
// types.c:579 `STORAGE_ALIAS: ident_equal`). #14 B-full Layer 1:
|
||||
// bare `oserror` vs qualified `os.oserror` resolve to the SAME
|
||||
// SK_TYPE sym (aliassym maps both via #51/#53), so a cross-module
|
||||
// nominal forward compares equal where the surface streq said false.
|
||||
fn typeeqast(c: *checker, a: *node, b: *node) bool = {
|
||||
let aa: *node = unwrapbang(a);
|
||||
let bb: *node = unwrapbang(b);
|
||||
if (aa == nil) { return bb == nil; };
|
||||
if (bb == nil) { return false; };
|
||||
if (aa.kind != bb.kind) { return false; };
|
||||
let k: nkind = aa.kind;
|
||||
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
|
||||
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TNAME) {
|
||||
if (streq(aa.str, bb.str)) { return true; };
|
||||
let sa: *sym = aliassym(c, aa);
|
||||
let sb: *sym = aliassym(c, bb);
|
||||
if (sa != nil && sa == sb) { return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TFN) {
|
||||
// Divergence: cstage type.c:239 compares resolved Type; we
|
||||
// compare AST. See #178.
|
||||
if (!typeeqast(aa.lhs, bb.lhs)) { return false; };
|
||||
if (!typeeqast(c, aa.lhs, bb.lhs)) { return false; };
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
@@ -11149,7 +11159,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let va: bool = pa.op == tkind.TK_ELLIPSIS;
|
||||
let vb: bool = pb.op == tkind.TK_ELLIPSIS;
|
||||
if (va != vb) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
};
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
@@ -11168,7 +11178,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -11199,7 +11209,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
if (!typeeqast(c, pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -12492,7 +12502,7 @@ fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||
if (ru) {
|
||||
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||
};
|
||||
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||
if (typeeqast(c, ltn, rtn)) { return ltn; };
|
||||
// Mismatched typed pair — return ltn so the binop stamps something;
|
||||
// 5-lite-b: the trailing nil-on-mismatch shape was eliminated when
|
||||
// the helper was split out of binoptype.
|
||||
@@ -12568,7 +12578,7 @@ fn binoptype(c: *checker, e: *node) *node = {
|
||||
// broad differing-types flip (typeeqast vs cstage type_eq
|
||||
// asymmetry risk) stays out.
|
||||
if (varianterr(c, ltn) || varianterr(c, rtn)) {
|
||||
if (!typeeqast(ltn, rtn)) {
|
||||
if (!typeeqast(c, ltn, rtn)) {
|
||||
deffolderr(c, e, "operands have differing types");
|
||||
};
|
||||
};
|
||||
@@ -13994,7 +14004,7 @@ fn addrfnptrmatches(c: *checker, ptr: *node, synth: *node) bool = {
|
||||
let ref: *node = resolvealias(c, unwrapbang(pu.lhs));
|
||||
if (ref == nil) { return false; };
|
||||
if (ref.kind != nkind.N_TFN) { return false; };
|
||||
return typeeqast(synth, ref);
|
||||
return typeeqast(c, synth, ref);
|
||||
};
|
||||
|
||||
// assignableaddrfn — project #206 Option C gate. Mirror of cstage
|
||||
@@ -14060,7 +14070,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let su: *node = resolvealias(c, unwrapbang(src));
|
||||
if (du == nil) { *confident = false; return true; };
|
||||
if (su == nil) { *confident = false; return true; };
|
||||
if (typeeqast(du, su)) { return true; };
|
||||
if (typeeqast(c, du, su)) { return true; };
|
||||
// #258: implicit [N]T -> []T array-to-slice borrow. Hare admits an
|
||||
// array with a defined length wherever its element slice is expected
|
||||
// (ref/harec/src/types.c:1080-1097, the SLICE-dst arm). Element types
|
||||
@@ -14070,7 +14080,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// explicit full slice via desugararrayslice; cgen is untouched.
|
||||
if (du.kind == nkind.N_TSLICE) {
|
||||
if (su.kind == nkind.N_TARRAY) {
|
||||
if (typeeqast(du.lhs, su.lhs)) { return true; };
|
||||
if (typeeqast(c, du.lhs, su.lhs)) { return true; };
|
||||
return false;
|
||||
};
|
||||
};
|
||||
@@ -14201,7 +14211,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) { return true; };
|
||||
@@ -14228,7 +14238,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
@@ -14375,12 +14385,12 @@ fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (typeeqast(c, cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (typeeqast(c, alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
@@ -14427,7 +14437,7 @@ fn casevariantin(c: *checker, tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (typeeqast(c, v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
@@ -14602,7 +14612,7 @@ fn taggedarrayvariantctor(c: *checker, dst: *node, src: *node) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return false; };
|
||||
if (typeeqast(c, v, src)) { return false; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) {
|
||||
@@ -14822,7 +14832,7 @@ fn desugararrayslice(c: *checker, dsttn: *node, srctn: *node, val: *node) *node
|
||||
if (su == nil) { return val; };
|
||||
if (du.kind != nkind.N_TSLICE) { return val; };
|
||||
if (su.kind != nkind.N_TARRAY) { return val; };
|
||||
if (!typeeqast(du.lhs, su.lhs)) { return val; };
|
||||
if (!typeeqast(c, du.lhs, su.lhs)) { return val; };
|
||||
let sl: *node = newnode(nkind.N_SLICE, val.file, val.line, val.col);
|
||||
sl.lhs = val; // sliced base; lo (.rhs) / hi (.cond) nil → 0 : len(arr)
|
||||
let slt: *node = newnode(nkind.N_TSLICE, "", 0, 0);
|
||||
@@ -14898,7 +14908,7 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
||||
let au: *node = resolvealias(c, unwrapbang(atype));
|
||||
if (pu != nil) { if (au != nil) {
|
||||
if (pu.kind == nkind.N_TSLICE) { if (au.kind == nkind.N_TARRAY) {
|
||||
if (!typeeqast(pu.lhs, au.lhs)) {
|
||||
if (!typeeqast(c, pu.lhs, au.lhs)) {
|
||||
errnotassign(c, param.lhs, atype, "argument");
|
||||
};
|
||||
}; };
|
||||
@@ -15433,7 +15443,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
let found: bool = false;
|
||||
let rv: *node = r.list;
|
||||
for (rv != nil) {
|
||||
if (typeeqast(rv, ev)) {
|
||||
if (typeeqast(c, rv, ev)) {
|
||||
found = true;
|
||||
rv = nil;
|
||||
} else { rv = rv.next; };
|
||||
|
||||
@@ -840,23 +840,33 @@ fn resolvealias(c: *checker, n: *node) *node = {
|
||||
|
||||
// typeeqast — structural equality on AST type expressions, mod
|
||||
// the `!` wrapper. Mirrors variant_match in cgen + check.c: NAMED
|
||||
// types compare by string (the closest stand-in for pointer
|
||||
// identity at the AST level); other nodes recurse by kind.
|
||||
fn typeeqast(a: *node, b: *node) bool = {
|
||||
// types compare by string fast-path, else by resolved-decl identity
|
||||
// (the AST analog of cstage type.c:278 `TY_NAMED: a == b` and harec
|
||||
// types.c:579 `STORAGE_ALIAS: ident_equal`). #14 B-full Layer 1:
|
||||
// bare `oserror` vs qualified `os.oserror` resolve to the SAME
|
||||
// SK_TYPE sym (aliassym maps both via #51/#53), so a cross-module
|
||||
// nominal forward compares equal where the surface streq said false.
|
||||
fn typeeqast(c: *checker, a: *node, b: *node) bool = {
|
||||
let aa: *node = unwrapbang(a);
|
||||
let bb: *node = unwrapbang(b);
|
||||
if (aa == nil) { return bb == nil; };
|
||||
if (bb == nil) { return false; };
|
||||
if (aa.kind != bb.kind) { return false; };
|
||||
let k: nkind = aa.kind;
|
||||
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
|
||||
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TNAME) {
|
||||
if (streq(aa.str, bb.str)) { return true; };
|
||||
let sa: *sym = aliassym(c, aa);
|
||||
let sb: *sym = aliassym(c, bb);
|
||||
if (sa != nil && sa == sb) { return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TFN) {
|
||||
// Divergence: cstage type.c:239 compares resolved Type; we
|
||||
// compare AST. See #178.
|
||||
if (!typeeqast(aa.lhs, bb.lhs)) { return false; };
|
||||
if (!typeeqast(c, aa.lhs, bb.lhs)) { return false; };
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
@@ -868,7 +878,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let va: bool = pa.op == tkind.TK_ELLIPSIS;
|
||||
let vb: bool = pb.op == tkind.TK_ELLIPSIS;
|
||||
if (va != vb) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
};
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
@@ -887,7 +897,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -918,7 +928,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
if (!typeeqast(c, pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -2211,7 +2221,7 @@ fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||
if (ru) {
|
||||
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||
};
|
||||
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||
if (typeeqast(c, ltn, rtn)) { return ltn; };
|
||||
// Mismatched typed pair — return ltn so the binop stamps something;
|
||||
// 5-lite-b: the trailing nil-on-mismatch shape was eliminated when
|
||||
// the helper was split out of binoptype.
|
||||
@@ -2287,7 +2297,7 @@ fn binoptype(c: *checker, e: *node) *node = {
|
||||
// broad differing-types flip (typeeqast vs cstage type_eq
|
||||
// asymmetry risk) stays out.
|
||||
if (varianterr(c, ltn) || varianterr(c, rtn)) {
|
||||
if (!typeeqast(ltn, rtn)) {
|
||||
if (!typeeqast(c, ltn, rtn)) {
|
||||
deffolderr(c, e, "operands have differing types");
|
||||
};
|
||||
};
|
||||
@@ -3713,7 +3723,7 @@ fn addrfnptrmatches(c: *checker, ptr: *node, synth: *node) bool = {
|
||||
let ref: *node = resolvealias(c, unwrapbang(pu.lhs));
|
||||
if (ref == nil) { return false; };
|
||||
if (ref.kind != nkind.N_TFN) { return false; };
|
||||
return typeeqast(synth, ref);
|
||||
return typeeqast(c, synth, ref);
|
||||
};
|
||||
|
||||
// assignableaddrfn — project #206 Option C gate. Mirror of cstage
|
||||
@@ -3779,7 +3789,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let su: *node = resolvealias(c, unwrapbang(src));
|
||||
if (du == nil) { *confident = false; return true; };
|
||||
if (su == nil) { *confident = false; return true; };
|
||||
if (typeeqast(du, su)) { return true; };
|
||||
if (typeeqast(c, du, su)) { return true; };
|
||||
// #258: implicit [N]T -> []T array-to-slice borrow. Hare admits an
|
||||
// array with a defined length wherever its element slice is expected
|
||||
// (ref/harec/src/types.c:1080-1097, the SLICE-dst arm). Element types
|
||||
@@ -3789,7 +3799,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// explicit full slice via desugararrayslice; cgen is untouched.
|
||||
if (du.kind == nkind.N_TSLICE) {
|
||||
if (su.kind == nkind.N_TARRAY) {
|
||||
if (typeeqast(du.lhs, su.lhs)) { return true; };
|
||||
if (typeeqast(c, du.lhs, su.lhs)) { return true; };
|
||||
return false;
|
||||
};
|
||||
};
|
||||
@@ -3920,7 +3930,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) { return true; };
|
||||
@@ -3947,7 +3957,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
@@ -4094,12 +4104,12 @@ fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (typeeqast(c, cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (typeeqast(c, alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
@@ -4146,7 +4156,7 @@ fn casevariantin(c: *checker, tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (typeeqast(c, v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
@@ -4321,7 +4331,7 @@ fn taggedarrayvariantctor(c: *checker, dst: *node, src: *node) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return false; };
|
||||
if (typeeqast(c, v, src)) { return false; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) {
|
||||
@@ -4541,7 +4551,7 @@ fn desugararrayslice(c: *checker, dsttn: *node, srctn: *node, val: *node) *node
|
||||
if (su == nil) { return val; };
|
||||
if (du.kind != nkind.N_TSLICE) { return val; };
|
||||
if (su.kind != nkind.N_TARRAY) { return val; };
|
||||
if (!typeeqast(du.lhs, su.lhs)) { return val; };
|
||||
if (!typeeqast(c, du.lhs, su.lhs)) { return val; };
|
||||
let sl: *node = newnode(nkind.N_SLICE, val.file, val.line, val.col);
|
||||
sl.lhs = val; // sliced base; lo (.rhs) / hi (.cond) nil → 0 : len(arr)
|
||||
let slt: *node = newnode(nkind.N_TSLICE, "", 0, 0);
|
||||
@@ -4617,7 +4627,7 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
||||
let au: *node = resolvealias(c, unwrapbang(atype));
|
||||
if (pu != nil) { if (au != nil) {
|
||||
if (pu.kind == nkind.N_TSLICE) { if (au.kind == nkind.N_TARRAY) {
|
||||
if (!typeeqast(pu.lhs, au.lhs)) {
|
||||
if (!typeeqast(c, pu.lhs, au.lhs)) {
|
||||
errnotassign(c, param.lhs, atype, "argument");
|
||||
};
|
||||
}; };
|
||||
@@ -5152,7 +5162,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
let found: bool = false;
|
||||
let rv: *node = r.list;
|
||||
for (rv != nil) {
|
||||
if (typeeqast(rv, ev)) {
|
||||
if (typeeqast(c, rv, ev)) {
|
||||
found = true;
|
||||
rv = nil;
|
||||
} else { rv = rv.next; };
|
||||
|
||||
@@ -11121,23 +11121,33 @@ fn resolvealias(c: *checker, n: *node) *node = {
|
||||
|
||||
// typeeqast — structural equality on AST type expressions, mod
|
||||
// the `!` wrapper. Mirrors variant_match in cgen + check.c: NAMED
|
||||
// types compare by string (the closest stand-in for pointer
|
||||
// identity at the AST level); other nodes recurse by kind.
|
||||
fn typeeqast(a: *node, b: *node) bool = {
|
||||
// types compare by string fast-path, else by resolved-decl identity
|
||||
// (the AST analog of cstage type.c:278 `TY_NAMED: a == b` and harec
|
||||
// types.c:579 `STORAGE_ALIAS: ident_equal`). #14 B-full Layer 1:
|
||||
// bare `oserror` vs qualified `os.oserror` resolve to the SAME
|
||||
// SK_TYPE sym (aliassym maps both via #51/#53), so a cross-module
|
||||
// nominal forward compares equal where the surface streq said false.
|
||||
fn typeeqast(c: *checker, a: *node, b: *node) bool = {
|
||||
let aa: *node = unwrapbang(a);
|
||||
let bb: *node = unwrapbang(b);
|
||||
if (aa == nil) { return bb == nil; };
|
||||
if (bb == nil) { return false; };
|
||||
if (aa.kind != bb.kind) { return false; };
|
||||
let k: nkind = aa.kind;
|
||||
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
|
||||
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TNAME) {
|
||||
if (streq(aa.str, bb.str)) { return true; };
|
||||
let sa: *sym = aliassym(c, aa);
|
||||
let sb: *sym = aliassym(c, bb);
|
||||
if (sa != nil && sa == sb) { return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TSLICE){ return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TCHAN) { return typeeqast(c, aa.lhs, bb.lhs); };
|
||||
if (k == nkind.N_TFN) {
|
||||
// Divergence: cstage type.c:239 compares resolved Type; we
|
||||
// compare AST. See #178.
|
||||
if (!typeeqast(aa.lhs, bb.lhs)) { return false; };
|
||||
if (!typeeqast(c, aa.lhs, bb.lhs)) { return false; };
|
||||
let pa: *node = aa.list;
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
@@ -11149,7 +11159,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let va: bool = pa.op == tkind.TK_ELLIPSIS;
|
||||
let vb: bool = pb.op == tkind.TK_ELLIPSIS;
|
||||
if (va != vb) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
};
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
@@ -11168,7 +11178,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
let pb: *node = bb.list;
|
||||
for (pa != nil) {
|
||||
if (pb == nil) { return false; };
|
||||
if (!typeeqast(pa.lhs, pb.lhs)) { return false; };
|
||||
if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -11199,7 +11209,7 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
// lands; b1c's (void|size) has none, so byte-id is untouched.
|
||||
if (pa.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (pb.op == tkind.TK_ELLIPSIS) { return false; };
|
||||
if (!typeeqast(pa, pb)) { return false; };
|
||||
if (!typeeqast(c, pa, pb)) { return false; };
|
||||
pa = pa.next;
|
||||
pb = pb.next;
|
||||
};
|
||||
@@ -12492,7 +12502,7 @@ fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||
if (ru) {
|
||||
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||
};
|
||||
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||
if (typeeqast(c, ltn, rtn)) { return ltn; };
|
||||
// Mismatched typed pair — return ltn so the binop stamps something;
|
||||
// 5-lite-b: the trailing nil-on-mismatch shape was eliminated when
|
||||
// the helper was split out of binoptype.
|
||||
@@ -12568,7 +12578,7 @@ fn binoptype(c: *checker, e: *node) *node = {
|
||||
// broad differing-types flip (typeeqast vs cstage type_eq
|
||||
// asymmetry risk) stays out.
|
||||
if (varianterr(c, ltn) || varianterr(c, rtn)) {
|
||||
if (!typeeqast(ltn, rtn)) {
|
||||
if (!typeeqast(c, ltn, rtn)) {
|
||||
deffolderr(c, e, "operands have differing types");
|
||||
};
|
||||
};
|
||||
@@ -13994,7 +14004,7 @@ fn addrfnptrmatches(c: *checker, ptr: *node, synth: *node) bool = {
|
||||
let ref: *node = resolvealias(c, unwrapbang(pu.lhs));
|
||||
if (ref == nil) { return false; };
|
||||
if (ref.kind != nkind.N_TFN) { return false; };
|
||||
return typeeqast(synth, ref);
|
||||
return typeeqast(c, synth, ref);
|
||||
};
|
||||
|
||||
// assignableaddrfn — project #206 Option C gate. Mirror of cstage
|
||||
@@ -14060,7 +14070,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let su: *node = resolvealias(c, unwrapbang(src));
|
||||
if (du == nil) { *confident = false; return true; };
|
||||
if (su == nil) { *confident = false; return true; };
|
||||
if (typeeqast(du, su)) { return true; };
|
||||
if (typeeqast(c, du, su)) { return true; };
|
||||
// #258: implicit [N]T -> []T array-to-slice borrow. Hare admits an
|
||||
// array with a defined length wherever its element slice is expected
|
||||
// (ref/harec/src/types.c:1080-1097, the SLICE-dst arm). Element types
|
||||
@@ -14070,7 +14080,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// explicit full slice via desugararrayslice; cgen is untouched.
|
||||
if (du.kind == nkind.N_TSLICE) {
|
||||
if (su.kind == nkind.N_TARRAY) {
|
||||
if (typeeqast(du.lhs, su.lhs)) { return true; };
|
||||
if (typeeqast(c, du.lhs, su.lhs)) { return true; };
|
||||
return false;
|
||||
};
|
||||
};
|
||||
@@ -14201,7 +14211,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) { return true; };
|
||||
@@ -14228,7 +14238,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TTAGGED) {
|
||||
if (typeeqast(v, src)) { return true; };
|
||||
if (typeeqast(c, v, src)) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
@@ -14375,12 +14385,12 @@ fn taggeddefmod(c: *checker, st: *node) str = {
|
||||
|
||||
fn casecovers(c: *checker, cs: *node, want: *node, unionmod: str) bool = {
|
||||
if (cs.lhs != nil) {
|
||||
if (typeeqast(cs.lhs, want)) { return true; };
|
||||
if (typeeqast(c, cs.lhs, want)) { return true; };
|
||||
if (casevariantpairmatch(want, cs.lhs, unionmod)) { return true; };
|
||||
};
|
||||
let alt: *node = cs.list;
|
||||
for (alt != nil) {
|
||||
if (typeeqast(alt, want)) { return true; };
|
||||
if (typeeqast(c, alt, want)) { return true; };
|
||||
if (casevariantpairmatch(want, alt, unionmod)) { return true; };
|
||||
alt = alt.next;
|
||||
};
|
||||
@@ -14427,7 +14437,7 @@ fn casevariantin(c: *checker, tagged: *node, pat: *node, unionmod: str) bool = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (typeeqast(v, pat)) { return true; };
|
||||
if (typeeqast(c, v, pat)) { return true; };
|
||||
if (casevariantpairmatch(v, pat, unionmod)) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
@@ -14602,7 +14612,7 @@ fn taggedarrayvariantctor(c: *checker, dst: *node, src: *node) bool = {
|
||||
let vtagged: bool = false;
|
||||
if (vu != nil) { if (vu.kind == nkind.N_TTAGGED) { vtagged = true; }; };
|
||||
if (vtagged && !vspread) {
|
||||
if (typeeqast(v, src)) { return false; };
|
||||
if (typeeqast(c, v, src)) { return false; };
|
||||
} else {
|
||||
let innerconf: bool = false;
|
||||
if (isassignable(c, v, src, &innerconf)) {
|
||||
@@ -14822,7 +14832,7 @@ fn desugararrayslice(c: *checker, dsttn: *node, srctn: *node, val: *node) *node
|
||||
if (su == nil) { return val; };
|
||||
if (du.kind != nkind.N_TSLICE) { return val; };
|
||||
if (su.kind != nkind.N_TARRAY) { return val; };
|
||||
if (!typeeqast(du.lhs, su.lhs)) { return val; };
|
||||
if (!typeeqast(c, du.lhs, su.lhs)) { return val; };
|
||||
let sl: *node = newnode(nkind.N_SLICE, val.file, val.line, val.col);
|
||||
sl.lhs = val; // sliced base; lo (.rhs) / hi (.cond) nil → 0 : len(arr)
|
||||
let slt: *node = newnode(nkind.N_TSLICE, "", 0, 0);
|
||||
@@ -14898,7 +14908,7 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
||||
let au: *node = resolvealias(c, unwrapbang(atype));
|
||||
if (pu != nil) { if (au != nil) {
|
||||
if (pu.kind == nkind.N_TSLICE) { if (au.kind == nkind.N_TARRAY) {
|
||||
if (!typeeqast(pu.lhs, au.lhs)) {
|
||||
if (!typeeqast(c, pu.lhs, au.lhs)) {
|
||||
errnotassign(c, param.lhs, atype, "argument");
|
||||
};
|
||||
}; };
|
||||
@@ -15433,7 +15443,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
let found: bool = false;
|
||||
let rv: *node = r.list;
|
||||
for (rv != nil) {
|
||||
if (typeeqast(rv, ev)) {
|
||||
if (typeeqast(c, rv, ev)) {
|
||||
found = true;
|
||||
rv = nil;
|
||||
} else { rv = rv.next; };
|
||||
|
||||
Reference in New Issue
Block a user