Repository navigation
wam_rust: R−1 baseline fixes, align nested execution, cut and ITE with SWI (D129–D134) - #4356
Merged
Merged
Conversation
The lowered emitter wrote Value::Atom("x".to_string()) and
Value::Unbound(format!(..)), which do not compile since D96 made the
payload a Sym (an interner id under the default intern feature). Emit
"x".into() and WamState::fresh_var_sym instead; same names, no behavior
change.
Adds tests/test_wam_rust_baseline_fixes.pl, the R-1 SWI-comparison
harness, with the R-1f programs (lowered atom constants, get_nil, fresh
variables) built under default features and under
--no-default-features --features decorate_sort. The lowered exec tests
and the cut-semantics driver build their own inputs with .into() now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
catch/3 (goal and recovery), lowered call/execute, lowered_dispatch and the dynamic rule-body solver ran nested code without a backtrack floor, so a goal failing inside the nested run resumed the caller's choice points. Each now saves backtrack_floor, sets it to its entry depth (the mechanism call_goal_once already uses) and restores it on every exit. The hybrid-wrapper backtrack loops in rust_target.pl are unchanged: each wrapper starts with reset_query(), so no older caller choice point exists. Harness cases catch_floor, catch_rec_floor, lower_floor, lower_floor_ex and dyn_floor now match SWI in interpreter and functions mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
BeginAggregate cleared the single aggregate_acc and finalisation cleared it again, so an aggregate nested in another aggregate's goal wiped the outer one's solutions (findall over a findall gave [b] for [a,b]). BeginAggregate now parks the enclosing accumulator in its frame's data after the continuation pc, and finalisation swaps it back before any exit and finalises from the frame's own list. Harness cases nested, nested_bag and nested_fail match SWI in interpreter and functions mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
After an if-then-else (or disjunction) the shared compiler keeps one branch's variable map, so a Y variable first seen inside the construct was initialised on one path only: a failed condition left the slot absent for the read after the ITE (ite_map(no,R) gave [] for [a,b]; rundoite failed interpreted but succeeded lowered), and a variable first seen in the else branch was re-created fresh after the ITE. Rust-only fix, shared compiler unchanged: the Rust target rewrites each predicate's WAM text so such a Yn gets put_variable Yn, Yn before the outermost guard and its later first-occurrence instructions become value forms. Both the instruction table and the lowered emitter read the rewritten text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
The cut barrier B0 was a machine register that every Allocate overwrote and nothing restored, so after a call whose callee allocated, a cut in the caller used the callee's barrier (cut_after_call printed first and fallback in the interpreter). As in the standard WAM, the environment frame now keeps the caller's B0: Allocate saves it, Deallocate and the fused deallocate-and-proceed arms restore it. Harness cases cut_after_call and cut_in_agg match SWI in interpreter and functions mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
catch/3 meta-called its goal with the cut barrier left at the enclosing clause's B0, so a cut inside the goal removed the caller's choice points. Set the barrier to the entry depth around the goal, as call_goal_once does; catch/3 stays first-solution. Harness cases catch_cut (oracled with the first-solution reading of catch/3) and catch_cut_local match in interpreter and functions mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase R−1 of the heap-cell rewrite design (
docs/proposals/wam_rust_heap_cell_rewrite_design.md§12.1): fix, on today's runtime, the places where the Rust WAM target differs from SWI-Prolog, so the rewrite targets correct behaviour instead of emulating bugs. One commit per item, each with its own ledger row. A shared report is indocs/reports/wam_rust_r_minus_1_baseline_fixes.md.internfeaturecatch/3goal and recovery, loweredcall/execute/lowered_dispatch, and the dynamic rule-body solvercatch_floor:[ok]vs[]→[ok](alsolower_floor,dyn_floor)nested:[[a,b]]vs[[b]]→[[a,b]]wam_target.plunchanged): permanent variables first bound inside an ITE are initialized before the guard, limited to the code the guard reachesite_map(no,R):[a,b]vs[]→[a,b]; lowered and interpreter now agree onrundoiteAllocate, restored atDeallocate(standard WAM)cut_after_call:[first]vs[first,fallback]→[first]catch/3goal is opaque to cutcatch_cutwas broken →[a,c]catch/3stays first-solution by design, socatch_cutgives[a,c]where SWI gives[a,b,c]. The harness checks it against SWI'scatch(once(G),C,R)and asserts the difference explicitly.R−1a and the hybrid wrappers: the
rust_target.plhybrid wrappers were left unchanged on purpose. Each starts withvm.reset_query(), so no older caller choice point can exist and a floor would be a no-op.Tests
tests/test_wam_rust_baseline_fixes.pl(92 tests):--no-default-featuresbuild;.into()literal form.Verification
--benchstdout at N=40 and N=5000 arecmp-identical to the base after every commit. The re-freeze records an unchanged baseline.Found, not fixed (documented in the report; outside R−1)
call/executeof a runtime builtin with no label (e.g.catch/3) returns false;','/2goal functor as"/2";\+/1builtin arm uses a sentinel, not a floor (not reached under default options);catch/3recovery is still transparent to cut;🤖 Generated with Claude Code
https://claude.ai/code/session_013PJqq7jMzces6bMwTnPbpd
Generated by Claude Code