datalog: anonymous-renamer avoids user _anon<N> collision
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
The renamer for anonymous `_` variables started at counter 0 and
produced `_anon1, _anon2, ...` unconditionally. A user writing the
same naming convention would see their variables shadowed:
(dl-eval "p(a, b). p(c, d). q(_anon1) :- p(_anon1, _)."
"?- q(X).")
=> () ; should be ({:X a} {:X c})
The `_` got renamed to `_anon1` too, collapsing the two positions
of `p` to a single var (forcing args to be equal — which neither
tuple satisfies).
Fix: scan each rule (and query goal) for the highest `_anon<N>`
already present and start the renamer past it. New helpers
`dl-max-anon-num` / `dl-max-anon-num-list` / `dl-try-parse-int`
walk the rule tree; `dl-make-anon-renamer` now takes a `start`
argument; `dl-rename-anon-rule` and the query-time renamer in
`dl-query` both compute the start from the input.
1 regression test; conformance 275/275.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -428,7 +428,10 @@
|
||||
;; names.
|
||||
(let
|
||||
((goals (dl-query-coerce goal))
|
||||
(renamer (dl-make-anon-renamer)))
|
||||
;; Start the renamer past any `_anon<N>` symbols the user
|
||||
;; may have written in the query — avoids collision.
|
||||
(renamer
|
||||
(dl-make-anon-renamer (dl-max-anon-num-list goal 0 0))))
|
||||
(let
|
||||
((user-vars (dl-query-user-vars goals))
|
||||
(renamed (map (fn (g) (dl-rename-anon-lit g renamer)) goals)))
|
||||
|
||||
Reference in New Issue
Block a user