Skip to content

Aim step-into-child at the children a children() call forwards - #83

Merged
revarbat merged 1 commit into
mainfrom
to-child-forwarded
Aug 9, 2026
Merged

Aim step-into-child at the children a children() call forwards#83
revarbat merged 1 commit into
mainfrom
to-child-forwarded

Conversation

@revarbat

@revarbat revarbat commented Aug 8, 2026

Copy link
Copy Markdown
Member

Stepping to a child from inside a module's children(); ran the script to completion instead of stopping at the child.

Cause

childStatementPositions returned a node's own children. A children() call has none — it forwards the enclosing invocation's, which live on the context, not on the node.

With no target to match, the step degraded into a continue. So the one statement whose entire job is to run the children was the one place a debugger could not step into them:

paused at children();  →  targets used: set()   →  ran off the end

It now reads ctx.childrenNodes for that case:

paused at children();  →  targets used: {(…, 5)}  →  paused at line 5

Every forwarded child is returned even when an index argument (children(0), children([1:2])) will run only some — a position that is never reached can never be stopped at, so the extra targets are inert.

The reported cause was a red herring

This came from a report that step-into-child failed for a built-in child, with the plausible explanation that a builtin has no body to pause in. That was wrong, and I had briefly written it into a user-facing message before testing it.

cube() as a forwarded child steps fine now, and a user module failed identically before the fix. What mattered was where the pause was, not what the child happened to be.

Verification

DebugHooksChildren.ChildrenCallForwardsItsCallersChildrenAsStepTargets is new and negative-controlled: with the children() branch disabled it fails with "no statement-level stop at the children() call", and passes with it.

801 C++ tests pass. Against a local build, BelfrySCAD's 653 tests and its GUI verifiers pass, and to_child from children(); now lands on the child for both a user module and a builtin.

🤖 Generated with Claude Code

Stepping to a child from inside a module's `children();` ran the script to
completion instead of stopping at the child.

childStatementPositions returned a node's own children, and a `children()`
call has none -- it forwards the enclosing invocation's, which live on the
context, not on the node. With no target to match, the step degraded into
a continue: the one statement whose entire job is to run the children was
the one place a debugger could not step into them.

It now reads ctx.childrenNodes for that case. Every forwarded child is
returned even when an index argument (children(0), children([1:2])) will
run only some -- a position that is never reached can never be stopped at,
so the extra targets are inert.

Found while chasing a report that step-into-child failed for a built-in
child. The built-in was a red herring: cube() as a forwarded child steps
fine now, and a user module failed identically before. What mattered was
where the pause was, not what the child happened to be.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@revarbat
revarbat merged commit af0ff89 into main Aug 9, 2026
3 checks passed
@revarbat
revarbat deleted the to-child-forwarded branch August 9, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant