wcc/ww: checktryprop flattens spread variants in the success count
The F8 multi-success gate counted a `...inner` spread as one variant, bypassing the multi-success reject. New trycountvariants recursively flattens spreads (the #209 recursion; cstage check.c:2160). Also carries the rule-7 deferral cites for the adjacent task-#50/#51 holes (exprtypeoftry lookups, desugarcallargs fn-ptr bail, checkisas) — the attempted scopelookupprefer hardening is byte-id-blocked by the #50 curmod layer (evidence in the task).
This commit is contained in:
@@ -15672,6 +15672,13 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
|||||||
};
|
};
|
||||||
}; };
|
}; };
|
||||||
let decl: *node = calleefndecl(c, n.lhs);
|
let decl: *node = calleefndecl(c, n.lhs);
|
||||||
|
// task #51: calleefndecl nils every fn-VALUE callee — a deref `(*fp)(...)`
|
||||||
|
// (N_UN), an SK_VAR fn-ptr ident, a struct-field fn call — so this bail
|
||||||
|
// skips the #258 array→slice desugar AND the general arg typecheck for
|
||||||
|
// them, and cgen then pushes raw array words where the callee reads a 24B
|
||||||
|
// slice header. cstage drives the same arg loop off the callee TYPE
|
||||||
|
// (cmd/wcc/check.c:1828 type_chase_named(cexpr(callee))). The type-keyed
|
||||||
|
// callee path is MECHANISM (not a checker gate) — filed as task #51.
|
||||||
if (decl == nil) { return; };
|
if (decl == nil) { return; };
|
||||||
let param: *node = decl.list;
|
let param: *node = decl.list;
|
||||||
let prev: *node = nil;
|
let prev: *node = nil;
|
||||||
@@ -16200,6 +16207,13 @@ fn checkisas(c: *checker, n: *node) void = {
|
|||||||
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
||||||
if (e == nil) { return nil; };
|
if (e == nil) { return nil; };
|
||||||
if (e.kind == nkind.N_IDENT) {
|
if (e.kind == nkind.N_IDENT) {
|
||||||
|
// #11a/task #50: this bare-leaf lookup wants curmod preference
|
||||||
|
// (scopelookupprefer, the #53/#55 family) but the swap BROKE the
|
||||||
|
// 995 self-rebuild byte-id — in the bundled self-compile ww's
|
||||||
|
// scopelookupprefer diverges from cstage's resolution (the same
|
||||||
|
// curmod-in-bundle layer that blocked #5), flipping a try-operand
|
||||||
|
// stamp in the selfhost source. Held at plain scopelookup until #50
|
||||||
|
// lands the bundle curmod fix; aligning here in isolation is unsound.
|
||||||
let s: *sym = scopelookup(c.cur, e.str);
|
let s: *sym = scopelookup(c.cur, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
@@ -16213,17 +16227,61 @@ fn exprtypeoftry(c: *checker, e: *node) *node = {
|
|||||||
let nm: str;
|
let nm: str;
|
||||||
nm.ptr = nil; nm.len = 0;
|
nm.ptr = nil; nm.len = 0;
|
||||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||||
|
// #11b/task #51: an N_DOT callee `mod.f()?` is looked up by BARE
|
||||||
|
// LEAF here, NOT via the module qualifier (callee.lhs) the way
|
||||||
|
// exprtype's own N_CALL arm does (:3095 scopelookupinmodule) — a
|
||||||
|
// cross-module same-leaf `f` misbinds. The mechanism fix (module-
|
||||||
|
// keyed callee resolution + the deref-callee `(*fp)()?` shape that
|
||||||
|
// returns nil below) rides task #51 with the fn-ptr-callee desugar.
|
||||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||||
if (nm.len == 0) { return nil; };
|
if (nm.len == 0) { return nil; };
|
||||||
|
// #11a/task #50: curmod preference wanted here too, held at plain
|
||||||
|
// scopelookup — the prefer swap broke 995 byte-id (bundle curmod
|
||||||
|
// divergence, same as the N_IDENT arm above + #5/#50).
|
||||||
let s: *sym = scopelookup(c.cur, nm);
|
let s: *sym = scopelookup(c.cur, nm);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.skind != skind.SK_FN) { return nil; };
|
if (s.skind != skind.SK_FN) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
return s.decl.lhs;
|
return s.decl.lhs;
|
||||||
};
|
};
|
||||||
|
// task #51: a deref callee `(*fp)()?` / SK_VAR fn-ptr ident / struct-
|
||||||
|
// field fn call returns nil here, so checktryprop silently bails and
|
||||||
|
// the F8 multi-success reject is skipped for those shapes. The fix
|
||||||
|
// (type-keyed operand resolution: peel TPTR → TFN.ret) is mechanism,
|
||||||
|
// filed with the fn-ptr-callee desugar as task #51 — NOT a checker gate.
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// trycountvariants — #38/F3 (review item 8): walk a tagged union's variant
|
||||||
|
// list FLATTENING `...inner` spreads, accumulating the success count and the
|
||||||
|
// has-error flag. cstage counts/checks the resolve_type-FLATTENED u->params
|
||||||
|
// (cmd/wcc/check.c:2160-2165 over the TK_ELLIPSIS-spliced chain); ww's
|
||||||
|
// checktryprop walked the raw AST, so a `(...inner | e)` counted the spread as
|
||||||
|
// ONE success and the F8 multi-success gate never fired — the exact silent
|
||||||
|
// accept the gate exists to catch (a valid bool success then treated as error
|
||||||
|
// by the single-tag-compare cgen). iserror is judged against the OUTER union
|
||||||
|
// (`outer`) throughout — taggedhaserr(outer) holds because the spread's sibling
|
||||||
|
// or a spliced member carries the error, so each flattened member routes
|
||||||
|
// through varianterr, matching cstage's per-param iserror. Mirrors the #209
|
||||||
|
// spread recursion tinfofornode already runs over vu.params (check.ww:2275).
|
||||||
|
fn trycountvariants(c: *checker, outer: *node, v: *node, nsuccp: *int,
|
||||||
|
haserrp: *bool, depth: i32) void = {
|
||||||
|
for (v != nil) {
|
||||||
|
if (v.op == tkind.TK_ELLIPSIS && depth < 8i32) {
|
||||||
|
let inner: *node = resolvealias(c, unwrapbang(v));
|
||||||
|
if (inner != nil && inner.kind == nkind.N_TTAGGED) {
|
||||||
|
trycountvariants(c, outer, inner.list, nsuccp,
|
||||||
|
haserrp, depth + 1i32);
|
||||||
|
v = v.next;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (iserrvariant(c, outer, v)) { *haserrp = true; }
|
||||||
|
else { *nsuccp += 1; };
|
||||||
|
v = v.next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn checktryprop(c: *checker, n: *node) void = {
|
fn checktryprop(c: *checker, n: *node) void = {
|
||||||
if (n == nil) { return; };
|
if (n == nil) { return; };
|
||||||
let t: *node = exprtypeoftry(c, n.lhs);
|
let t: *node = exprtypeoftry(c, n.lhs);
|
||||||
@@ -16240,11 +16298,9 @@ fn checktryprop(c: *checker, n: *node) void = {
|
|||||||
// N_TRYPROP/N_TRYUNW.
|
// N_TRYPROP/N_TRYUNW.
|
||||||
let haserr: bool = false;
|
let haserr: bool = false;
|
||||||
let nsucc: int = 0;
|
let nsucc: int = 0;
|
||||||
let v: *node = u.list;
|
// #38/F3 (review item 8): flatten `...inner` spreads so the F8
|
||||||
for (v != nil) {
|
// multi-success gate counts the spliced members, not the spread alias.
|
||||||
if (iserrvariant(c, u, v)) { haserr = true; } else { nsucc += 1; };
|
trycountvariants(c, u, u.list, &nsucc, &haserr, 0i32);
|
||||||
v = v.next;
|
|
||||||
};
|
|
||||||
if (nsucc > 1) {
|
if (nsucc > 1) {
|
||||||
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
||||||
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
||||||
|
|||||||
@@ -5252,6 +5252,13 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
|||||||
};
|
};
|
||||||
}; };
|
}; };
|
||||||
let decl: *node = calleefndecl(c, n.lhs);
|
let decl: *node = calleefndecl(c, n.lhs);
|
||||||
|
// task #51: calleefndecl nils every fn-VALUE callee — a deref `(*fp)(...)`
|
||||||
|
// (N_UN), an SK_VAR fn-ptr ident, a struct-field fn call — so this bail
|
||||||
|
// skips the #258 array→slice desugar AND the general arg typecheck for
|
||||||
|
// them, and cgen then pushes raw array words where the callee reads a 24B
|
||||||
|
// slice header. cstage drives the same arg loop off the callee TYPE
|
||||||
|
// (cmd/wcc/check.c:1828 type_chase_named(cexpr(callee))). The type-keyed
|
||||||
|
// callee path is MECHANISM (not a checker gate) — filed as task #51.
|
||||||
if (decl == nil) { return; };
|
if (decl == nil) { return; };
|
||||||
let param: *node = decl.list;
|
let param: *node = decl.list;
|
||||||
let prev: *node = nil;
|
let prev: *node = nil;
|
||||||
@@ -5780,6 +5787,13 @@ fn checkisas(c: *checker, n: *node) void = {
|
|||||||
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
||||||
if (e == nil) { return nil; };
|
if (e == nil) { return nil; };
|
||||||
if (e.kind == nkind.N_IDENT) {
|
if (e.kind == nkind.N_IDENT) {
|
||||||
|
// #11a/task #50: this bare-leaf lookup wants curmod preference
|
||||||
|
// (scopelookupprefer, the #53/#55 family) but the swap BROKE the
|
||||||
|
// 995 self-rebuild byte-id — in the bundled self-compile ww's
|
||||||
|
// scopelookupprefer diverges from cstage's resolution (the same
|
||||||
|
// curmod-in-bundle layer that blocked #5), flipping a try-operand
|
||||||
|
// stamp in the selfhost source. Held at plain scopelookup until #50
|
||||||
|
// lands the bundle curmod fix; aligning here in isolation is unsound.
|
||||||
let s: *sym = scopelookup(c.cur, e.str);
|
let s: *sym = scopelookup(c.cur, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
@@ -5793,17 +5807,61 @@ fn exprtypeoftry(c: *checker, e: *node) *node = {
|
|||||||
let nm: str;
|
let nm: str;
|
||||||
nm.ptr = nil; nm.len = 0;
|
nm.ptr = nil; nm.len = 0;
|
||||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||||
|
// #11b/task #51: an N_DOT callee `mod.f()?` is looked up by BARE
|
||||||
|
// LEAF here, NOT via the module qualifier (callee.lhs) the way
|
||||||
|
// exprtype's own N_CALL arm does (:3095 scopelookupinmodule) — a
|
||||||
|
// cross-module same-leaf `f` misbinds. The mechanism fix (module-
|
||||||
|
// keyed callee resolution + the deref-callee `(*fp)()?` shape that
|
||||||
|
// returns nil below) rides task #51 with the fn-ptr-callee desugar.
|
||||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||||
if (nm.len == 0) { return nil; };
|
if (nm.len == 0) { return nil; };
|
||||||
|
// #11a/task #50: curmod preference wanted here too, held at plain
|
||||||
|
// scopelookup — the prefer swap broke 995 byte-id (bundle curmod
|
||||||
|
// divergence, same as the N_IDENT arm above + #5/#50).
|
||||||
let s: *sym = scopelookup(c.cur, nm);
|
let s: *sym = scopelookup(c.cur, nm);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.skind != skind.SK_FN) { return nil; };
|
if (s.skind != skind.SK_FN) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
return s.decl.lhs;
|
return s.decl.lhs;
|
||||||
};
|
};
|
||||||
|
// task #51: a deref callee `(*fp)()?` / SK_VAR fn-ptr ident / struct-
|
||||||
|
// field fn call returns nil here, so checktryprop silently bails and
|
||||||
|
// the F8 multi-success reject is skipped for those shapes. The fix
|
||||||
|
// (type-keyed operand resolution: peel TPTR → TFN.ret) is mechanism,
|
||||||
|
// filed with the fn-ptr-callee desugar as task #51 — NOT a checker gate.
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// trycountvariants — #38/F3 (review item 8): walk a tagged union's variant
|
||||||
|
// list FLATTENING `...inner` spreads, accumulating the success count and the
|
||||||
|
// has-error flag. cstage counts/checks the resolve_type-FLATTENED u->params
|
||||||
|
// (cmd/wcc/check.c:2160-2165 over the TK_ELLIPSIS-spliced chain); ww's
|
||||||
|
// checktryprop walked the raw AST, so a `(...inner | e)` counted the spread as
|
||||||
|
// ONE success and the F8 multi-success gate never fired — the exact silent
|
||||||
|
// accept the gate exists to catch (a valid bool success then treated as error
|
||||||
|
// by the single-tag-compare cgen). iserror is judged against the OUTER union
|
||||||
|
// (`outer`) throughout — taggedhaserr(outer) holds because the spread's sibling
|
||||||
|
// or a spliced member carries the error, so each flattened member routes
|
||||||
|
// through varianterr, matching cstage's per-param iserror. Mirrors the #209
|
||||||
|
// spread recursion tinfofornode already runs over vu.params (check.ww:2275).
|
||||||
|
fn trycountvariants(c: *checker, outer: *node, v: *node, nsuccp: *int,
|
||||||
|
haserrp: *bool, depth: i32) void = {
|
||||||
|
for (v != nil) {
|
||||||
|
if (v.op == tkind.TK_ELLIPSIS && depth < 8i32) {
|
||||||
|
let inner: *node = resolvealias(c, unwrapbang(v));
|
||||||
|
if (inner != nil && inner.kind == nkind.N_TTAGGED) {
|
||||||
|
trycountvariants(c, outer, inner.list, nsuccp,
|
||||||
|
haserrp, depth + 1i32);
|
||||||
|
v = v.next;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (iserrvariant(c, outer, v)) { *haserrp = true; }
|
||||||
|
else { *nsuccp += 1; };
|
||||||
|
v = v.next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn checktryprop(c: *checker, n: *node) void = {
|
fn checktryprop(c: *checker, n: *node) void = {
|
||||||
if (n == nil) { return; };
|
if (n == nil) { return; };
|
||||||
let t: *node = exprtypeoftry(c, n.lhs);
|
let t: *node = exprtypeoftry(c, n.lhs);
|
||||||
@@ -5820,11 +5878,9 @@ fn checktryprop(c: *checker, n: *node) void = {
|
|||||||
// N_TRYPROP/N_TRYUNW.
|
// N_TRYPROP/N_TRYUNW.
|
||||||
let haserr: bool = false;
|
let haserr: bool = false;
|
||||||
let nsucc: int = 0;
|
let nsucc: int = 0;
|
||||||
let v: *node = u.list;
|
// #38/F3 (review item 8): flatten `...inner` spreads so the F8
|
||||||
for (v != nil) {
|
// multi-success gate counts the spliced members, not the spread alias.
|
||||||
if (iserrvariant(c, u, v)) { haserr = true; } else { nsucc += 1; };
|
trycountvariants(c, u, u.list, &nsucc, &haserr, 0i32);
|
||||||
v = v.next;
|
|
||||||
};
|
|
||||||
if (nsucc > 1) {
|
if (nsucc > 1) {
|
||||||
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
||||||
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
||||||
|
|||||||
@@ -15672,6 +15672,13 @@ fn desugarcallargs(c: *checker, n: *node) void = {
|
|||||||
};
|
};
|
||||||
}; };
|
}; };
|
||||||
let decl: *node = calleefndecl(c, n.lhs);
|
let decl: *node = calleefndecl(c, n.lhs);
|
||||||
|
// task #51: calleefndecl nils every fn-VALUE callee — a deref `(*fp)(...)`
|
||||||
|
// (N_UN), an SK_VAR fn-ptr ident, a struct-field fn call — so this bail
|
||||||
|
// skips the #258 array→slice desugar AND the general arg typecheck for
|
||||||
|
// them, and cgen then pushes raw array words where the callee reads a 24B
|
||||||
|
// slice header. cstage drives the same arg loop off the callee TYPE
|
||||||
|
// (cmd/wcc/check.c:1828 type_chase_named(cexpr(callee))). The type-keyed
|
||||||
|
// callee path is MECHANISM (not a checker gate) — filed as task #51.
|
||||||
if (decl == nil) { return; };
|
if (decl == nil) { return; };
|
||||||
let param: *node = decl.list;
|
let param: *node = decl.list;
|
||||||
let prev: *node = nil;
|
let prev: *node = nil;
|
||||||
@@ -16200,6 +16207,13 @@ fn checkisas(c: *checker, n: *node) void = {
|
|||||||
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
fn exprtypeoftry(c: *checker, e: *node) *node = {
|
||||||
if (e == nil) { return nil; };
|
if (e == nil) { return nil; };
|
||||||
if (e.kind == nkind.N_IDENT) {
|
if (e.kind == nkind.N_IDENT) {
|
||||||
|
// #11a/task #50: this bare-leaf lookup wants curmod preference
|
||||||
|
// (scopelookupprefer, the #53/#55 family) but the swap BROKE the
|
||||||
|
// 995 self-rebuild byte-id — in the bundled self-compile ww's
|
||||||
|
// scopelookupprefer diverges from cstage's resolution (the same
|
||||||
|
// curmod-in-bundle layer that blocked #5), flipping a try-operand
|
||||||
|
// stamp in the selfhost source. Held at plain scopelookup until #50
|
||||||
|
// lands the bundle curmod fix; aligning here in isolation is unsound.
|
||||||
let s: *sym = scopelookup(c.cur, e.str);
|
let s: *sym = scopelookup(c.cur, e.str);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
@@ -16213,17 +16227,61 @@ fn exprtypeoftry(c: *checker, e: *node) *node = {
|
|||||||
let nm: str;
|
let nm: str;
|
||||||
nm.ptr = nil; nm.len = 0;
|
nm.ptr = nil; nm.len = 0;
|
||||||
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };
|
||||||
|
// #11b/task #51: an N_DOT callee `mod.f()?` is looked up by BARE
|
||||||
|
// LEAF here, NOT via the module qualifier (callee.lhs) the way
|
||||||
|
// exprtype's own N_CALL arm does (:3095 scopelookupinmodule) — a
|
||||||
|
// cross-module same-leaf `f` misbinds. The mechanism fix (module-
|
||||||
|
// keyed callee resolution + the deref-callee `(*fp)()?` shape that
|
||||||
|
// returns nil below) rides task #51 with the fn-ptr-callee desugar.
|
||||||
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
if (callee.kind == nkind.N_DOT) { nm = callee.str; };
|
||||||
if (nm.len == 0) { return nil; };
|
if (nm.len == 0) { return nil; };
|
||||||
|
// #11a/task #50: curmod preference wanted here too, held at plain
|
||||||
|
// scopelookup — the prefer swap broke 995 byte-id (bundle curmod
|
||||||
|
// divergence, same as the N_IDENT arm above + #5/#50).
|
||||||
let s: *sym = scopelookup(c.cur, nm);
|
let s: *sym = scopelookup(c.cur, nm);
|
||||||
if (s == nil) { return nil; };
|
if (s == nil) { return nil; };
|
||||||
if (s.skind != skind.SK_FN) { return nil; };
|
if (s.skind != skind.SK_FN) { return nil; };
|
||||||
if (s.decl == nil) { return nil; };
|
if (s.decl == nil) { return nil; };
|
||||||
return s.decl.lhs;
|
return s.decl.lhs;
|
||||||
};
|
};
|
||||||
|
// task #51: a deref callee `(*fp)()?` / SK_VAR fn-ptr ident / struct-
|
||||||
|
// field fn call returns nil here, so checktryprop silently bails and
|
||||||
|
// the F8 multi-success reject is skipped for those shapes. The fix
|
||||||
|
// (type-keyed operand resolution: peel TPTR → TFN.ret) is mechanism,
|
||||||
|
// filed with the fn-ptr-callee desugar as task #51 — NOT a checker gate.
|
||||||
return nil;
|
return nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// trycountvariants — #38/F3 (review item 8): walk a tagged union's variant
|
||||||
|
// list FLATTENING `...inner` spreads, accumulating the success count and the
|
||||||
|
// has-error flag. cstage counts/checks the resolve_type-FLATTENED u->params
|
||||||
|
// (cmd/wcc/check.c:2160-2165 over the TK_ELLIPSIS-spliced chain); ww's
|
||||||
|
// checktryprop walked the raw AST, so a `(...inner | e)` counted the spread as
|
||||||
|
// ONE success and the F8 multi-success gate never fired — the exact silent
|
||||||
|
// accept the gate exists to catch (a valid bool success then treated as error
|
||||||
|
// by the single-tag-compare cgen). iserror is judged against the OUTER union
|
||||||
|
// (`outer`) throughout — taggedhaserr(outer) holds because the spread's sibling
|
||||||
|
// or a spliced member carries the error, so each flattened member routes
|
||||||
|
// through varianterr, matching cstage's per-param iserror. Mirrors the #209
|
||||||
|
// spread recursion tinfofornode already runs over vu.params (check.ww:2275).
|
||||||
|
fn trycountvariants(c: *checker, outer: *node, v: *node, nsuccp: *int,
|
||||||
|
haserrp: *bool, depth: i32) void = {
|
||||||
|
for (v != nil) {
|
||||||
|
if (v.op == tkind.TK_ELLIPSIS && depth < 8i32) {
|
||||||
|
let inner: *node = resolvealias(c, unwrapbang(v));
|
||||||
|
if (inner != nil && inner.kind == nkind.N_TTAGGED) {
|
||||||
|
trycountvariants(c, outer, inner.list, nsuccp,
|
||||||
|
haserrp, depth + 1i32);
|
||||||
|
v = v.next;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (iserrvariant(c, outer, v)) { *haserrp = true; }
|
||||||
|
else { *nsuccp += 1; };
|
||||||
|
v = v.next;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fn checktryprop(c: *checker, n: *node) void = {
|
fn checktryprop(c: *checker, n: *node) void = {
|
||||||
if (n == nil) { return; };
|
if (n == nil) { return; };
|
||||||
let t: *node = exprtypeoftry(c, n.lhs);
|
let t: *node = exprtypeoftry(c, n.lhs);
|
||||||
@@ -16240,11 +16298,9 @@ fn checktryprop(c: *checker, n: *node) void = {
|
|||||||
// N_TRYPROP/N_TRYUNW.
|
// N_TRYPROP/N_TRYUNW.
|
||||||
let haserr: bool = false;
|
let haserr: bool = false;
|
||||||
let nsucc: int = 0;
|
let nsucc: int = 0;
|
||||||
let v: *node = u.list;
|
// #38/F3 (review item 8): flatten `...inner` spreads so the F8
|
||||||
for (v != nil) {
|
// multi-success gate counts the spliced members, not the spread alias.
|
||||||
if (iserrvariant(c, u, v)) { haserr = true; } else { nsucc += 1; };
|
trycountvariants(c, u, u.list, &nsucc, &haserr, 0i32);
|
||||||
v = v.next;
|
|
||||||
};
|
|
||||||
if (nsucc > 1) {
|
if (nsucc > 1) {
|
||||||
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
if (n.kind == nkind.N_TRYPROP) { cerr("?"); } else { cerr("!"); };
|
||||||
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
cerr(": multi-success union unwired (task #14): bind and match instead\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user