[new] Add callsite info to compile-time errors

This commit is contained in:
Peter Taoussanis 2025-04-17 16:30:02 +02:00
parent 248e91f982
commit 345b125f6b
2 changed files with 27 additions and 26 deletions

View file

@ -230,7 +230,7 @@
(defn- args->opts [args] (defn- args->opts [args]
(case (count args) (case (count args)
0 {} 0 {}
1 (impl/valid-opts! (first args)) 1 (first args)
(apply hash-map args)))) (apply hash-map args))))
#?(:clj #?(:clj
@ -249,7 +249,9 @@
;; Used also for interop (tools.logging, SLF4J), etc. ;; Used also for interop (tools.logging, SLF4J), etc.
{:arglists (impl/arglists :signal-allowed?)} {:arglists (impl/arglists :signal-allowed?)}
[& args] `(impl/signal-allowed? ~(args->opts args)))) [& args]
(truss/keep-callsite
`(impl/signal-allowed? ~(args->opts args)))))
(comment (macroexpand '(signal-allowed? {:ns "my-ns"}))) (comment (macroexpand '(signal-allowed? {:ns "my-ns"})))

View file

@ -490,12 +490,12 @@
(comment (enc/qb 1e6 (inst+nsecs (enc/now-inst) 1e9))) (comment (enc/qb 1e6 (inst+nsecs (enc/now-inst) 1e9)))
#?(:clj #?(:clj
(defn valid-opts! [x] (defn- valid-opts! [macro-form macro-env caller opts]
(if (map? x) (if (map? opts)
(do x) (do opts)
;; We require const map keys, but vals may require eval (truss/ex-info!
(truss/ex-info! "Telemere signal opts must be a map with const (compile-time) keys." (str "`" caller "` needs compile-time map opts at "
{:opts (truss/typed-val x)})))) (sigs/format-callsite (enc/get-source macro-form macro-env)))))))
#?(:clj (defn- auto-> [form auto-form] (if (= form :auto) auto-form form))) #?(:clj (defn- auto-> [form auto-form] (if (= form :auto) auto-form form)))
#?(:clj #?(:clj
@ -504,8 +504,8 @@
Wrapped for public API." Wrapped for public API."
([ opts] (truss/keep-callsite `(signal-allowed? nil ~opts))) ([ opts] (truss/keep-callsite `(signal-allowed? nil ~opts)))
([base-opts opts] ([base-opts opts]
(valid-opts! (or base-opts {})) (valid-opts! &form &env 'telemere/signal-allowed? (or base-opts {}))
(valid-opts! (or opts {})) (valid-opts! &form &env 'telemere/signal-allowed? (or opts {}))
(let [opts (merge {:kind :generic, :level :info} base-opts opts) (let [opts (merge {:kind :generic, :level :info} base-opts opts)
{:keys [#_callsite-id elide? allow?]} {:keys [#_callsite-id elide? allow?]}
(sigs/filter-call (sigs/filter-call
@ -525,8 +525,8 @@
"Generic low-level signal creator. Wrapped for public API." "Generic low-level signal creator. Wrapped for public API."
([ opts] (truss/keep-callsite `(signal! nil ~opts))) ([ opts] (truss/keep-callsite `(signal! nil ~opts)))
([base-opts opts] ([base-opts opts]
(valid-opts! (or base-opts {})) (valid-opts! &form &env 'telemere/signal! (or base-opts {}))
(valid-opts! (or opts {})) (valid-opts! &form &env 'telemere/signal! (or opts {}))
(let [cljs? (boolean (:ns &env)) (let [cljs? (boolean (:ns &env))
clj? (not cljs?) clj? (not cljs?)
@ -574,10 +574,9 @@
trace? (get opts :trace? (boolean run-form)) trace? (get opts :trace? (boolean run-form))
_ _
(when-not (contains? #{true false nil} trace?) (when-not (contains? #{true false nil} trace?)
(truss/unexpected-arg! trace? (truss/ex-info!
{:param 'trace? (str "Signal needs compile-time `:trace?` value at "
:context `signal! (sigs/format-callsite ns-form coords))))
:msg "Expected constant (compile-time) `:trace?` boolean"}))
thread-form (when clj? `(enc/thread-info)) thread-form (when clj? `(enc/thread-info))
@ -621,16 +620,14 @@
_ ; Compile-time validation _ ; Compile-time validation
(do (do
(when (and run-form error-form) ; Ambiguous source of error (when (and run-form error-form) ; Ambiguous source of error
(truss/ex-info! "Signals cannot have both `:run` and `:error` opts at the same time" (truss/ex-info!
{:run-form run-form (str "Signal cannot have both `:run` and `:error` opts at "
:error-form error-form (sigs/format-callsite ns-form coords))))
:ns ns-form
:coords coords
:other-opts (dissoc opts :run :error)}))
(when-let [e (find opts :msg_)] ; Common typo/confusion (when-let [e (find opts :msg_)] ; Common typo/confusion
(truss/ex-info! "Signals cannot have `:msg_` opt (did you mean `:msg`?))" (truss/ex-info!
{:msg_ (truss/typed-val (val e))}))) (str "Signal cannot have `:msg_` opt (did you mean `:msg`?) at "
(sigs/format-callsite ns-form coords)))))
signal-form signal-form
(let [record-form (let [record-form
@ -640,7 +637,9 @@
[:run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs) [:run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs)
[:no-run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords (enc/host-info) ~'__thread ~'__otel-context1, ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil) [:no-run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords (enc/host-info) ~'__thread ~'__otel-context1, ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
[:no-run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil) [:no-run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
(truss/unexpected-arg! clause {:context :signal-constructor-args}))) (truss/ex-info!
(str "Unexpected signal constructor args at "
(sigs/format-callsite ns-form coords)))))
record-form record-form
(if-not run-form (if-not run-form