|
|
|
|
@@ -20,11 +20,9 @@
|
|
|
|
|
package wcc;
|
|
|
|
|
|
|
|
|
|
import os;
|
|
|
|
|
import mem;
|
|
|
|
|
import tok;
|
|
|
|
|
|
|
|
|
|
type checker = struct {
|
|
|
|
|
a: *arena,
|
|
|
|
|
tc: *tctx,
|
|
|
|
|
top: *scope,
|
|
|
|
|
cur: *scope,
|
|
|
|
|
@@ -72,11 +70,11 @@ fn seedprimitives(c: *checker) void = {
|
|
|
|
|
// separate alias chain — see collectaliases in cgen.ww for the
|
|
|
|
|
// companion seed.
|
|
|
|
|
let empty: str;
|
|
|
|
|
let tnvoid: *node = newnode(c.a, nkind.N_TNAME, empty, 0, 0);
|
|
|
|
|
let tnvoid: *node = newnode(nkind.N_TNAME, empty, 0, 0);
|
|
|
|
|
tnvoid.str = "void";
|
|
|
|
|
let bang: *node = newnode(c.a, nkind.N_TBANG, empty, 0, 0);
|
|
|
|
|
let bang: *node = newnode(nkind.N_TBANG, empty, 0, 0);
|
|
|
|
|
bang.lhs = tnvoid;
|
|
|
|
|
let nomemdecl: *node = newnode(c.a, nkind.N_TYPEDECL, empty, 0, 0);
|
|
|
|
|
let nomemdecl: *node = newnode(nkind.N_TYPEDECL, empty, 0, 0);
|
|
|
|
|
nomemdecl.str = "nomem";
|
|
|
|
|
nomemdecl.lhs = bang;
|
|
|
|
|
scopedefine(c.top, "nomem", skind.SK_TYPE, nil, nomemdecl);
|
|
|
|
|
@@ -350,7 +348,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
|
|
|
|
if (k == nkind.N_MCASE) {
|
|
|
|
|
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
|
|
|
|
let outer: *scope = c.cur;
|
|
|
|
|
c.cur = newscope(c.a, outer);
|
|
|
|
|
c.cur = newscope(outer);
|
|
|
|
|
let nm: str = n.str;
|
|
|
|
|
if (nm.len > 0) {
|
|
|
|
|
checkmoduleshadow(c, nm, "binding");
|
|
|
|
|
@@ -372,7 +370,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
|
|
|
|
// Mirrors cstage cstmt N_BLOCK at cmd/wcc/check.c:1559-1566.
|
|
|
|
|
if (k == nkind.N_BLOCK) {
|
|
|
|
|
let outer: *scope = c.cur;
|
|
|
|
|
c.cur = newscope(c.a, outer);
|
|
|
|
|
c.cur = newscope(outer);
|
|
|
|
|
let m: *node = n.list;
|
|
|
|
|
for (m != nil) {
|
|
|
|
|
resolvewalk(c, m);
|
|
|
|
|
@@ -651,7 +649,7 @@ fn scruttype(c: *checker, e: *node) *node = {
|
|
|
|
|
// exprtype to return primitive type nodes for literal
|
|
|
|
|
// expressions. The arena keeps them around as long as the checker.
|
|
|
|
|
fn mktname(c: *checker, nm: str) *node = {
|
|
|
|
|
let n: *node = newnode(c.a, nkind.N_TNAME, "", 0, 0);
|
|
|
|
|
let n: *node = newnode(nkind.N_TNAME, "", 0, 0);
|
|
|
|
|
n.str = nm;
|
|
|
|
|
return n;
|
|
|
|
|
};
|
|
|
|
|
@@ -838,7 +836,7 @@ fn astoffset(c: *checker, dot: *node) i64 = {
|
|
|
|
|
// wwstage cgen only reads `uval` for N_INTLIT codegen so `str` is
|
|
|
|
|
// just for the AST printer, but set it for parity with the parser's
|
|
|
|
|
// own literal-emit shape.
|
|
|
|
|
fn arenau64tos(a: *arena, v: u64) str = {
|
|
|
|
|
fn arenau64tos(v: u64) str = {
|
|
|
|
|
let buf: []u8 = alloc([], 24u64)!;
|
|
|
|
|
let i: i32 = 23;
|
|
|
|
|
buf[i] = 0u8;
|
|
|
|
|
@@ -862,7 +860,7 @@ fn arenau64tos(a: *arena, v: u64) str = {
|
|
|
|
|
fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
|
|
|
|
n.kind = nkind.N_INTLIT;
|
|
|
|
|
n.uval = v: u64;
|
|
|
|
|
n.str = arenau64tos(c.a, v: u64);
|
|
|
|
|
n.str = arenau64tos(v: u64);
|
|
|
|
|
n.lhs = nil;
|
|
|
|
|
n.list = nil;
|
|
|
|
|
let empty: str;
|
|
|
|
|
@@ -1014,11 +1012,11 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
// site that needs iserror discrimination.
|
|
|
|
|
r = tinfofornode(c, n.lhs);
|
|
|
|
|
} else { if (k == nkind.N_TPTR) {
|
|
|
|
|
r = typeptr(c.a, tinfofornode(c, n.lhs));
|
|
|
|
|
r = typeptr(tinfofornode(c, n.lhs));
|
|
|
|
|
} else { if (k == nkind.N_TSLICE) {
|
|
|
|
|
r = typeslice(c.a, tinfofornode(c, n.lhs));
|
|
|
|
|
r = typeslice(tinfofornode(c, n.lhs));
|
|
|
|
|
} else { if (k == nkind.N_TCHAN) {
|
|
|
|
|
r = typechan(c.a, tinfofornode(c, n.lhs));
|
|
|
|
|
r = typechan(tinfofornode(c, n.lhs));
|
|
|
|
|
} else { if (k == nkind.N_TARRAY) {
|
|
|
|
|
// Cstage cmd/wcc/check.c:314-326: length must be an integer
|
|
|
|
|
// literal (`[_]T` keeps alen=0 as the inferred-length sentinel
|
|
|
|
|
@@ -1034,14 +1032,14 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
if (n.rhs.kind == nkind.N_INTLIT) { elen = n.rhs.uval; };
|
|
|
|
|
};
|
|
|
|
|
let sub: *tinfo = tinfofornode(c, n.lhs);
|
|
|
|
|
r = typearray(c.a, sub, elen);
|
|
|
|
|
r = typearray(sub, elen);
|
|
|
|
|
} else { if (k == nkind.N_TFN) {
|
|
|
|
|
// Cstage cmd/wcc/check.c:437-466: function types are 8B / 8B
|
|
|
|
|
// (call-target pointer shape). Pre-bind before recursing into
|
|
|
|
|
// the return type so a recursive `type F = fn() F` self-ref
|
|
|
|
|
// doesn't spin (cycle-break mirror of the TSTRUCT/TTAGGED
|
|
|
|
|
// pattern below).
|
|
|
|
|
r = newtype(c.a, tykind.TY_FN);
|
|
|
|
|
r = newtype(tykind.TY_FN);
|
|
|
|
|
r.size = 8u64;
|
|
|
|
|
r.align = 8u64;
|
|
|
|
|
r.slotsize = 8u64;
|
|
|
|
|
@@ -1052,7 +1050,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
// (default i32 = 4B/4B). Cgen's slotsize-TENUM fallback pads
|
|
|
|
|
// to 8B per its stack-slot contract; tinfo.size carries the
|
|
|
|
|
// raw storage width so size(EnumT) folds to the correct value.
|
|
|
|
|
r = newtype(c.a, tykind.TY_ENUM);
|
|
|
|
|
r = newtype(tykind.TY_ENUM);
|
|
|
|
|
let storage: *tinfo = nil;
|
|
|
|
|
if (n.lhs != nil) { storage = tinfofornode(c, n.lhs); };
|
|
|
|
|
if (storage == nil) { storage = c.tc.tyi32; };
|
|
|
|
|
@@ -1071,7 +1069,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
// slotsize TTUPLE — narrow scalars pad to 8 (cgen spills each
|
|
|
|
|
// tuple element into its own register / stack-slot eightbyte),
|
|
|
|
|
// composites contribute their own ti.slotsize.
|
|
|
|
|
r = newtype(c.a, tykind.TY_TUPLE);
|
|
|
|
|
r = newtype(tykind.TY_TUPLE);
|
|
|
|
|
tinfocachebind(c.tc, n, r);
|
|
|
|
|
let total: u64 = 0u64;
|
|
|
|
|
let slottotal: u64 = 0u64;
|
|
|
|
|
@@ -1109,7 +1107,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
// struct; size-derived alignment; final round to 8). That
|
|
|
|
|
// slot total lands in ti.slotsize so the cgen fast-path can
|
|
|
|
|
// graduate TY_STRUCT off the AST walker.
|
|
|
|
|
r = newtype(c.a, tykind.TY_STRUCT);
|
|
|
|
|
r = newtype(tykind.TY_STRUCT);
|
|
|
|
|
tinfocachebind(c.tc, n, r);
|
|
|
|
|
let off: u64 = 0u64;
|
|
|
|
|
let maxalign: u64 = 1u64;
|
|
|
|
|
@@ -1151,7 +1149,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|
|
|
|
// Cstage cmd/wcc/check.c:347-435: 8B tag + max(variant)
|
|
|
|
|
// rounded up to 8. Pre-bind for cycle protection (recursive
|
|
|
|
|
// sum-type shapes through NAMED variants).
|
|
|
|
|
r = newtype(c.a, tykind.TY_TAGGED);
|
|
|
|
|
r = newtype(tykind.TY_TAGGED);
|
|
|
|
|
tinfocachebind(c.tc, n, r);
|
|
|
|
|
// #61 A.3 nullable fold: `(*T | void)` collapses to a single
|
|
|
|
|
// 8B pointer slot, null is the void variant. Mirrors
|
|
|
|
|
@@ -1310,11 +1308,11 @@ fn exprtype(c: *checker, e: *node) *node = {
|
|
|
|
|
if (e.list.list == nil) {
|
|
|
|
|
if (e.list.next != nil) {
|
|
|
|
|
if (e.list.next.next == nil) {
|
|
|
|
|
let sl: *node = newnode(c.a, nkind.N_TSLICE, "", 0, 0);
|
|
|
|
|
let sl: *node = newnode(nkind.N_TSLICE, "", 0, 0);
|
|
|
|
|
sl.lhs = mktname(c, "u8");
|
|
|
|
|
let nome: *node = mktname(c, "nomem");
|
|
|
|
|
sl.next = nome;
|
|
|
|
|
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
tt.list = sl;
|
|
|
|
|
return tt;
|
|
|
|
|
};
|
|
|
|
|
@@ -1324,11 +1322,11 @@ fn exprtype(c: *checker, e: *node) *node = {
|
|
|
|
|
// Value form: `alloc(value)`.
|
|
|
|
|
if (e.list.next == nil) {
|
|
|
|
|
let argt: *node = exprtype(c, e.list);
|
|
|
|
|
let ptr: *node = newnode(c.a, nkind.N_TPTR, "", 0, 0);
|
|
|
|
|
let ptr: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
|
|
|
|
ptr.lhs = argt;
|
|
|
|
|
let nome: *node = mktname(c, "nomem");
|
|
|
|
|
ptr.next = nome;
|
|
|
|
|
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
tt.list = ptr;
|
|
|
|
|
return tt;
|
|
|
|
|
};
|
|
|
|
|
@@ -1845,14 +1843,14 @@ fn checkletassign(c: *checker, n: *node) void = {
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
if (!shadowed) {
|
|
|
|
|
let sl: *node = newnode(c.a, nkind.N_TSLICE, "", 0, 0);
|
|
|
|
|
let sl: *node = newnode(nkind.N_TSLICE, "", 0, 0);
|
|
|
|
|
sl.lhs = n.lhs.lhs;
|
|
|
|
|
if (wrapped) {
|
|
|
|
|
src = sl;
|
|
|
|
|
} else {
|
|
|
|
|
let nome: *node = mktname(c, "nomem");
|
|
|
|
|
sl.next = nome;
|
|
|
|
|
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
|
|
|
|
|
tt.list = sl;
|
|
|
|
|
src = tt;
|
|
|
|
|
};
|
|
|
|
|
@@ -2043,7 +2041,7 @@ fn installparams(c: *checker, params: *node) void = {
|
|
|
|
|
// per-statement scopes.
|
|
|
|
|
fn resolvefnbody(c: *checker, fnnode: *node) void = {
|
|
|
|
|
let outer: *scope = c.cur;
|
|
|
|
|
c.cur = newscope(c.a, c.cur);
|
|
|
|
|
c.cur = newscope(c.cur);
|
|
|
|
|
installparams(c, fnnode.list);
|
|
|
|
|
// #61 audit §1.8 — A.2: walk each param's declared type-expr so
|
|
|
|
|
// tinfofornode stamps n.type_ on it. installparams binds the name
|
|
|
|
|
@@ -2065,10 +2063,9 @@ fn resolvefnbody(c: *checker, fnnode: *node) void = {
|
|
|
|
|
c.cur = outer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export fn checkinit(c: *checker, a: *arena, tc: *tctx) void = {
|
|
|
|
|
c.a = a;
|
|
|
|
|
export fn checkinit(c: *checker, tc: *tctx) void = {
|
|
|
|
|
c.tc = tc;
|
|
|
|
|
c.top = newscope(a, nil);
|
|
|
|
|
c.top = newscope(nil);
|
|
|
|
|
c.cur = c.top;
|
|
|
|
|
c.nresolved = 0;
|
|
|
|
|
c.nunresolved = 0;
|
|
|
|
|
|