clj-kondo

2025-12-01T13:37:17.722809Z

hello, I may have found an edge case here. let me know if this is a known issue. This come from my actual code, but I tried to simplify it into this made up example of loop -> if -> clojure.core/match -> recur. here, clj-kondo will lint the first recur form as error Recur can only be used in tail position. but if the recur form is in another form like do or let, it doesn't lint as error file.clj

(require '[clojure.core.match :refer [match]])

(loop [[target & remaining] [{:hey "a"} {:hi "b"} {:hello "c"} {:hi "d"}]]
  (if (> (count remaining) 0)
    (match [target]
      [{:hey _}]
      (recur remaining) ;; <-- lint error here

      [{:hi _}]
      (do
        (println "hi" target)
        (recur remaining))

      :else (println "end"))
    (println "end")))
clj-kondo
clj-kondo --lint .\file.clj
.\file.clj:7:7: error: Recur can only be used in tail position.
linting took 708ms, errors: 1, warnings: 0
if it is inside when or directly inside loop however, no lint-error is reported. lastly, this is a working clojure code, or at least this is working babashka code
bb .\file.clj
hi {:hi b}
end

borkdude 2025-12-01T13:40:51.662149Z

seems like a bug. feel free to report an issue

šŸ‘šŸ¼ 1
borkdude 2025-12-01T13:41:42.549449Z

you can add a #_:clj-kondo/ignore to silence the warning

2025-12-01T13:44:18.687869Z

Thank you, I will post the issue. this isn't a big issue since I don't write the recur with just one form like that. Just happen write my code halfway and noticed this inconsistency.

borkdude 2025-12-01T13:46:07.180769Z

great, thanks for explaining the urgency :)

2025-12-01T13:56:31.533909Z

posted here, thank you for the response @borkdude! https://github.com/clj-kondo/clj-kondo/issues/2661

šŸ™ 1
pez 2025-12-01T21:02:24.207489Z

I don’t think reader conditionals should be marked as illegal just because it is not a .cljc extension on the file.

pez 2025-12-01T21:03:03.887929Z

This file uses the extension .fiddle and is a first class citizen in Calva. 😃

borkdude 2025-12-01T21:46:45.829409Z

that's how clojure/clojurescript work - you can disable that linter if you want

borkdude 2025-12-01T21:52:49.459789Z

I don't even know why clj-kondo is activated for .fiddle files. Maybe this is something you control in Calva. In that case you can maybe also control that it should be linted as cljc

pez 2025-12-01T22:11:19.225889Z

Calva is configured to treat fiddle files as Clojure-ish file. It gets all the service as any Clojure-ish files get, clojure-lsp, linting, etc. The Clojure repl doesn’t complain about the reader conditional. I don’t think the Clojure repl even knows what file extension the file has. It reads and evaluates. So does the ClojureScript repl.

; clj  hello-world.core 
#?(:cljs (js/console.log "cljc from js")
   :clj (.println System/out "cljc from jvm")
   :bb (.println System/out "cljc from bb"))
cljc from jvm

nil

; cljs  hello-world.core 
#?(:cljs (js/console.log "cljc from js")
   :clj (.println System/out "cljc from jvm")
   :bb (.println System/out "cljc from bb"))
cljc from js

nil

borkdude 2025-12-01T22:12:53.867109Z

The REPL is accepting of reader conditionals, but when code is loaded from a file, it's not accepting

borkdude 2025-12-01T22:14:16.975099Z

$ clj-kondo --lint /tmp/foo.fiddle
/tmp/foo.fiddle:1:1: error: Reader conditionals are only allowed in .cljc files
linting took 47ms, errors: 1, warnings: 0
$ clj-kondo --lint /tmp/foo.fiddle --lang cljc
linting took 13ms, errors: 0, warnings: 0

borkdude 2025-12-01T22:14:28.264429Z

you can make clj-kondo believe this is a cljc file in that way.

pez 2025-12-01T22:32:28.268939Z

Ah, thanks. You’re right, loading a file the repl complains. So then I am again happy that kondo has this warning. 😃

pez 2025-12-01T22:32:52.786569Z

You are absolutely right!

pez 2025-12-01T22:35:25.293559Z

> you can make clj-kondo believe this is a cljc file in that way Calva treats anything that isn’t explicitly targeted for a particular repl a bit like cljc. So that’s partly where I’m coming from. But if Clojure doesn’t want to play along, there’s not much Calva can do about it. I wonder what the reason could be to close that map….

borkdude 2025-12-01T22:37:06.912539Z

depends on how you evaluate stuff. you can bind a dynamic var to allow reader conditionals. Again, don't know anything about Calva's integration with this

pez 2025-12-01T22:41:24.181819Z

Good to know! Calva’s integration is super basic bare nrepl client. There’s nothing fancy going on at the Calva level at least. Enough moving parts in the stack below. 😃