Error when checking types "First argument to TApp must be TFn, actual: Fn"

86 views
Skip to first unread message

Brendan Tobolaski

unread,
Jun 8, 2015, 11:33:53 PM6/8/15
to clojure-c...@googlegroups.com
I have the following namespace:

(ns geyser.rabbitmq
  (:require [langohr.core :as rmq]
            [langohr.channel :as lch]
            [langohr.basic :as lb]
            [clojure.core.typed :as t]))

(t/defalias ^:private rmq_options
  (t/HMap :optional {:host t/Str
                     :port t/Int
                     :username t/Str
                     :password t/Str
                     :vhost t/Str
                     :ssl t/Bool
                     :ssl-context t/Any
                     :authentication-mechanism t/Any
                     :executor t/Any}))

(t/ann langohr.core/connect [rmq_options -> t/Any])
(t/ann langohr.channel/open [t/Any -> t/Any])
(t/ann langohr.basic/publish [t/Any t/Str t/Any -> t/Nothing])

(t/ann rabbitmq-sender! [t/Str
                         rmq_options
                          (t/Fn [t/Int -> (t/Vec t/Str)])
                          -> (t/Fn [t/Int -> t/Nothing])])
(defn rabbitmq-sender!
  [exchange config messages]
  (let [connection (rmq/connect config)
        chan (lch/open connection)]
    (t/ann-form  (fn [n]
                   (dorun (map #(lb/publish chan "" %) (messages n))))
                (t/Fn [t/Int -> t/Nothing]))))


When I run lein typed check on it, I get this error: 

Building core.typed base environments ...
Finished building base environments
"Elapsed time: 10482.354066 msecs"
core.typed initialized.
Start collecting geyser.rabbitmq
Finished collecting geyser.rabbitmq
Collected 1 namespaces in 536.271041 msecs
Not checking langohr.core (does not depend on clojure.core.typed)
Not checking clojure.core.typed (does not depend on clojure.core.typed)
Not checking langohr.basic (does not depend on clojure.core.typed)
Not checking langohr.channel (does not depend on clojure.core.typed)
Start checking geyser.rabbitmq
Type Error (geyser/rabbitmq.clj:30:18) Internal Error (geyser/rabbitmq.clj:30:18) First argument to TApp must be TFn, actual: Fn
Type Checker: Found 1 error
Found errors
Subprocess failed

I have no idea what this error means. Can someone point me in the right direction? I'm using core.typed 0.3.0-alpha2 if that is of any assistance.

Ambrose Bonnaire-Sergeant

unread,
Jun 8, 2015, 11:55:08 PM6/8/15
to core.typed
This error is saying you can't invoke t/Fn. You really want t/IFn (t/Fn is a flag for something that is a function).

I can't remember what dorun does, but I assume it returns nil, not Nothing (which is either an infinite loop or an exception).

Thanks,
Ambrose
Message has been deleted

Ambrose Bonnaire-Sergeant

unread,
Aug 3, 2015, 3:37:45 AM8/3/15
to core.typed


On Mon, Aug 3, 2015 at 11:49 AM, Chris Cornelison <chris.co...@gmail.com> wrote:
I also get something similar, and don't understand how TApp/TFn relates my code.

(ns manifold.core.directories
  "Functions that return the parts of the Manifold standard
  directory structure. These are all illumina-specific"
  (:require
    [environ.core :refer [env]]
    [clojure.core.typed :refer [ann cf check-ns U Map Keyword Fn tc-ignore]]
    [clojure.tools.logging :as log]
    [me.raynes.fs :as fs])
  )


(ann ^:no-check environ.core/env (Map Keyword String))
(ann ^:no-check me.raynes.fs/file (Fn [(U java.io.File String) (U java.io.File String) * -> java.io.File]))

Should be
(ann ^:no-check me.raynes.fs/file (IFn [(U java.io.File String) (U java.io.File String) * -> java.io.File]))

 

(ann manifold [-> java.io.File])
(defn manifold
  "Retrieves the base Manifold data directory from the environment variable
  MANIFOLD_DATA_DIR. If this variable is not set, throws an exception."
  []
  (let [p (env :manifold-data-dir)]
    (if (nil? p)
      (let [msg "Missing MANIFOLD_DATA_DIR environment variable"]
        (tc-ignore (log/error msg))
        (throw (Exception. msg)))
      (fs/file p))))

Result of type checking...

$lein typed check
Initializing core.typed ...
Building core.typed base environments ...
Finished building base environments
"Elapsed time: 4023.466697 msecs"
core.typed initialized.
Start collecting manifold.core.process-ids
Finished collecting manifold.core.process-ids
Start collecting manifold.core.directories
Finished collecting manifold.core.directories
Collected 2 namespaces in 947.822073 msecs
Not checking clojure.core.typed (does not depend on clojure.core.typed)
Start checking manifold.core.process-ids
Checked manifold.core.process-ids in 773.500626 msecs
Not checking me.raynes.fs (does not depend on clojure.core.typed)
Not checking clojure.tools.logging (does not depend on clojure.core.typed)
Not checking environ.core (does not depend on clojure.core.typed)
Start checking manifold.core.directories
Type Error (manifold/core/directories.clj:26:7) Internal Error (manifold/core/directories.clj:26:7) First argument to TApp must be TFn, actual: Fn
Type Checker: Found 1 error
Found errors
Subprocess failed



Many other calls to (fs/file ...) in this module seem to type-check just fine.

Using clojure 1.7.0 and core.typed 0.3.9

Thanks,
Chris

Chris Cornelison

unread,
Aug 3, 2015, 10:14:06 AM8/3/15
to clojure-c...@googlegroups.com
Thanks!

I know there is 'tc-ignore' to ignore stuff in other's libraries you don't want to annotate, however it would be nice if there was some way to ignore certain namespaces more globally.  Take clojure.tools.logging for example. In a typical production codebase there are logging calls everywhere, and in general I'm not concerned about miss-using the logging library. But I am concerned about protecting the interface boundaries between components of my own systems.

Is tc-ignore the only option at this point?

Thanks,
Chris

Ambrose Bonnaire-Sergeant

unread,
Aug 3, 2015, 10:16:47 AM8/3/15
to core.typed
tc-ignore is the best option, perhaps write a wrapper macro for tools.logger that calls tc-ignore.

Thanks,
Ambrose
Reply all
Reply to author
Forward
0 new messages