fix: unary arithmetic type-error message no longer crashes the reporter

rewrite-message assumed janet's BINARY arithmetic dispatch error shape
("could not find method :+ for 1 or :r+ for "a""). Unary inc/dec/- on a
non-number produce "could not find method :+ for "x"" — no "or :r" clause
— so orpos was nil and the reporter itself threw "could not find method :+
for nil", burying the real error. Handle the unary form. Found auditing
the RFC 0006 checker's default (checker-off) path. Regression row in
cli-test.
This commit is contained in:
Yogthos 2026-06-13 12:26:56 -04:00
parent f2d65addc8
commit 37949ac602
2 changed files with 19 additions and 7 deletions

View file

@ -259,18 +259,24 @@
[msg] [msg]
(def msg (string msg)) (def msg (string msg))
(cond (cond
# janet polymorphic arithmetic: could not find method :+ for 1 or :r+ for "a" # janet polymorphic arithmetic. Binary: "could not find method :+ for 1 or
# :r+ for "a"". Unary (inc/dec/-): "could not find method :+ for "x"" — no
# "or :r" clause, so orpos is nil; handle both without crashing the reporter.
(string/has-prefix? "could not find method :" msg) (string/has-prefix? "could not find method :" msg)
(let [rest* (string/slice msg (length "could not find method :")) (let [rest* (string/slice msg (length "could not find method :"))
sp (string/find " " rest*) sp (string/find " " rest*)
op (string/slice rest* 0 sp) op (string/slice rest* 0 sp)
tail (string/slice rest* (+ sp (length " for "))) tail (string/slice rest* (+ sp (length " for ")))
orpos (string/find " or :r" tail) orpos (string/find " or :r" tail)]
a (string/slice tail 0 orpos) (if (nil? orpos)
forpos (string/find " for " tail (+ orpos 1)) # unary form: one operand
b (string/slice tail (+ forpos 5))] (string "Cannot " (get op-words op op) " " tail
(string "Cannot " (get op-words op op) " " a " and " b " — " op " expects numbers")
" — " op " expects numbers")) (let [a (string/slice tail 0 orpos)
forpos (string/find " for " tail (+ orpos 1))
b (string/slice tail (+ forpos 5))]
(string "Cannot " (get op-words op op) " " a " and " b
" — " op " expects numbers"))))
# janet fixed-arity: <function _r$ns/f--N> called with 2 arguments, expected 1 # janet fixed-arity: <function _r$ns/f--N> called with 2 arguments, expected 1
(and (string/has-prefix? "<function " msg) (string/find "> called with " msg)) (and (string/has-prefix? "<function " msg) (string/find "> called with " msg))
(let [nm-end (string/find ">" msg) (let [nm-end (string/find ">" msg)

View file

@ -45,6 +45,12 @@
(check "arith error message rewritten" (check "arith error message rewritten"
(run-err "-e" `(+ 1 "a")`) (run-err "-e" `(+ 1 "a")`)
(has `Cannot add 1 and "a"`)) (has `Cannot add 1 and "a"`))
# unary arithmetic (inc/dec) on a non-number: the host error has no "or :r"
# clause, which used to crash the rewriter itself — handle it (jolt audit)
(check "unary arith error does not crash the rewriter"
(run-err "-e" `(inc "x")`)
(fn [s] (and (string/find "expects numbers" s)
(nil? (string/find "could not find method" s)))))
(check "arity error names the fn" (check "arity error names the fn"
(run-err "-e" "(defn afn [x] x) (afn 1 2)") (run-err "-e" "(defn afn [x] x) (afn 1 2)")
(has "Wrong number of args (2) passed to: user/afn")) (has "Wrong number of args (2) passed to: user/afn"))