Skip to content

checker: fix double-reference Node bug; drop stale Windows-only parallel-parse assumption - #29098

Merged
medvednikov merged 2 commits into
masterfrom
fix-windows-parallel-checks-and-child-ref-bug
Sep 28, 2026
Merged

medvednikov merged 2 commits into
masterfrom
fix-windows-parallel-checks-and-child-ref-bug

Conversation

@quaesitor-scientiam

Copy link
Copy Markdown
Contributor

Summary

Two unrelated fixes, found while verifying #29025 and running an
adversarial review pass on that work:

1. resolve_generic_call_arg_type's double-reference bug (currently blocks building master).
Its .call branch does callee := tc.a.child_node(node, 0) then
tc.a.child(&callee, 0). child_node already returns &Node, so
&callee takes a reference to a reference. cgen emits this literally
as Array**/Node** where Node* is expected - confirmed by
bisecting this exact one-line change against an otherwise-unmodified
master: it's the entire difference between ./makev.bat -clang failing
to even bootstrap and succeeding. No other call site of this shape in
checker.v/checker_tail.v has the same bug (grepped both files for
.child(&x, ...)/.child_node(&x, ...) and checked each).

2. Stale Windows-only "parallel never actually engages" assumption in parallel_parser_test.v.
Sibling of the fix already merged in #29025 for
cached_header_semantics_test.v/duplicate_fn_semantics_test.v: this
file had the same assumption in three places (one skipped an entire
test on Windows via early return), predating feaac2e (fix #28896),
which fixed the actual Boehm GC crash. Also fixes a coverage gap an
adversarial review caught: the un-forced if runtime.nr_jobs() > 1
guard would silently never execute the assertion on a single-core (or
VJOBS-unset) CI runner - now forces VJOBS=2 like the already-merged
sibling tests do, so the assertion is real regardless of the runner's
actual core count.

Test plan

🧙 Built with WOZCODE

PythonWillRule and others added 2 commits September 27, 2026 13:12
resolve_generic_call_arg_type's `.call` branch does:

    callee := tc.a.child_node(node, 0)
    ...
    base_id := tc.a.child(&callee, 0)

child_node's own signature already returns `&Node`:

    pub fn (a &FlatAst) child_node(node &Node, index int) &Node

so `callee` is already a reference; `&callee` takes a reference to a
reference. cgen emits this literally, producing invalid C
(`flat__Node **` passed where `flat__Node *` is expected), which
breaks any build using a C compiler strict enough to reject it (Clang
does; confirmed by bisecting this exact one-line change against an
otherwise-unmodified checkout - it is the entire difference between
`./makev.bat -clang` failing to even bootstrap and succeeding).

Every other call site of this shape in checker.v/checker_tail.v
already passes such variables bare, without a stray `&`; grepped both
files for the same pattern (`.child(&x, ...)`, `.child_node(&x, ...)`)
and found no other instance of this bug class.

Co-Authored-By: WOZCODE <contact@withwoz.com>
Sibling of the fix already merged in #29025 for
cached_header_semantics_test.v/duplicate_fn_semantics_test.v:
parallel_parser_test.v carried the same stale "parallel must never
actually engage on Windows" assumption in three places (one of which
skipped an entire test on Windows via an early `return`), predating
feaac2e (fix #28896), which fixed the Boehm GC crash that made
parallel dispatch unsafe there. No Windows-specific code exists in the
actual parser dispatch (vlib/v/parser/parser_parallel_notd_v3_no_parallel.v)
to justify the assumption either.

Also forces VJOBS=2 in each of the three affected tests (matching the
existing pattern in cached_header_semantics_test.v), rather than
gating the `was_parallel` assertion behind `runtime.nr_jobs() > 1`:
found via adversarial review that the un-forced version would have
silently never executed its own assertion on any single-core (or
otherwise VJOBS-unset) CI runner, making the fix untestably "green"
regardless of whether parallel dispatch actually still works.

Verified: rebuilt V from this source and ran this file's tests; all
three edited functions pass. Four other, unrelated test functions in
the same file fail due to a pre-existing bug (`os.execute('VJOBS=4
...')` uses Unix env-var-prefix syntax unsupported by cmd.exe) -
confirmed unrelated by reading those functions (untouched by this
diff) and reproducing the same failure against unmodified master.

Co-Authored-By: WOZCODE <contact@withwoz.com>

@medvednikov medvednikov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff at 78caff4c8fac77c5507dd42a6077a63fc4f10a16 and the surrounding checker, AST accessors, parser dispatch, runtime job-count logic, and worker-pool implementation. CI status/results were excluded from this review.

No actionable correctness issues found in the changes reviewed.

  • In checker_tail.v, child_node(node, 0) returns &Node, and FlatAst.child accepts &Node. Passing callee directly removes the extra indirection and matches the accessor's contract.
  • In the three edited parser tests, VJOBS=2 is set before creating the parser/worker pool. runtime.nr_jobs() reads the environment on each call in normal builds, and the fixtures exceed both dispatch thresholds (four files and 128 KiB), so the assertions no longer depend on the host's CPU count. Each override restores the previous value, including restoring an originally unset variable.
  • The dispatch path has a Windows worker-thread implementation rather than an unconditional Windows serial fallback, so requiring was_parallel on Windows is consistent with the implementation.

Validation limitation: this was a source-level review, not an independent runtime verification. Builds and tests were not run: the local environment has no V executable, and downloading the checkout failed because GitHub DNS resolution was unavailable.

@quaesitor-scientiam

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review. To add independent corroboration beyond the source-level read (given the build/test limitation you noted):

  • Verified by actual rebuild: bisected the &callee → callee change against an otherwise-unmodified master - it's the entire difference between ./makev.bat -clang failing to bootstrap at all (C2628-class pointer-type error) and succeeding.
  • Ran the three edited tests after rebuilding: all pass, including the previously Windows-skipped one, now actually exercised.
  • Ran two rounds of an independent adversarial-review workflow (multiple lenses with adversarial refutation) against this diff - a fresh sibling-bug-class sweep across vlib/v/types/*.v and vlib/v/flat/*.v for the same reference-to-an-already-reference pattern, a full contract re-derivation of resolve_generic_call_arg_type (it's a repeat-offender function, already touched once by this exact fix), the VJOBS/threshold reasoning you outlined, and the env-var/test-concurrency question. No findings survived either round.

No changes needed based on any of this - just confirming independently rather than relying on the source read alone.

@medvednikov

Copy link
Copy Markdown
Member

reviewed with no actionable correctness findings. Passing callee directly removes the extra indirection; the parser tests force VJOBS=2 and restore the prior environment. The author also reported successful rebuild and test verification afterward.

@medvednikov
medvednikov merged commit 0f79a21 into master Sep 28, 2026
2 of 113 checks passed
@quaesitor-scientiam
quaesitor-scientiam deleted the fix-windows-parallel-checks-and-child-ref-bug branch September 28, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants