datalog: reject malformed dict body literals
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m26s

A dict in a rule body that isn't `{:neg <positive-lit>}` (the only
recognised dict shape) used to silently fall through every dispatch
clause in dl-rule-check-safety, contributing zero bound variables.
The user would then see a confusing "head variable(s) X do not
appear in any positive body literal" pointing at the head — not at
the actual bug in the body. Typos like `{:negs ...}` are the typical
trigger.

dl-process-lit! now flags both:

  - a dict that lacks :neg
  - a bare number / string / symbol used as a body lit

with a clear error naming the offending literal.

1 new regression test; conformance 265/265.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 08:04:03 +00:00
parent 00881f84eb
commit ba60db2eef
5 changed files with 50 additions and 8 deletions

View File

@@ -221,6 +221,19 @@
"banned(a). u(a). vip(X) :- u(X), not(not(banned(X))).")))
true)
;; A dict body literal that isn't `{:neg ...}` is almost always a
;; typo — it would otherwise silently fall through to a confusing
;; head-var-unbound safety error. Now caught with a clear message.
(dl-et-test!
"dict body lit without :neg rejected"
(dl-et-throws?
(fn ()
(let ((db (dl-make-db)))
(dl-add-rule! db
{:head (list (quote p) (quote X))
:body (list {:weird "stuff"})}))))
true)
(dl-et-test!
"unsafe head var"
(dl-et-throws? (fn () (dl-program "p(X, Y) :- q(X).")))