Seven-Streams opened a new pull request, #711:
URL: https://github.com/apache/tvm-ffi/pull/711
## Summary
This PR completes the Rust structural traversal API by giving all four
structural operations a
typed callback and `#[dispatch(...)]` frontend while preserving the
distinction between
engine-driven and user-driven recursion.
| API | Recursion owner | Callback state model | Generated dispatch |
|---|---|---|---|
| `structural_walk` | Engine | `FnMut` capture / walker fields |
`#[dispatch(walk)]` |
| `structural_map` | Engine | `FnMut` capture / mapper fields |
`#[dispatch(map)]` |
| `structural_visit` | Callback or visitor | `VisitCallbacks<State, ...>` +
`VisitContext<State>` | `#[dispatch(visit)]` |
| `structural_mutate` | Callback or mutator | `MutateCallbacks<State, ...>`
+ `MutateContext<State>` | `#[dispatch(mutate)]` |
The callback-backed visit and mutate paths implement `StructuralVisitor` and
`StructuralMutator` directly. As a result, callbacks, generated dispatch
types, and hand-written
visitors/mutators now share the same mutable runtime protocol and registered
structural hooks.
## Motivation
Before this PR, the Rust walk/map layers already accepted typed callbacks,
but user-driven visit
and mutate required hand-written trait implementations. In addition,
`#[dispatch(visit)]` named
the engine-driven walk dispatcher rather than the `StructuralVisitor` layer,
leaving the four APIs
asymmetric.
This PR aligns the names and entry points with their recursion model, adds
lightweight callback
frontends for one-off user-driven traversals, and retains a fully
borrow-checked state model for
callbacks that recursively re-enter themselves.
## Changes
### Extend `#[dispatch]` to four explicit modes
- Add `dispatch(walk)` for engine-driven observers using `walk_*` handlers.
- Keep `dispatch(map)` for engine-driven replacements using `map_*` handlers.
- Make `dispatch(visit)` generate `StructuralVisitor` from user-driven
`visit_*` handlers.
- Add `dispatch(mutate)` to generate `StructuralMutator` from user-driven
`mutate_*` handlers.
- Preserve source-order, first-match dispatch over owned FFI values,
borrowed object nodes, and
catch-all `VisitValue`/`MapValue` handlers.
- Forward an optional trailing `DefRegionKind` argument in every mode.
- Use mode-specific fallback behavior: `Advance` for walk, no replacement
for map, default child
traversal for visit, and the appropriate copy/in-place default for mutate.
### Add callback-driven structural visitors
- Allow `structural_visit` to accept either `&mut StructuralVisitor`, one
typed callback, or a
nested callback tuple.
- Add `VisitCallbacks<State, ...>` for reusable callback chains with
ordinary mutable state.
- Add `VisitContext<State>` with access to state, the current value and
definition region,
selected-child recursion, and default child traversal.
- A matched callback owns traversal of its value; unmatched values use
default child traversal.
- Support `()`, `Result<()>`, `Option<VisitInterrupt>`, and
`Result<Option<VisitInterrupt>>` callback outcomes.
### Add callback-driven structural mutators
- Allow `structural_mutate` to accept either `&mut StructuralMutator`, one
typed callback, or a
nested callback tuple.
- Add `MutateCallbacks<State, ...>` for reusable callback chains with
ordinary mutable state.
- Add `MutateContext<State>` with access to state, the current value and
definition region,
borrowed-child mutation, owned-child maybe-in-place mutation, default
mutation, and
invocation-local variable remapping.
- A matched callback supplies the final value; unmatched values retain the
engine's current
copy/maybe-in-place permission and use default mutation.
- Keep `MutateContext::default_mutate()` on the copy path because the
callback may still hold a
shared borrow of the current value. Owned children can explicitly use
`maybe_inplace_mutate()` when reuse is safe.
### Make recursive callback state borrow-checked
- Visit and mutate callbacks remain `Fn`, allowing the same callback to be
recursively
re-entered.
- Callback code is stored independently behind `Rc`, while mutable state and
the active driver
remain in the callback wrapper.
- Recursive context methods require `&mut self`, so Rust rejects a state
borrow that remains live
across recursive visit/mutate calls instead of relying on external
`Cell`/`RefCell` state.
- Direct callbacks are wrapped in a temporary `VisitCallbacks<(), ...>` or
`MutateCallbacks<(), ...>`; users opt into state by constructing the
wrapper explicitly.
### Preserve structural runtime semantics
- Registered `__s_visit__`, `__s_mutate__`, and `__s_maybe_inplace_mutate__`
hooks continue to
receive the active Rust-backed visitor/mutator and can re-enter Rust
through the shared ABI.
- Definition-region propagation, reflected-field fallback, interrupt/error
context, panic
resumption, and nested traversal state restoration continue to work across
callback paths.
- Mutation keeps invocation-local `FreeVar`/`DAGNode` remapping and rechecks
uniqueness before an
in-place write.
- No C or C++ ABI changes are introduced.
## Compatibility note
The former walk-layer naming is intentionally changed:
- `#[dispatch(visit)]` with `visit_*` observer methods becomes
`#[dispatch(walk)]` with `walk_*`
methods.
- `VisitDispatch` becomes `WalkDispatch`.
- `DispatchVisitor` becomes `DispatchWalker`.
`#[dispatch(visit)]` now denotes the user-driven visitor layer and generates
`StructuralVisitor`. Existing hand-written `StructuralVisitor` and
`StructuralMutator` call sites
remain valid.
## Tests
- `cargo test --workspace`
- `cargo test --workspace --release`
- `cargo test --workspace --all-features`
- `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps`
- `uv run --group docs sphinx-build -W --keep-going -b html docs
docs/_build/html`
- Pre-commit hooks on all changed files
The expanded regression coverage includes callback first-match behavior,
nested tuples,
definition regions, selected-child recursion, stateful recursive re-entry,
interrupts, registered
hooks, reflection, nested traversals, panic/error propagation,
copy-on-write/in-place behavior,
and invocation-local identity remapping.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]