selfhost: graduate N_* defs to nkind enum
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
// `i32`, `str`, `*u8` etc. resolve.
|
||||
// 2. Walks the file's top-level decls (use/def/type/fn/let) and
|
||||
// installs Sym entries for each.
|
||||
// 3. Recursively walks fn bodies; for every N_IDENT used as an
|
||||
// 3. Recursively walks fn bodies; for every nkind.N_IDENT used as an
|
||||
// expression or as a type name, looks it up and counts the
|
||||
// resolved vs. unresolved.
|
||||
// 4. Returns a summary the caller (wwdump -r) prints; the test
|
||||
@@ -70,15 +70,15 @@ fn installdecl(c: *checker, d: *node) void = {
|
||||
if (d == nil) { return; };
|
||||
let k: i32 = d.kind;
|
||||
let nm: str = d.str;
|
||||
if (k == N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; };
|
||||
if (k == N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; };
|
||||
if (k == N_TYPEDECL) { scopedefine(c.top, nm, skind.SK_TYPE, nil, d); return; };
|
||||
if (k == N_FNDECL) { scopedefine(c.top, nm, skind.SK_FN, nil, d); return; };
|
||||
if (k == N_LET) { scopedefine(c.top, nm, skind.SK_VAR, nil, d); return; };
|
||||
if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; };
|
||||
if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; };
|
||||
if (k == nkind.N_TYPEDECL) { scopedefine(c.top, nm, skind.SK_TYPE, nil, d); return; };
|
||||
if (k == nkind.N_FNDECL) { scopedefine(c.top, nm, skind.SK_FN, nil, d); return; };
|
||||
if (k == nkind.N_LET) { scopedefine(c.top, nm, skind.SK_VAR, nil, d); return; };
|
||||
};
|
||||
|
||||
// resolvewalk — recursive AST walk that, for every N_IDENT and
|
||||
// N_TNAME seen, looks up the name and bumps the resolved/unresolved
|
||||
// resolvewalk — recursive AST walk that, for every nkind.N_IDENT and
|
||||
// nkind.N_TNAME seen, looks up the name and bumps the resolved/unresolved
|
||||
// counters. Local lets are installed in the current scope as soon as
|
||||
// their init/type expressions have been walked (forward use of a let
|
||||
// before its declaration would resolve to nothing — same semantics as
|
||||
@@ -91,17 +91,17 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
|
||||
// Typed checks fire on the way down so the scrutinee/operand
|
||||
// is examined before the arm bodies install new bindings.
|
||||
if (k == N_MATCH) { checkmatchexhaust(c, n); };
|
||||
if (k == N_TRYPROP) { checktryprop(c, n); };
|
||||
if (k == N_TYPETEST) { checkisas(c, n); };
|
||||
if (k == N_TYPEASSERT) { checkisas(c, n); };
|
||||
if (k == N_LET) { checkletassign(c, n); };
|
||||
if (k == N_RETURN) { checkretassign(c, n); };
|
||||
if (k == nkind.N_MATCH) { checkmatchexhaust(c, n); };
|
||||
if (k == nkind.N_TRYPROP) { checktryprop(c, n); };
|
||||
if (k == nkind.N_TYPETEST) { checkisas(c, n); };
|
||||
if (k == nkind.N_TYPEASSERT) { checkisas(c, n); };
|
||||
if (k == nkind.N_LET) { checkletassign(c, n); };
|
||||
if (k == nkind.N_RETURN) { checkretassign(c, n); };
|
||||
|
||||
// `use IDENT;` — name is a module label, not a free ident.
|
||||
if (k == N_USE) { return; };
|
||||
if (k == nkind.N_USE) { return; };
|
||||
|
||||
if (k == N_IDENT) {
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
if (nm.len > 0) {
|
||||
let s: *sym = scopelookup(c.cur, nm);
|
||||
@@ -116,7 +116,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
};
|
||||
};
|
||||
|
||||
if (k == N_TNAME) {
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = n.str;
|
||||
if (nm.len > 0) {
|
||||
let s: *sym = scopelookup(c.cur, nm);
|
||||
@@ -155,7 +155,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
|
||||
// `match (e) { case let v: T => stmt; ... }` — the binding `v`
|
||||
// is declared by the case arm and visible inside its body.
|
||||
if (k == N_MCASE) {
|
||||
if (k == nkind.N_MCASE) {
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
let nm: str = n.str;
|
||||
if (nm.len > 0) {
|
||||
@@ -165,19 +165,19 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == N_DOT) {
|
||||
if (k == nkind.N_DOT) {
|
||||
// Walk only the base; the .field name is a member, not a
|
||||
// free identifier.
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == N_FIELD) {
|
||||
if (k == nkind.N_FIELD) {
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == N_TFIELD) {
|
||||
if (k == nkind.N_TFIELD) {
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
return;
|
||||
};
|
||||
@@ -201,7 +201,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
// `X` so subsequent statements can resolve it. Top-level lets
|
||||
// are installed in installdecl, so this duplicate install at
|
||||
// the file scope just no-ops (scopedefine returns nil on dup).
|
||||
if (k == N_LET) {
|
||||
if (k == nkind.N_LET) {
|
||||
let nm: str = n.str;
|
||||
if (nm.len > 0) {
|
||||
scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
@@ -217,21 +217,21 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
// needs to enforce: tagged-union exhaustiveness, ? subset
|
||||
// propagation, and !-flag semantics.
|
||||
|
||||
// unwrapbang — strip an N_TBANG wrapper; leaves other nodes alone.
|
||||
// unwrapbang — strip an nkind.N_TBANG wrapper; leaves other nodes alone.
|
||||
fn unwrapbang(n: *node) *node = {
|
||||
if (n == nil) { return nil; };
|
||||
if (n.kind == N_TBANG) { return n.lhs; };
|
||||
if (n.kind == nkind.N_TBANG) { return n.lhs; };
|
||||
return n;
|
||||
};
|
||||
|
||||
// resolvealias — if n is an N_TNAME pointing at a typedecl, return
|
||||
// resolvealias — if n is an nkind.N_TNAME pointing at a typedecl, return
|
||||
// the typedecl's body (possibly recursively). Pass-through for any
|
||||
// other node. The chain stops once we hit a non-N_TNAME node or a
|
||||
// other node. The chain stops once we hit a non-nkind.N_TNAME node or a
|
||||
// name we can't resolve.
|
||||
fn resolvealias(c: *checker, n: *node) *node = {
|
||||
let cur: *node = n;
|
||||
for (cur != nil) {
|
||||
if (cur.kind != N_TNAME) { return cur; };
|
||||
if (cur.kind != nkind.N_TNAME) { return cur; };
|
||||
let s: *sym = scopelookup(c.cur, cur.str);
|
||||
if (s == nil) { return cur; };
|
||||
if (s.skind != skind.SK_TYPE) { return cur; };
|
||||
@@ -254,10 +254,10 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
if (bb == nil) { return false; };
|
||||
if (aa.kind != bb.kind) { return false; };
|
||||
let k: i32 = aa.kind;
|
||||
if (k == N_TNAME) { return streq(aa.str, bb.str); };
|
||||
if (k == N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
|
||||
if (k == N_TCHAN) { return typeeqast(aa.lhs, bb.lhs); };
|
||||
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); };
|
||||
// Conservative: anything else (struct/fn/tagged/tuple/array)
|
||||
// fails the cheap check. Selfhost code doesn't currently rely
|
||||
// on equality at these shapes for the targeted checks.
|
||||
@@ -265,18 +265,18 @@ fn typeeqast(a: *node, b: *node) bool = {
|
||||
};
|
||||
|
||||
// varianterr — does this variant carry the `!` mark? Either
|
||||
// the variant itself is N_TBANG or it's an alias whose typedecl
|
||||
// the variant itself is nkind.N_TBANG or it's an alias whose typedecl
|
||||
// body is `!T`. Mirrors C check.c's iserror-after-NAMED rule.
|
||||
fn varianterr(c: *checker, v: *node) bool = {
|
||||
if (v == nil) { return false; };
|
||||
if (v.kind == N_TBANG) { return true; };
|
||||
if (v.kind == N_TNAME) {
|
||||
if (v.kind == nkind.N_TBANG) { return true; };
|
||||
if (v.kind == nkind.N_TNAME) {
|
||||
let s: *sym = scopelookup(c.cur, v.str);
|
||||
if (s != nil) {
|
||||
if (s.skind == skind.SK_TYPE) {
|
||||
if (s.decl != nil) {
|
||||
if (s.decl.lhs != nil) {
|
||||
if (s.decl.lhs.kind == N_TBANG) {
|
||||
if (s.decl.lhs.kind == nkind.N_TBANG) {
|
||||
return true;
|
||||
};
|
||||
};
|
||||
@@ -288,7 +288,7 @@ fn varianterr(c: *checker, v: *node) bool = {
|
||||
};
|
||||
|
||||
// taggedhaserr — true iff any variant of `n` (assumed
|
||||
// N_TTAGGED) is `!`-marked. Picks the explicit-flag semantics over
|
||||
// nkind.N_TTAGGED) is `!`-marked. Picks the explicit-flag semantics over
|
||||
// the legacy "first variant = success" rule.
|
||||
fn taggedhaserr(c: *checker, n: *node) bool = {
|
||||
let v: *node = n.list;
|
||||
@@ -312,26 +312,26 @@ fn iserrvariant(c: *checker, tagged: *node, v: *node) bool = {
|
||||
};
|
||||
|
||||
// scruttype — resolve the type expression for a match's
|
||||
// scrutinee. Handles N_IDENT (look up local/param's declared
|
||||
// type) and N_DOT (struct-field access). Returns nil if we
|
||||
// scrutinee. Handles nkind.N_IDENT (look up local/param's declared
|
||||
// type) and nkind.N_DOT (struct-field access). Returns nil if we
|
||||
// can't statically determine the type. Used by exhaustiveness.
|
||||
fn scruttype(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
if (e.kind == N_IDENT) {
|
||||
if (e.kind == nkind.N_IDENT) {
|
||||
let s: *sym = scopelookup(c.cur, e.str);
|
||||
if (s == nil) { return nil; };
|
||||
if (s.decl == nil) { return nil; };
|
||||
// For N_LET / N_PARAM: declared type is decl.lhs.
|
||||
// For nkind.N_LET / nkind.N_PARAM: declared type is decl.lhs.
|
||||
return s.decl.lhs;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
// mktname — fabricate an N_TNAME node with str = `nm`. Used by
|
||||
// mktname — fabricate an nkind.N_TNAME node with str = `nm`. Used by
|
||||
// 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, N_TNAME, "", 0, 0);
|
||||
let n: *node = newnode(c.a, nkind.N_TNAME, "", 0, 0);
|
||||
n.str = nm;
|
||||
return n;
|
||||
};
|
||||
@@ -343,31 +343,31 @@ fn mktname(c: *checker, nm: str) *node = {
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: i32 = e.kind;
|
||||
if (k == N_INTLIT) { return mktname(c, "untyped_int"); };
|
||||
if (k == N_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
if (k == N_STRLIT) { return mktname(c, "str"); };
|
||||
if (k == N_RUNELIT) { return mktname(c, "rune"); };
|
||||
if (k == N_TRUE) { return mktname(c, "bool"); };
|
||||
if (k == N_FALSE) { return mktname(c, "bool"); };
|
||||
if (k == N_VOIDLIT) { return mktname(c, "void"); };
|
||||
if (k == N_NIL) { return mktname(c, "untyped_nil"); };
|
||||
if (k == N_IDENT) {
|
||||
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
|
||||
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
|
||||
if (k == nkind.N_RUNELIT) { return mktname(c, "rune"); };
|
||||
if (k == nkind.N_TRUE) { return mktname(c, "bool"); };
|
||||
if (k == nkind.N_FALSE) { return mktname(c, "bool"); };
|
||||
if (k == nkind.N_VOIDLIT) { return mktname(c, "void"); };
|
||||
if (k == nkind.N_NIL) { return mktname(c, "untyped_nil"); };
|
||||
if (k == nkind.N_IDENT) {
|
||||
let s: *sym = scopelookup(c.cur, e.str);
|
||||
if (s == nil) { return nil; };
|
||||
if (s.decl == nil) { return nil; };
|
||||
return s.decl.lhs;
|
||||
};
|
||||
if (k == N_CAST) {
|
||||
if (k == nkind.N_CAST) {
|
||||
// `expr: T` — explicit cast; the type expr is e.rhs.
|
||||
return e.rhs;
|
||||
};
|
||||
if (k == N_CALL) {
|
||||
if (k == nkind.N_CALL) {
|
||||
let callee: *node = e.lhs;
|
||||
if (callee == nil) { return nil; };
|
||||
let nm: str;
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (callee.kind == N_IDENT) { nm = callee.str; };
|
||||
if (callee.kind == N_DOT) { nm = callee.str; };
|
||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||
if (nm.len == 0) { return nil; };
|
||||
let s: *sym = scopelookup(c.cur, nm);
|
||||
if (s == nil) { return nil; };
|
||||
@@ -375,13 +375,13 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (s.decl == nil) { return nil; };
|
||||
return s.decl.lhs; // fn-decl's lhs is the return type
|
||||
};
|
||||
if (k == N_TRYPROP) {
|
||||
if (k == nkind.N_TRYPROP) {
|
||||
// success unwrap: the success-variant type of operand's
|
||||
// tagged union.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != N_TTAGGED) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
// Hare semantics: success = first non-error variant if
|
||||
// any !-flag is present; else first variant.
|
||||
if (taggedhaserr(c, ou)) {
|
||||
@@ -394,11 +394,11 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
};
|
||||
return ou.list;
|
||||
};
|
||||
if (k == N_TYPEASSERT) {
|
||||
if (k == nkind.N_TYPEASSERT) {
|
||||
// `e as T` → T
|
||||
return e.rhs;
|
||||
};
|
||||
if (k == N_TYPETEST) {
|
||||
if (k == nkind.N_TYPETEST) {
|
||||
// `e is T` → bool
|
||||
return mktname(c, "bool");
|
||||
};
|
||||
@@ -410,25 +410,25 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
// through without needing real type inference.
|
||||
fn isuntypedint(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != N_TNAME) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
return streq(t.str, "untyped_int");
|
||||
};
|
||||
|
||||
fn isuntypedfloat(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != N_TNAME) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
return streq(t.str, "untyped_float");
|
||||
};
|
||||
|
||||
fn isuntypednil(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != N_TNAME) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
return streq(t.str, "untyped_nil");
|
||||
};
|
||||
|
||||
fn isnumerictname(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != N_TNAME) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
let s: str = t.str;
|
||||
if (streq(s, "i8")) { return true; };
|
||||
if (streq(s, "i16")) { return true; };
|
||||
@@ -449,7 +449,7 @@ fn isnumerictname(t: *node) bool = {
|
||||
|
||||
fn isstrtname(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != N_TNAME) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
return streq(t.str, "str");
|
||||
};
|
||||
|
||||
@@ -474,7 +474,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (isuntypedint(su)) {
|
||||
if (isnumerictname(du)) { return true; };
|
||||
// (T | ...) tagged: only OK if some variant accepts untyped_int.
|
||||
if (du.kind == N_TTAGGED) {
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
@@ -487,7 +487,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
return true;
|
||||
};
|
||||
// Known non-numeric primitive: confidently wrong.
|
||||
if (du.kind == N_TNAME) {
|
||||
if (du.kind == nkind.N_TNAME) {
|
||||
if (streq(du.str, "bool")) { return false; };
|
||||
if (streq(du.str, "void")) { return false; };
|
||||
if (streq(du.str, "str")) { return false; };
|
||||
@@ -498,7 +498,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
};
|
||||
if (isuntypedfloat(su)) {
|
||||
if (isnumerictname(du)) { return true; };
|
||||
if (du.kind == N_TNAME) {
|
||||
if (du.kind == nkind.N_TNAME) {
|
||||
if (streq(du.str, "bool")) { return false; };
|
||||
if (streq(du.str, "void")) { return false; };
|
||||
if (streq(du.str, "str")) { return false; };
|
||||
@@ -508,17 +508,17 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
};
|
||||
if (isuntypednil(su)) {
|
||||
// nil → ptr/slice/chan/fn/nullable
|
||||
if (du.kind == N_TPTR) { return true; };
|
||||
if (du.kind == N_TSLICE) { return true; };
|
||||
if (du.kind == N_TCHAN) { return true; };
|
||||
if (du.kind == N_TFN) { return true; };
|
||||
if (du.kind == nkind.N_TPTR) { return true; };
|
||||
if (du.kind == nkind.N_TSLICE) { return true; };
|
||||
if (du.kind == nkind.N_TCHAN) { return true; };
|
||||
if (du.kind == nkind.N_TFN) { return true; };
|
||||
// nullable `(*T | void)` — already accepted by typeeqast
|
||||
// when matched whole; nil is OK there too.
|
||||
if (du.kind == N_TTAGGED) {
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
if (v.kind == N_TPTR) { return true; };
|
||||
if (v.kind == N_TSLICE){ return true; };
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE){ return true; };
|
||||
v = v.next;
|
||||
};
|
||||
};
|
||||
@@ -526,7 +526,7 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
return true;
|
||||
};
|
||||
// Tagged-union variant inclusion: src is one of dst's variants.
|
||||
if (du.kind == N_TTAGGED && su.kind != N_TTAGGED) {
|
||||
if (du.kind == nkind.N_TTAGGED && su.kind != nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
@@ -541,13 +541,13 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
// (don't be confident) — common when forwarding a fallible
|
||||
// return through another fn with the same shape but possibly
|
||||
// a different surface spelling.
|
||||
if (du.kind == N_TTAGGED && su.kind == N_TTAGGED) {
|
||||
if (du.kind == nkind.N_TTAGGED && su.kind == nkind.N_TTAGGED) {
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
// Two known primitives with different names are confidently
|
||||
// incompatible. `i32 ↔ bool`, `str ↔ i32`, etc.
|
||||
if (du.kind == N_TNAME && su.kind == N_TNAME) {
|
||||
if (du.kind == nkind.N_TNAME && su.kind == nkind.N_TNAME) {
|
||||
let known_d: bool = isnumerictname(du) || isstrtname(du);
|
||||
if (!known_d) { if (streq(du.str, "bool")) { known_d = true; }; };
|
||||
if (!known_d) { if (streq(du.str, "void")) { known_d = true; }; };
|
||||
@@ -587,7 +587,7 @@ fn casecovers(c: *checker, cs: *node, want: *node) bool = {
|
||||
fn errmatchvariant(c: *checker, n: *node, vname: *node) void = {
|
||||
os.write(2, "match: variant not handled".ptr, 26u64);
|
||||
if (vname != nil) {
|
||||
if (vname.kind == N_TNAME) {
|
||||
if (vname.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
os.write(2, vname.str.ptr, vname.str.len: u64);
|
||||
os.write(2, ")".ptr, 1u64);
|
||||
@@ -612,7 +612,7 @@ fn casevariantin(tagged: *node, pat: *node) bool = {
|
||||
fn errbadcase(c: *checker, pat: *node) void = {
|
||||
os.write(2, "case: not a variant of scrutinee".ptr, 32u64);
|
||||
if (pat != nil) {
|
||||
if (pat.kind == N_TNAME) {
|
||||
if (pat.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
os.write(2, pat.str.ptr, pat.str.len: u64);
|
||||
os.write(2, ")".ptr, 1u64);
|
||||
@@ -628,7 +628,7 @@ fn checkmatchexhaust(c: *checker, n: *node) void = {
|
||||
let st: *node = scruttype(c, n.lhs);
|
||||
let u: *node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != N_TTAGGED) { return; };
|
||||
if (u.kind != nkind.N_TTAGGED) { return; };
|
||||
// Validity: every `case T` pattern (and multi-pattern alts)
|
||||
// must name a variant of u. Catches typos and dead arms that
|
||||
// the dispatch would never reach.
|
||||
@@ -684,12 +684,12 @@ fn errnotassign(c: *checker, dst: *node, src: *node, where: str) void = {
|
||||
os.write(2, where.ptr, where.len: u64);
|
||||
os.write(2, ": not assignable".ptr, 16u64);
|
||||
if (src != nil) {
|
||||
if (src.kind == N_TNAME) {
|
||||
if (src.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
os.write(2, src.str.ptr, src.str.len: u64);
|
||||
os.write(2, " → ".ptr, 5u64);
|
||||
if (dst != nil) {
|
||||
if (dst.kind == N_TNAME) {
|
||||
if (dst.kind == nkind.N_TNAME) {
|
||||
os.write(2, dst.str.ptr, dst.str.len: u64);
|
||||
};
|
||||
};
|
||||
@@ -741,7 +741,7 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
let st: *node = scruttype(c, n.lhs);
|
||||
let u: *node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != N_TTAGGED) {
|
||||
if (u.kind != nkind.N_TTAGGED) {
|
||||
os.write(2, "is/as: operand is not a tagged union\n".ptr, 37u64);
|
||||
c.errs += 1;
|
||||
return;
|
||||
@@ -750,7 +750,7 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
if (want == nil) { return; };
|
||||
if (!casevariantin(u, want)) {
|
||||
os.write(2, "is/as: not a variant of operand".ptr, 31u64);
|
||||
if (want.kind == N_TNAME) {
|
||||
if (want.kind == nkind.N_TNAME) {
|
||||
os.write(2, " (".ptr, 2u64);
|
||||
os.write(2, want.str.ptr, want.str.len: u64);
|
||||
os.write(2, ")".ptr, 1u64);
|
||||
@@ -764,26 +764,26 @@ fn checkisas(c: *checker, n: *node) void = {
|
||||
//
|
||||
// For `expr?`, the operand's error subset must be a subset of the
|
||||
// enclosing fn's return-type variants. Mirrors C check.c. Operand
|
||||
// is N_TRYPROP; its lhs is the value-bearing expr; we look at the
|
||||
// expr's *declared* type for N_IDENT/N_CALL cases.
|
||||
// is nkind.N_TRYPROP; its lhs is the value-bearing expr; we look at the
|
||||
// expr's *declared* type for nkind.N_IDENT/nkind.N_CALL cases.
|
||||
|
||||
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
if (e.kind == N_IDENT) {
|
||||
if (e.kind == nkind.N_IDENT) {
|
||||
let s: *sym = scopelookup(c.cur, e.str);
|
||||
if (s == nil) { return nil; };
|
||||
if (s.decl == nil) { return nil; };
|
||||
return s.decl.lhs;
|
||||
};
|
||||
if (e.kind == N_CALL) {
|
||||
// callee return type lookup: callee is e.lhs (N_IDENT or
|
||||
// N_DOT). We need the fn-decl's lhs (return-type AST).
|
||||
if (e.kind == nkind.N_CALL) {
|
||||
// callee return type lookup: callee is e.lhs (nkind.N_IDENT or
|
||||
// nkind.N_DOT). We need the fn-decl's lhs (return-type AST).
|
||||
let callee: *node = e.lhs;
|
||||
if (callee == nil) { return nil; };
|
||||
let nm: str;
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (callee.kind == N_IDENT) { nm = callee.str; };
|
||||
if (callee.kind == N_DOT) { nm = callee.str; };
|
||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||
if (nm.len == 0) { return nil; };
|
||||
let s: *sym = scopelookup(c.cur, nm);
|
||||
if (s == nil) { return nil; };
|
||||
@@ -799,7 +799,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
let t: *node = exprtypeoftry(c, n.lhs);
|
||||
let u: *node = resolvealias(c, unwrapbang(t));
|
||||
if (u == nil) { return; };
|
||||
if (u.kind != N_TTAGGED) { return; };
|
||||
if (u.kind != nkind.N_TTAGGED) { return; };
|
||||
// Does the operand have any error variants?
|
||||
let haserr: bool = false;
|
||||
let v: *node = u.list;
|
||||
@@ -816,7 +816,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
c.errs += 1;
|
||||
return;
|
||||
};
|
||||
if (r.kind != N_TTAGGED) {
|
||||
if (r.kind != nkind.N_TTAGGED) {
|
||||
os.write(2, "?: enclosing fn return is not tagged\n".ptr, 37u64);
|
||||
c.errs += 1;
|
||||
return;
|
||||
@@ -846,7 +846,7 @@ fn checktryprop(c: *checker, n: *node) void = {
|
||||
fn installparams(c: *checker, params: *node) void = {
|
||||
let p: *node = params;
|
||||
for (p != nil) {
|
||||
if (p.kind == N_PARAM) {
|
||||
if (p.kind == nkind.N_PARAM) {
|
||||
let nm: str = p.str;
|
||||
if (nm.len > 0) {
|
||||
scopedefine(c.cur, nm, skind.SK_PARAM, nil, p);
|
||||
@@ -888,7 +888,7 @@ export fn checkinit(c: *checker, a: *arena, tc: *tctx) void = {
|
||||
|
||||
export fn checkfile(c: *checker, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
if (file.kind != N_FILE) { return; };
|
||||
if (file.kind != nkind.N_FILE) { return; };
|
||||
|
||||
// Pass 1: install all top-level names.
|
||||
let d: *node = file.list;
|
||||
@@ -901,15 +901,15 @@ export fn checkfile(c: *checker, file: *node) void = {
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
let k: i32 = d.kind;
|
||||
if (k == N_FNDECL) {
|
||||
if (k == nkind.N_FNDECL) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
|
||||
resolvefnbody(c, d);
|
||||
} else { if (k == N_DEF) {
|
||||
} else { if (k == nkind.N_DEF) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||
if (d.rhs != nil) { resolvewalk(c, d.rhs); };
|
||||
} else { if (k == N_TYPEDECL) {
|
||||
} else { if (k == nkind.N_TYPEDECL) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||
} else { if (k == N_LET) {
|
||||
} else { if (k == nkind.N_LET) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); };
|
||||
if (d.rhs != nil) { resolvewalk(c, d.rhs); };
|
||||
};};};};
|
||||
|
||||
Reference in New Issue
Block a user