Fork me on GitHub
#clj-kondo
<
2022-09-11
>
quoll18:09:24

Since I'm new to clj-kondo, I'm wondering if someone has advice for configuring around a construct... I'm calling a macro inside conditional compilation, where the macro generates a record definition that satisfies a protocol. clj-kondo is seeing one of the function definitions in this as a call to the function, and reports an error. The error in this case is that the function expects 3 args but that it's being called with 2 (what it's seeing at the arg vector and a let block that forms the body of the function). Any suggestions on how I might inform the linter that this is not a problem, please?

quoll18:09:28

Thank you!

borkdude18:09:14

possibly lint-as with deftype will work

quoll18:09:29

I did it with defrecord, and yes, it works well. Thank you!

quoll21:09:25

It's a call of (recur 1) which is asking to restart a function that's defined in a letfn and takes a single argument.

quoll21:09:08

But it says:

src/asami/durable/flat_file.clj:118:25: error: recur argument count mismatch (expected 0, got 1)
src/asami/durable/flat_file.clj:135:33: error: recur argument count mismatch (expected 0, got 1)

borkdude21:09:27

> I know I'm being a bit needy here Not at all, please do ask all the questions you want

borkdude21:09:54

I'm trying to repro that...

$ clj-kondo --lint - <<< '(letfn [(foo [x] (recur 1))])'
<stdin>:1:10: warning: unused binding foo
<stdin>:1:15: warning: unused binding x
linting took 15ms, errors: 0, warnings: 2
:thinking_face:

borkdude21:09:50

It could be a bug. Is it possible to narrow this down to a smaller example?

quoll21:09:03

I see that there was an https://github.com/clj-kondo/clj-kondo/issues/131 that was also a problem with arities in letfn, and it referred to something happening in #129

quoll21:09:10

Hmmm, I can try

borkdude21:09:22

I think I know what's going on, it's a defrecord + letfn thing

borkdude21:09:06

$ clj-kondo --lint - <<< '(defrecord Foo [] clojure.lang.ILookup (valAt [_ _] (letfn [(foo [x] (recur 1 2))])))'
<stdin>:1:62: warning: unused binding foo
<stdin>:1:67: warning: unused binding x
<stdin>:1:70: error: recur argument count mismatch (expected 0, got 2)

quoll21:09:29

you're faster than I 🙂

borkdude21:09:58

so what's happening here: clj-kondo compensates for the recur in valAt and subtracts the "this" argument but it forgets to turn that off for the letfn function

borkdude21:09:21

I'll file a bug. I you can ignore this with #_:clj-kondo/ignore

quoll21:09:30

Makes sense. Thank you!

borkdude21:09:47

so like this: #_:clj-kondo/ignore (recur 1)

quoll21:09:09

in the config file??

borkdude21:09:14

in the code

borkdude21:09:11

before the false positive you can insert #_:clj-kondo/ignore

quoll21:09:31

OIC. Thank you

quoll21:09:45

I was using the sledgehammer approach

quoll21:09:04

:linters {:invalid-arity {:skip-args [clojure.core/letfn]}}

borkdude21:09:55

or you could just use let + fn ? :) I usually don't use letfn at all unless I need mutually recursive functions which I never do

borkdude21:09:32

Posted the issue here: https://github.com/clj-kondo/clj-kondo/issues/1806 - I'll fix it before the next release (usually within a month)

quoll21:09:00

While that's reasonable, this code has been around a while, and there's nothing actually wrong with letfn, so I'll leave it for now

borkdude21:09:11

fair enough

borkdude21:09:35

and I also discovered that it's not just about letfn :) let+ fn has the same bug

👍 1
quoll21:09:22

any suggestions on how to create a minimum reproduction that leads to error: Unresolved symbol: format ?

borkdude21:09:11

is this .cljc ?

quoll21:09:37

yes! Thank you

quoll23:09:58

This is an awkward one. The following fails, claiming that fn is called with 1 arg but expects 2: https://github.com/quoll/asami/blob/a469640790e272ecad6d47bb00a687a3b0291722/src/asami/query.cljc#L350

quoll23:09:45

The map is creating a transducer that gets applied to a pair of seqs, so I can see how this might confuse the linter

quoll23:09:26

But I can't reproduce it on a smaller scale. For instance, this passes:

(sequence (comp (map (fn [a b] [a b])) cat) [1 2 3] [4 5 6])

quoll23:09:47

So too does code that doesn't work:

(sequence (comp (map (fn [a b c] [a b c])) cat) [1 2 3] [4 5 6])

quoll23:09:12

When I pass that to the linter, it works fine:

$ echo '(sequence (comp (map (fn [a b c] [a b c])) cat) [1 2 3] [4 5 6])' | clj-kondo --lint -
linting took 10ms, errors: 0, warnings: 0

quoll23:09:46

That's despite the code actually failing:

user=> (sequence (comp (map (fn [a b c] [a b c])) cat) [1 2 3] [4 5 6])
Execution error (ArityException) at user/eval1 (REPL:1).
Wrong number of args (2) passed to: user/eval1/fn--137

quoll23:09:29

so, my minimal examples all pass the linter, but the actual code incorrectly fails 🙂

quoll02:09:18

Speaking of letfn, it seems that the clj-kondo really doesn't like the plumatic schema version of letfn

borkdude09:09:07

@U051N6TTC clj-kondo has built-in support for some schema things, but I don't think letfn has ever come up.

borkdude09:09:31

if you could write it as a let + s/fn, it might be supported right now

borkdude09:09:01

About the invalid arity bug, it seems like clj-kondo is indeed confused about transducer vs. seq. This yields a similar but valid warning:

(comp (map (fn [results _]
             (map identity results))
           [])
      cat)

borkdude09:09:31

if you remove the [] the warning disappears (as it should)

borkdude09:09:36

I narrowed the example down to this in your ns:

(defn disjunction
  "Implements an OR operation by repeating a join across each arm of the operation,
   and concatenating the results"
  [graph
   part
   [_ & patterns]] ;; Discard the first element, since it is just the OR operator
  (sequence
   (comp (map (fn [_results _cols]))
         cat)
   []
   []))
but when I move this example to a standalone file, the error disappears

borkdude09:09:26

so what I'm trying now is to remove stuff until the error disappears

borkdude09:09:31

Oh lol, it's related to .cljc - repro:

(ns query)

(defn disjunction
  [_graph _part]
  (sequence
   (comp (map (fn [_results _cols]))
         cat)
   []
   []))
I think it's just a matter of adding cljs.core somewhere to fix it :/

borkdude09:09:35

Thanks for finding those bugs :-D

borkdude09:09:11

a workaround for now:

(comp (map #_:clj-kondo/ignore (fn [_results _cols])) cat)

quoll13:09:32

That’s what I did. Thank you for looking at it!