selfhost/cmd/wcc: stamp e.type_ for N_BIN + N_UN (A.6.1.3)
Adds unifyarith / binoptype / unoptype mirroring cstage cmd/wcc/check.c:580-596, 598-640, 642-687. Two new exprtype arms stamp e.type_ for N_BIN and N_UN via the same tinfofornode pattern as A.6.1.1/.2. unifyarith: untyped+untyped (prefer float), untyped+typed (typed via isassignable), typed+typed (typeeqast), fallback ltn. binoptype: ptr arith (ptr±int → ptr, ptr-ptr → i64), bitwise/ arith → unifyarith, comparison + logical → bool. unoptype: deref (resolvealias+unwrapbang then N_TPTR.lhs), addrof → *T with slice/str pseudo-field .len/.cap widening to *i64 (mirrors check.c:672-682), unary +/-/^/!. Wwstage stays silent on operator-type errors per existing checker discipline; cstage flags the same shapes. Verified 132/132 incl. 995_self_rebuild byte-identity.
This commit is contained in:
@@ -8160,9 +8160,120 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// unifyarith — usual-arithmetic-conversion analogue at the AST-tnode
|
||||||
|
// layer. Mirrors cstage cmd/wcc/check.c:580-596 `unify_arith`. The
|
||||||
|
// trailing typeeq fallback covers same-typed operands; mismatched typed
|
||||||
|
// pairs silently return ltn (cstage flags the same shape — wwstage's
|
||||||
|
// checker stays silent here per existing discipline).
|
||||||
|
fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||||
|
let lu: bool = isuntypedint(ltn) || isuntypedfloat(ltn);
|
||||||
|
let ru: bool = isuntypedint(rtn) || isuntypedfloat(rtn);
|
||||||
|
if (lu && ru) {
|
||||||
|
if (isuntypedfloat(ltn) || isuntypedfloat(rtn)) {
|
||||||
|
return mktname(c, "untyped_float");
|
||||||
|
};
|
||||||
|
return mktname(c, "untyped_int");
|
||||||
|
};
|
||||||
|
let conf: bool = false;
|
||||||
|
if (lu) {
|
||||||
|
if (isassignable(c, rtn, ltn, &conf)) { return rtn; };
|
||||||
|
};
|
||||||
|
if (ru) {
|
||||||
|
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||||
|
};
|
||||||
|
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
|
||||||
|
// binoptype — derive the result tnode of an N_BIN operator expression.
|
||||||
|
// Mirrors cstage cmd/wcc/check.c:598-640 `cbinop`. Operates on tnodes
|
||||||
|
// returned by exprtype; ptr arithmetic / bitwise / shifts / comparisons /
|
||||||
|
// logicals all reflect cstage's rules. Type-mismatch diagnostics are
|
||||||
|
// elided here (cstage gates the same shape).
|
||||||
|
fn binoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let ltn: *node = exprtype(c, e.lhs, nil);
|
||||||
|
let rtn: *node = exprtype(c, e.rhs, nil);
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && ltn.kind == nkind.N_TPTR && isinttypeast(rtn)) {
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS) {
|
||||||
|
if (isinttypeast(ltn) && rtn != nil && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return rtn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && rtn != nil
|
||||||
|
&& ltn.kind == nkind.N_TPTR && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return mktname(c, "i64");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS ||
|
||||||
|
op == tkind.TK_STAR || op == tkind.TK_SLASH ||
|
||||||
|
op == tkind.TK_PERCENT || op == tkind.TK_AMP ||
|
||||||
|
op == tkind.TK_PIPE || op == tkind.TK_CARET ||
|
||||||
|
op == tkind.TK_LSHIFT || op == tkind.TK_RSHIFT) {
|
||||||
|
return unifyarith(c, ltn, rtn);
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_EQ || op == tkind.TK_NEQ ||
|
||||||
|
op == tkind.TK_LT || op == tkind.TK_LE ||
|
||||||
|
op == tkind.TK_GT || op == tkind.TK_GE ||
|
||||||
|
op == tkind.TK_AND || op == tkind.TK_OR) {
|
||||||
|
return mktname(c, "bool");
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unoptype — derive the result tnode of an N_UN unary expression. Mirrors
|
||||||
|
// cstage cmd/wcc/check.c:642-687 `cunop`. The slice/str .len/.cap
|
||||||
|
// pseudo-field address-of widening to *i64 mirrors check.c:672-682
|
||||||
|
// directly — its purpose is documented at the cstage site.
|
||||||
|
fn unoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let opt: *node = exprtype(c, e.lhs, nil);
|
||||||
|
if (op == tkind.TK_MINUS || op == tkind.TK_PLUS) { return opt; };
|
||||||
|
if (op == tkind.TK_NOT) { return mktname(c, "bool"); };
|
||||||
|
if (op == tkind.TK_TILDE) { return opt; };
|
||||||
|
if (op == tkind.TK_STAR) {
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let u: *node = resolvealias(c, unwrapbang(opt));
|
||||||
|
if (u == nil) { return nil; };
|
||||||
|
if (u.kind != nkind.N_TPTR) { return nil; };
|
||||||
|
return u.lhs;
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_AMP) {
|
||||||
|
if (e.lhs != nil && e.lhs.kind == nkind.N_DOT) {
|
||||||
|
let fld: str = e.lhs.str;
|
||||||
|
if (streq(fld, "len") || streq(fld, "cap")) {
|
||||||
|
let base: *node = e.lhs.lhs;
|
||||||
|
if (base != nil && base.type_ != nil) {
|
||||||
|
let bu: *tinfo = base.type_: *tinfo;
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil) {
|
||||||
|
if (bu.kind == tykind.TY_SLICE || bu.kind == tykind.TY_STR) {
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = mktname(c, "i64");
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = opt;
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
// exprtype — best-effort type-AST inference for an expression
|
// exprtype — best-effort type-AST inference for an expression
|
||||||
// node. Handles literals, identifiers, calls, and casts; returns
|
// node. Handles literals, identifiers, calls, casts, binary/unary
|
||||||
// nil for shapes we don't statically know (binary ops, struct
|
// ops; returns nil for shapes we don't statically know (struct
|
||||||
// field access into non-primitive types, etc).
|
// field access into non-primitive types, etc).
|
||||||
// `hint`: optional declared-type AST passed by the caller (let
|
// `hint`: optional declared-type AST passed by the caller (let
|
||||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||||
@@ -8240,6 +8351,16 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
};
|
};
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
if (k == nkind.N_BIN) {
|
||||||
|
let tn: *node = binoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
|
if (k == nkind.N_UN) {
|
||||||
|
let tn: *node = unoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
||||||
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
||||||
|
|||||||
@@ -1228,9 +1228,120 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// unifyarith — usual-arithmetic-conversion analogue at the AST-tnode
|
||||||
|
// layer. Mirrors cstage cmd/wcc/check.c:580-596 `unify_arith`. The
|
||||||
|
// trailing typeeq fallback covers same-typed operands; mismatched typed
|
||||||
|
// pairs silently return ltn (cstage flags the same shape — wwstage's
|
||||||
|
// checker stays silent here per existing discipline).
|
||||||
|
fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||||
|
let lu: bool = isuntypedint(ltn) || isuntypedfloat(ltn);
|
||||||
|
let ru: bool = isuntypedint(rtn) || isuntypedfloat(rtn);
|
||||||
|
if (lu && ru) {
|
||||||
|
if (isuntypedfloat(ltn) || isuntypedfloat(rtn)) {
|
||||||
|
return mktname(c, "untyped_float");
|
||||||
|
};
|
||||||
|
return mktname(c, "untyped_int");
|
||||||
|
};
|
||||||
|
let conf: bool = false;
|
||||||
|
if (lu) {
|
||||||
|
if (isassignable(c, rtn, ltn, &conf)) { return rtn; };
|
||||||
|
};
|
||||||
|
if (ru) {
|
||||||
|
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||||
|
};
|
||||||
|
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
|
||||||
|
// binoptype — derive the result tnode of an N_BIN operator expression.
|
||||||
|
// Mirrors cstage cmd/wcc/check.c:598-640 `cbinop`. Operates on tnodes
|
||||||
|
// returned by exprtype; ptr arithmetic / bitwise / shifts / comparisons /
|
||||||
|
// logicals all reflect cstage's rules. Type-mismatch diagnostics are
|
||||||
|
// elided here (cstage gates the same shape).
|
||||||
|
fn binoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let ltn: *node = exprtype(c, e.lhs, nil);
|
||||||
|
let rtn: *node = exprtype(c, e.rhs, nil);
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && ltn.kind == nkind.N_TPTR && isinttypeast(rtn)) {
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS) {
|
||||||
|
if (isinttypeast(ltn) && rtn != nil && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return rtn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && rtn != nil
|
||||||
|
&& ltn.kind == nkind.N_TPTR && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return mktname(c, "i64");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS ||
|
||||||
|
op == tkind.TK_STAR || op == tkind.TK_SLASH ||
|
||||||
|
op == tkind.TK_PERCENT || op == tkind.TK_AMP ||
|
||||||
|
op == tkind.TK_PIPE || op == tkind.TK_CARET ||
|
||||||
|
op == tkind.TK_LSHIFT || op == tkind.TK_RSHIFT) {
|
||||||
|
return unifyarith(c, ltn, rtn);
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_EQ || op == tkind.TK_NEQ ||
|
||||||
|
op == tkind.TK_LT || op == tkind.TK_LE ||
|
||||||
|
op == tkind.TK_GT || op == tkind.TK_GE ||
|
||||||
|
op == tkind.TK_AND || op == tkind.TK_OR) {
|
||||||
|
return mktname(c, "bool");
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unoptype — derive the result tnode of an N_UN unary expression. Mirrors
|
||||||
|
// cstage cmd/wcc/check.c:642-687 `cunop`. The slice/str .len/.cap
|
||||||
|
// pseudo-field address-of widening to *i64 mirrors check.c:672-682
|
||||||
|
// directly — its purpose is documented at the cstage site.
|
||||||
|
fn unoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let opt: *node = exprtype(c, e.lhs, nil);
|
||||||
|
if (op == tkind.TK_MINUS || op == tkind.TK_PLUS) { return opt; };
|
||||||
|
if (op == tkind.TK_NOT) { return mktname(c, "bool"); };
|
||||||
|
if (op == tkind.TK_TILDE) { return opt; };
|
||||||
|
if (op == tkind.TK_STAR) {
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let u: *node = resolvealias(c, unwrapbang(opt));
|
||||||
|
if (u == nil) { return nil; };
|
||||||
|
if (u.kind != nkind.N_TPTR) { return nil; };
|
||||||
|
return u.lhs;
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_AMP) {
|
||||||
|
if (e.lhs != nil && e.lhs.kind == nkind.N_DOT) {
|
||||||
|
let fld: str = e.lhs.str;
|
||||||
|
if (streq(fld, "len") || streq(fld, "cap")) {
|
||||||
|
let base: *node = e.lhs.lhs;
|
||||||
|
if (base != nil && base.type_ != nil) {
|
||||||
|
let bu: *tinfo = base.type_: *tinfo;
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil) {
|
||||||
|
if (bu.kind == tykind.TY_SLICE || bu.kind == tykind.TY_STR) {
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = mktname(c, "i64");
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = opt;
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
// exprtype — best-effort type-AST inference for an expression
|
// exprtype — best-effort type-AST inference for an expression
|
||||||
// node. Handles literals, identifiers, calls, and casts; returns
|
// node. Handles literals, identifiers, calls, casts, binary/unary
|
||||||
// nil for shapes we don't statically know (binary ops, struct
|
// ops; returns nil for shapes we don't statically know (struct
|
||||||
// field access into non-primitive types, etc).
|
// field access into non-primitive types, etc).
|
||||||
// `hint`: optional declared-type AST passed by the caller (let
|
// `hint`: optional declared-type AST passed by the caller (let
|
||||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||||
@@ -1308,6 +1419,16 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
};
|
};
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
if (k == nkind.N_BIN) {
|
||||||
|
let tn: *node = binoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
|
if (k == nkind.N_UN) {
|
||||||
|
let tn: *node = unoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
||||||
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
||||||
|
|||||||
@@ -8160,9 +8160,120 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// unifyarith — usual-arithmetic-conversion analogue at the AST-tnode
|
||||||
|
// layer. Mirrors cstage cmd/wcc/check.c:580-596 `unify_arith`. The
|
||||||
|
// trailing typeeq fallback covers same-typed operands; mismatched typed
|
||||||
|
// pairs silently return ltn (cstage flags the same shape — wwstage's
|
||||||
|
// checker stays silent here per existing discipline).
|
||||||
|
fn unifyarith(c: *checker, ltn: *node, rtn: *node) *node = {
|
||||||
|
let lu: bool = isuntypedint(ltn) || isuntypedfloat(ltn);
|
||||||
|
let ru: bool = isuntypedint(rtn) || isuntypedfloat(rtn);
|
||||||
|
if (lu && ru) {
|
||||||
|
if (isuntypedfloat(ltn) || isuntypedfloat(rtn)) {
|
||||||
|
return mktname(c, "untyped_float");
|
||||||
|
};
|
||||||
|
return mktname(c, "untyped_int");
|
||||||
|
};
|
||||||
|
let conf: bool = false;
|
||||||
|
if (lu) {
|
||||||
|
if (isassignable(c, rtn, ltn, &conf)) { return rtn; };
|
||||||
|
};
|
||||||
|
if (ru) {
|
||||||
|
if (isassignable(c, ltn, rtn, &conf)) { return ltn; };
|
||||||
|
};
|
||||||
|
if (typeeqast(ltn, rtn)) { return ltn; };
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
|
||||||
|
// binoptype — derive the result tnode of an N_BIN operator expression.
|
||||||
|
// Mirrors cstage cmd/wcc/check.c:598-640 `cbinop`. Operates on tnodes
|
||||||
|
// returned by exprtype; ptr arithmetic / bitwise / shifts / comparisons /
|
||||||
|
// logicals all reflect cstage's rules. Type-mismatch diagnostics are
|
||||||
|
// elided here (cstage gates the same shape).
|
||||||
|
fn binoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let ltn: *node = exprtype(c, e.lhs, nil);
|
||||||
|
let rtn: *node = exprtype(c, e.rhs, nil);
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && ltn.kind == nkind.N_TPTR && isinttypeast(rtn)) {
|
||||||
|
return ltn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS) {
|
||||||
|
if (isinttypeast(ltn) && rtn != nil && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return rtn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_MINUS) {
|
||||||
|
if (ltn != nil && rtn != nil
|
||||||
|
&& ltn.kind == nkind.N_TPTR && rtn.kind == nkind.N_TPTR) {
|
||||||
|
return mktname(c, "i64");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_PLUS || op == tkind.TK_MINUS ||
|
||||||
|
op == tkind.TK_STAR || op == tkind.TK_SLASH ||
|
||||||
|
op == tkind.TK_PERCENT || op == tkind.TK_AMP ||
|
||||||
|
op == tkind.TK_PIPE || op == tkind.TK_CARET ||
|
||||||
|
op == tkind.TK_LSHIFT || op == tkind.TK_RSHIFT) {
|
||||||
|
return unifyarith(c, ltn, rtn);
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_EQ || op == tkind.TK_NEQ ||
|
||||||
|
op == tkind.TK_LT || op == tkind.TK_LE ||
|
||||||
|
op == tkind.TK_GT || op == tkind.TK_GE ||
|
||||||
|
op == tkind.TK_AND || op == tkind.TK_OR) {
|
||||||
|
return mktname(c, "bool");
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
|
// unoptype — derive the result tnode of an N_UN unary expression. Mirrors
|
||||||
|
// cstage cmd/wcc/check.c:642-687 `cunop`. The slice/str .len/.cap
|
||||||
|
// pseudo-field address-of widening to *i64 mirrors check.c:672-682
|
||||||
|
// directly — its purpose is documented at the cstage site.
|
||||||
|
fn unoptype(c: *checker, e: *node) *node = {
|
||||||
|
let op: tkind = e.op;
|
||||||
|
let opt: *node = exprtype(c, e.lhs, nil);
|
||||||
|
if (op == tkind.TK_MINUS || op == tkind.TK_PLUS) { return opt; };
|
||||||
|
if (op == tkind.TK_NOT) { return mktname(c, "bool"); };
|
||||||
|
if (op == tkind.TK_TILDE) { return opt; };
|
||||||
|
if (op == tkind.TK_STAR) {
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let u: *node = resolvealias(c, unwrapbang(opt));
|
||||||
|
if (u == nil) { return nil; };
|
||||||
|
if (u.kind != nkind.N_TPTR) { return nil; };
|
||||||
|
return u.lhs;
|
||||||
|
};
|
||||||
|
if (op == tkind.TK_AMP) {
|
||||||
|
if (e.lhs != nil && e.lhs.kind == nkind.N_DOT) {
|
||||||
|
let fld: str = e.lhs.str;
|
||||||
|
if (streq(fld, "len") || streq(fld, "cap")) {
|
||||||
|
let base: *node = e.lhs.lhs;
|
||||||
|
if (base != nil && base.type_ != nil) {
|
||||||
|
let bu: *tinfo = base.type_: *tinfo;
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_PTR) { bu = bu.sub; };
|
||||||
|
if (bu != nil && bu.kind == tykind.TY_NAMED) { bu = bu.under; };
|
||||||
|
if (bu != nil) {
|
||||||
|
if (bu.kind == tykind.TY_SLICE || bu.kind == tykind.TY_STR) {
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = mktname(c, "i64");
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (opt == nil) { return nil; };
|
||||||
|
let pp: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||||
|
pp.lhs = opt;
|
||||||
|
return pp;
|
||||||
|
};
|
||||||
|
return nil;
|
||||||
|
};
|
||||||
|
|
||||||
// exprtype — best-effort type-AST inference for an expression
|
// exprtype — best-effort type-AST inference for an expression
|
||||||
// node. Handles literals, identifiers, calls, and casts; returns
|
// node. Handles literals, identifiers, calls, casts, binary/unary
|
||||||
// nil for shapes we don't statically know (binary ops, struct
|
// ops; returns nil for shapes we don't statically know (struct
|
||||||
// field access into non-primitive types, etc).
|
// field access into non-primitive types, etc).
|
||||||
// `hint`: optional declared-type AST passed by the caller (let
|
// `hint`: optional declared-type AST passed by the caller (let
|
||||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||||
@@ -8240,6 +8351,16 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
|||||||
};
|
};
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
if (k == nkind.N_BIN) {
|
||||||
|
let tn: *node = binoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
|
if (k == nkind.N_UN) {
|
||||||
|
let tn: *node = unoptype(c, e);
|
||||||
|
e.type_ = tinfofornode(c, tn): *void;
|
||||||
|
return tn;
|
||||||
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
// `expr: T` — explicit cast; the type expr is e.rhs. Mirrors
|
||||||
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
// cstage cmd/wcc/check.c:737 `n->type = resolve_type(c, n->rhs)`.
|
||||||
|
|||||||
Reference in New Issue
Block a user