selfhost/cmd/wcc: plumb exprtype hint + resolvewalk dispatch (A.6.0)
A.6.0: extend `exprtype(c, e)` → `exprtype(c, e, hint)` and dispatch post-order on every expression-yielding node kind in resolvewalk. hint is threaded but unused by every arm; A.6.1's STRUCTLIT/ARRLIT arms consume it (harec's check_expression result_type shape per feedback_hare_frontend_reference.md). Dispatch fires existing literal + ident stamps universally; per-kind stamp coverage lands in A.6.1+. Cgen reads tnode.type_ (not expression-node type_), so byte-identity holds. Verified 132/132 incl. 995_self_rebuild.
This commit is contained in:
@@ -7316,6 +7316,10 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
// Walk only the base; the .field name is a member, not a
|
||||
// free identifier.
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
// A.6.0: branch returns early; stamp here so the post-walk
|
||||
// dispatch below sees N_DOT covered. exprtype N_DOT arm is
|
||||
// added in A.6.1; for now this is a no-op nil return.
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -7374,7 +7378,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
if (n.lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = n.lhs.str;
|
||||
if (streq(nm, "size") || streq(nm, "align") || streq(nm, "offset")) {
|
||||
let _t: *node = exprtype(c, n);
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -7398,6 +7402,37 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
};
|
||||
};
|
||||
|
||||
// A.6.0: post-order dispatch of exprtype on every expression-yielding
|
||||
// node kind so n.type_ stamps fire universally — not only when reached
|
||||
// through checkletassign / checkretassign / checktryprop / the size-
|
||||
// align-offset fold. Mirrors cstage cmd/wcc/check.c cstmt's recursive
|
||||
// cexpr (cmd/wcc/check.c:1567 N_EXPRSTMT, :1570 N_RETURN, :1584 N_IF
|
||||
// cond, etc.). Plumbing-only: stamps fire from existing exprtype kind
|
||||
// arms (literals + idents); per-kind stamp coverage lands in A.6.1.
|
||||
// Stamps are tinfocache-backed idempotent so multi-walk via let /
|
||||
// return / try entry points is safe. N_DOT is dispatched in its own
|
||||
// early-return branch above; not listed here. N_LET / N_RETURN /
|
||||
// N_EXPRSTMT / N_IF / N_FOR / N_FORRANGE / N_BLOCK / N_MATCH-as-stmt
|
||||
// are not value-typed nodes; their expression children get stamped on
|
||||
// the recursive descent into them. Type-expression kinds (N_T*) are
|
||||
// covered separately by the tinfofornode block above.
|
||||
if (k == nkind.N_INTLIT || k == nkind.N_FLOATLIT ||
|
||||
k == nkind.N_STRLIT || k == nkind.N_RUNELIT ||
|
||||
k == nkind.N_TRUE || k == nkind.N_FALSE ||
|
||||
k == nkind.N_NIL || k == nkind.N_VOIDLIT ||
|
||||
k == nkind.N_IDENT || k == nkind.N_BIN ||
|
||||
k == nkind.N_UN || k == nkind.N_CALL ||
|
||||
k == nkind.N_INDEX || k == nkind.N_CAST ||
|
||||
k == nkind.N_STRUCTLIT || k == nkind.N_ARRLIT ||
|
||||
k == nkind.N_ALLOC || k == nkind.N_RECV ||
|
||||
k == nkind.N_SLICE || k == nkind.N_SPREAD ||
|
||||
k == nkind.N_TUPLE || k == nkind.N_TRYPROP ||
|
||||
k == nkind.N_TRYUNW || k == nkind.N_TYPETEST ||
|
||||
k == nkind.N_TYPEASSERT || k == nkind.N_YIELD ||
|
||||
k == nkind.N_MATCH) {
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
|
||||
// ---- type-level helpers (AST-level, no resolved tinfo) --------------
|
||||
@@ -8143,7 +8178,15 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
// field access into non-primitive types, etc).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `hint`: optional declared-type AST passed by the caller (let
|
||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||
// for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and
|
||||
// need the enclosing declared type to resolve. Ignored by every arm
|
||||
// in A.6.0; the param is plumbed here so the per-kind work that
|
||||
// follows doesn't ripple a fresh signature change. Mirrors harec's
|
||||
// `check_expression(..., result_type, ...)` per
|
||||
// `feedback_hare_frontend_reference.md`.
|
||||
fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
// #61 audit §1.8 — A.2 widens A.1's single N_INTLIT population to
|
||||
@@ -8253,7 +8296,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
};
|
||||
// Value form: `alloc(value)`.
|
||||
if (e.list.next == nil) {
|
||||
let argt: *node = exprtype(c, e.list);
|
||||
let argt: *node = exprtype(c, e.list, nil);
|
||||
let ptr: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||
ptr.lhs = argt;
|
||||
let nome: *node = mktname(c, "nomem");
|
||||
@@ -8344,7 +8387,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (k == nkind.N_TRYPROP) {
|
||||
// success unwrap: the success-variant type of operand's
|
||||
// tagged union.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -8364,7 +8407,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `e!` abort-on-error unwrap; success variant is what the
|
||||
// receiver gets, identical to `?` shape modulo control flow.
|
||||
// #31: required so `let p: *T = alloc(v)!;` resolves to *T.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -8736,7 +8779,9 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) { return; }; // no declared type, nothing to check
|
||||
if (n.rhs == nil) { return; }; // no init
|
||||
let src: *node = exprtype(c, n.rhs);
|
||||
// hint = nil for A.6.0; A.6.1 will pass n.lhs once STRUCTLIT/ARRLIT
|
||||
// arms consume it. Plumbing-only at this point.
|
||||
let src: *node = exprtype(c, n.rhs, nil);
|
||||
if (src == nil) { return; }; // can't infer
|
||||
// #45: alloc([], n) defers element type to the let-init context
|
||||
// (Hare-style). exprtype's alloc-slice branch synthesizes
|
||||
@@ -8805,7 +8850,7 @@ fn checkretassign(c: *checker, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
let src: *node = exprtype(c, n.lhs);
|
||||
let src: *node = exprtype(c, n.lhs, nil);
|
||||
if (src == nil) { return; };
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, c.fnret, src, &conf);
|
||||
|
||||
@@ -384,6 +384,10 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
// Walk only the base; the .field name is a member, not a
|
||||
// free identifier.
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
// A.6.0: branch returns early; stamp here so the post-walk
|
||||
// dispatch below sees N_DOT covered. exprtype N_DOT arm is
|
||||
// added in A.6.1; for now this is a no-op nil return.
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -442,7 +446,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
if (n.lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = n.lhs.str;
|
||||
if (streq(nm, "size") || streq(nm, "align") || streq(nm, "offset")) {
|
||||
let _t: *node = exprtype(c, n);
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -466,6 +470,37 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
};
|
||||
};
|
||||
|
||||
// A.6.0: post-order dispatch of exprtype on every expression-yielding
|
||||
// node kind so n.type_ stamps fire universally — not only when reached
|
||||
// through checkletassign / checkretassign / checktryprop / the size-
|
||||
// align-offset fold. Mirrors cstage cmd/wcc/check.c cstmt's recursive
|
||||
// cexpr (cmd/wcc/check.c:1567 N_EXPRSTMT, :1570 N_RETURN, :1584 N_IF
|
||||
// cond, etc.). Plumbing-only: stamps fire from existing exprtype kind
|
||||
// arms (literals + idents); per-kind stamp coverage lands in A.6.1.
|
||||
// Stamps are tinfocache-backed idempotent so multi-walk via let /
|
||||
// return / try entry points is safe. N_DOT is dispatched in its own
|
||||
// early-return branch above; not listed here. N_LET / N_RETURN /
|
||||
// N_EXPRSTMT / N_IF / N_FOR / N_FORRANGE / N_BLOCK / N_MATCH-as-stmt
|
||||
// are not value-typed nodes; their expression children get stamped on
|
||||
// the recursive descent into them. Type-expression kinds (N_T*) are
|
||||
// covered separately by the tinfofornode block above.
|
||||
if (k == nkind.N_INTLIT || k == nkind.N_FLOATLIT ||
|
||||
k == nkind.N_STRLIT || k == nkind.N_RUNELIT ||
|
||||
k == nkind.N_TRUE || k == nkind.N_FALSE ||
|
||||
k == nkind.N_NIL || k == nkind.N_VOIDLIT ||
|
||||
k == nkind.N_IDENT || k == nkind.N_BIN ||
|
||||
k == nkind.N_UN || k == nkind.N_CALL ||
|
||||
k == nkind.N_INDEX || k == nkind.N_CAST ||
|
||||
k == nkind.N_STRUCTLIT || k == nkind.N_ARRLIT ||
|
||||
k == nkind.N_ALLOC || k == nkind.N_RECV ||
|
||||
k == nkind.N_SLICE || k == nkind.N_SPREAD ||
|
||||
k == nkind.N_TUPLE || k == nkind.N_TRYPROP ||
|
||||
k == nkind.N_TRYUNW || k == nkind.N_TYPETEST ||
|
||||
k == nkind.N_TYPEASSERT || k == nkind.N_YIELD ||
|
||||
k == nkind.N_MATCH) {
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
|
||||
// ---- type-level helpers (AST-level, no resolved tinfo) --------------
|
||||
@@ -1211,7 +1246,15 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
// field access into non-primitive types, etc).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `hint`: optional declared-type AST passed by the caller (let
|
||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||
// for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and
|
||||
// need the enclosing declared type to resolve. Ignored by every arm
|
||||
// in A.6.0; the param is plumbed here so the per-kind work that
|
||||
// follows doesn't ripple a fresh signature change. Mirrors harec's
|
||||
// `check_expression(..., result_type, ...)` per
|
||||
// `feedback_hare_frontend_reference.md`.
|
||||
fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
// #61 audit §1.8 — A.2 widens A.1's single N_INTLIT population to
|
||||
@@ -1321,7 +1364,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
};
|
||||
// Value form: `alloc(value)`.
|
||||
if (e.list.next == nil) {
|
||||
let argt: *node = exprtype(c, e.list);
|
||||
let argt: *node = exprtype(c, e.list, nil);
|
||||
let ptr: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||
ptr.lhs = argt;
|
||||
let nome: *node = mktname(c, "nomem");
|
||||
@@ -1412,7 +1455,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (k == nkind.N_TRYPROP) {
|
||||
// success unwrap: the success-variant type of operand's
|
||||
// tagged union.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -1432,7 +1475,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `e!` abort-on-error unwrap; success variant is what the
|
||||
// receiver gets, identical to `?` shape modulo control flow.
|
||||
// #31: required so `let p: *T = alloc(v)!;` resolves to *T.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -1804,7 +1847,9 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) { return; }; // no declared type, nothing to check
|
||||
if (n.rhs == nil) { return; }; // no init
|
||||
let src: *node = exprtype(c, n.rhs);
|
||||
// hint = nil for A.6.0; A.6.1 will pass n.lhs once STRUCTLIT/ARRLIT
|
||||
// arms consume it. Plumbing-only at this point.
|
||||
let src: *node = exprtype(c, n.rhs, nil);
|
||||
if (src == nil) { return; }; // can't infer
|
||||
// #45: alloc([], n) defers element type to the let-init context
|
||||
// (Hare-style). exprtype's alloc-slice branch synthesizes
|
||||
@@ -1873,7 +1918,7 @@ fn checkretassign(c: *checker, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
let src: *node = exprtype(c, n.lhs);
|
||||
let src: *node = exprtype(c, n.lhs, nil);
|
||||
if (src == nil) { return; };
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, c.fnret, src, &conf);
|
||||
|
||||
@@ -7316,6 +7316,10 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
// Walk only the base; the .field name is a member, not a
|
||||
// free identifier.
|
||||
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
|
||||
// A.6.0: branch returns early; stamp here so the post-walk
|
||||
// dispatch below sees N_DOT covered. exprtype N_DOT arm is
|
||||
// added in A.6.1; for now this is a no-op nil return.
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -7374,7 +7378,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
if (n.lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = n.lhs.str;
|
||||
if (streq(nm, "size") || streq(nm, "align") || streq(nm, "offset")) {
|
||||
let _t: *node = exprtype(c, n);
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -7398,6 +7402,37 @@ fn resolvewalk(c: *checker, n: *node) void = {
|
||||
scopedefine(c.cur, nm, skind.SK_VAR, nil, n);
|
||||
};
|
||||
};
|
||||
|
||||
// A.6.0: post-order dispatch of exprtype on every expression-yielding
|
||||
// node kind so n.type_ stamps fire universally — not only when reached
|
||||
// through checkletassign / checkretassign / checktryprop / the size-
|
||||
// align-offset fold. Mirrors cstage cmd/wcc/check.c cstmt's recursive
|
||||
// cexpr (cmd/wcc/check.c:1567 N_EXPRSTMT, :1570 N_RETURN, :1584 N_IF
|
||||
// cond, etc.). Plumbing-only: stamps fire from existing exprtype kind
|
||||
// arms (literals + idents); per-kind stamp coverage lands in A.6.1.
|
||||
// Stamps are tinfocache-backed idempotent so multi-walk via let /
|
||||
// return / try entry points is safe. N_DOT is dispatched in its own
|
||||
// early-return branch above; not listed here. N_LET / N_RETURN /
|
||||
// N_EXPRSTMT / N_IF / N_FOR / N_FORRANGE / N_BLOCK / N_MATCH-as-stmt
|
||||
// are not value-typed nodes; their expression children get stamped on
|
||||
// the recursive descent into them. Type-expression kinds (N_T*) are
|
||||
// covered separately by the tinfofornode block above.
|
||||
if (k == nkind.N_INTLIT || k == nkind.N_FLOATLIT ||
|
||||
k == nkind.N_STRLIT || k == nkind.N_RUNELIT ||
|
||||
k == nkind.N_TRUE || k == nkind.N_FALSE ||
|
||||
k == nkind.N_NIL || k == nkind.N_VOIDLIT ||
|
||||
k == nkind.N_IDENT || k == nkind.N_BIN ||
|
||||
k == nkind.N_UN || k == nkind.N_CALL ||
|
||||
k == nkind.N_INDEX || k == nkind.N_CAST ||
|
||||
k == nkind.N_STRUCTLIT || k == nkind.N_ARRLIT ||
|
||||
k == nkind.N_ALLOC || k == nkind.N_RECV ||
|
||||
k == nkind.N_SLICE || k == nkind.N_SPREAD ||
|
||||
k == nkind.N_TUPLE || k == nkind.N_TRYPROP ||
|
||||
k == nkind.N_TRYUNW || k == nkind.N_TYPETEST ||
|
||||
k == nkind.N_TYPEASSERT || k == nkind.N_YIELD ||
|
||||
k == nkind.N_MATCH) {
|
||||
let _t: *node = exprtype(c, n, nil);
|
||||
};
|
||||
};
|
||||
|
||||
// ---- type-level helpers (AST-level, no resolved tinfo) --------------
|
||||
@@ -8143,7 +8178,15 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
// field access into non-primitive types, etc).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `hint`: optional declared-type AST passed by the caller (let
|
||||
// target, assign target). nil = "no hint, derive from self". Threaded
|
||||
// for use by A.6.1's STRUCTLIT/ARRLIT arms which can't self-type and
|
||||
// need the enclosing declared type to resolve. Ignored by every arm
|
||||
// in A.6.0; the param is plumbed here so the per-kind work that
|
||||
// follows doesn't ripple a fresh signature change. Mirrors harec's
|
||||
// `check_expression(..., result_type, ...)` per
|
||||
// `feedback_hare_frontend_reference.md`.
|
||||
fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
// #61 audit §1.8 — A.2 widens A.1's single N_INTLIT population to
|
||||
@@ -8253,7 +8296,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
};
|
||||
// Value form: `alloc(value)`.
|
||||
if (e.list.next == nil) {
|
||||
let argt: *node = exprtype(c, e.list);
|
||||
let argt: *node = exprtype(c, e.list, nil);
|
||||
let ptr: *node = newnode(nkind.N_TPTR, "", 0, 0);
|
||||
ptr.lhs = argt;
|
||||
let nome: *node = mktname(c, "nomem");
|
||||
@@ -8344,7 +8387,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (k == nkind.N_TRYPROP) {
|
||||
// success unwrap: the success-variant type of operand's
|
||||
// tagged union.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -8364,7 +8407,7 @@ fn exprtype(c: *checker, e: *node) *node = {
|
||||
// `e!` abort-on-error unwrap; success variant is what the
|
||||
// receiver gets, identical to `?` shape modulo control flow.
|
||||
// #31: required so `let p: *T = alloc(v)!;` resolves to *T.
|
||||
let opt: *node = exprtype(c, e.lhs);
|
||||
let opt: *node = exprtype(c, e.lhs, nil);
|
||||
let ou: *node = resolvealias(c, unwrapbang(opt));
|
||||
if (ou == nil) { return nil; };
|
||||
if (ou.kind != nkind.N_TTAGGED) { return nil; };
|
||||
@@ -8736,7 +8779,9 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) { return; }; // no declared type, nothing to check
|
||||
if (n.rhs == nil) { return; }; // no init
|
||||
let src: *node = exprtype(c, n.rhs);
|
||||
// hint = nil for A.6.0; A.6.1 will pass n.lhs once STRUCTLIT/ARRLIT
|
||||
// arms consume it. Plumbing-only at this point.
|
||||
let src: *node = exprtype(c, n.rhs, nil);
|
||||
if (src == nil) { return; }; // can't infer
|
||||
// #45: alloc([], n) defers element type to the let-init context
|
||||
// (Hare-style). exprtype's alloc-slice branch synthesizes
|
||||
@@ -8805,7 +8850,7 @@ fn checkretassign(c: *checker, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
let src: *node = exprtype(c, n.lhs);
|
||||
let src: *node = exprtype(c, n.lhs, nil);
|
||||
if (src == nil) { return; };
|
||||
let conf: bool = false;
|
||||
let ok: bool = isassignable(c, c.fnret, src, &conf);
|
||||
|
||||
Reference in New Issue
Block a user