错误的类型仍然使用 clojure core.typed 编译?

Wrong types still compile with clojure core.typed?

项目文件:

(defproject testclojure "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.clojure/core.typed "0.2.84"]
                 [alembic "0.3.2"]]
  :main ^:skip-aot testclojure.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

代码:

(ns testclojure.core
  (:gen-class)
  (:require [clojure.core.typed :refer [ann AnyInteger check-ns]])
  (:import [clojure.lang ISeq]))

(ann ^:no-check clojure.core/mod [AnyInteger AnyInteger -> AnyInteger])

(ann div-by [AnyInteger AnyInteger -> Boolean])
(defn div-by [x y]
  (== (mod y x) 0))

(ann div-by-3-or-5 [AnyInteger -> Boolean])
(defn div-by-3-or-5 [x]
  (or (div-by 3 x) (div-by 5 x)))

(ann euler1 [AnyInteger -> AnyInteger])
(defn euler1 [n]
  (reduce + (filter div-by-3-or-5 (range n))))

(ann -main [-> nil] )
(defn -main []
  (prn (euler1 "a")))

lein compile 完全没有错误。

正如 check-ns 的文档字符串所说:

Do not use check-ns within a checked namespace. It is intended to be used at the REPL or within a unit test. Suggested idiom for clojure.test: (is (check-ns 'your.ns))

如果你把它放在 test/testclojure/core_test.clj:

(ns testclojure.core-test
  (:require [clojure.test :refer :all]
            [clojure.core.typed :refer [check-ns]]
            testclojure.core))

(deftest core-typed
  (is (check-ns 'testclojure.core)))

lein test 会正确地抱怨类型问题:

lein test testclojure.core-test
Initializing core.typed ...
Building core.typed base environments ...
Finished building base environments
"Elapsed time: 4251.270066 msecs"
core.typed initialized.
Start collecting testclojure.core
WARNING: Duplicate var annotation:  clojure.core/mod
Finished collecting testclojure.core
Collected 1 namespaces in 833.458074 msecs
Not checking clojure.core.typed (does not depend on clojure.core.typed)
Start checking testclojure.core
Checked testclojure.core in 992.400431 msecs
Checked 2 namespaces  in 1843.974821 msecs
Type Error (testclojure/core.clj:22:8) Function euler1 could not be applied to arguments:


Domains:
    AnyInteger

Arguments:
    (clojure.core.typed/Val "a")

Ranges:
    AnyInteger

in: (euler1 "a")
in: (euler1 a)



lein test :only testclojure.core-test/core-typed

ERROR in (core-typed) (core.clj:4403)
expected: (check-ns (quote testclojure.core))
  actual: clojure.lang.ExceptionInfo: Type Checker: Found 1 error
 at clojure.core$ex_info.invoke (core.clj:4403)
    clojure.core.typed.errors$print_errors_BANG_.invoke (errors.clj:234)
    clojure.core.typed.check_ns_common$check_ns$fn__24049.invoke (check_ns_common.clj:114)
    clojure.lang.AFn.applyToHelper (AFn.java:152)
    clojure.lang.AFn.applyTo (AFn.java:144)
    clojure.core$apply.invoke (core.clj:624)
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1862)
    clojure.lang.RestFn.invoke (RestFn.java:425)
    clojure.core.typed.check_ns_common$check_ns.doInvoke (check_ns_common.clj:112)
    clojure.lang.RestFn.invoke (RestFn.java:425)
    clojure.lang.AFn.applyToHelper (AFn.java:156)
    clojure.lang.RestFn.applyTo (RestFn.java:132)
    clojure.core$apply.invoke (core.clj:628)
    clojure.core.typed.check_ns_clj$check_ns.doInvoke (check_ns_clj.clj:23)
    clojure.lang.RestFn.invoke (RestFn.java:410)
    clojure.lang.AFn.applyToHelper (AFn.java:154)
    clojure.lang.RestFn.applyTo (RestFn.java:132)
    clojure.core$apply.invoke (core.clj:626)
    clojure.core.typed$check_ns.doInvoke (typed.clj:2241)
    clojure.lang.RestFn.invoke (RestFn.java:410)
    clojure.lang.AFn.applyToHelper (AFn.java:154)
    clojure.lang.RestFn.applyTo (RestFn.java:132)
    clojure.core$apply.invoke (core.clj:624)
    testclojure.core_test/fn (core_test.clj:7)
    clojure.test$test_var$fn__7187.invoke (test.clj:704)
    clojure.test$test_var.invoke (test.clj:704)
    clojure.test$test_vars$fn__7209$fn__7214.invoke (test.clj:722)
    clojure.test$default_fixture.invoke (test.clj:674)
    clojure.test$test_vars$fn__7209.invoke (test.clj:722)
    clojure.test$default_fixture.invoke (test.clj:674)
    clojure.test$test_vars.invoke (test.clj:718)
    clojure.test$test_all_vars.invoke (test.clj:728)
    clojure.test$test_ns.invoke (test.clj:747)
    clojure.core$map$fn__4245.invoke (core.clj:2559)
    clojure.lang.LazySeq.sval (LazySeq.java:40)
    clojure.lang.LazySeq.seq (LazySeq.java:49)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1654)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:626)
    clojure.test$run_tests.doInvoke (test.clj:762)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:624)
    user$eval85$fn__140$fn__171.invoke (form-init5812871912759411988.clj:1)
    user$eval85$fn__140$fn__141.invoke (form-init5812871912759411988.clj:1)
    user$eval85$fn__140.invoke (form-init5812871912759411988.clj:1)
    user$eval85.invoke (form-init5812871912759411988.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:6703)
    clojure.lang.Compiler.eval (Compiler.java:6693)
    clojure.lang.Compiler.load (Compiler.java:7130)
    clojure.lang.Compiler.loadFile (Compiler.java:7086)
    clojure.main$load_script.invoke (main.clj:274)
    clojure.main$init_opt.invoke (main.clj:279)
    clojure.main$initialize.invoke (main.clj:307)
    clojure.main$null_opt.invoke (main.clj:342)
    clojure.main$main.doInvoke (main.clj:420)
    clojure.lang.RestFn.invoke (RestFn.java:421)
    clojure.lang.Var.invoke (Var.java:383)
    clojure.lang.AFn.applyToHelper (AFn.java:156)
    clojure.lang.Var.applyTo (Var.java:700)
    clojure.main.main (main.java:37)

Ran 1 tests containing 1 assertions.
0 failures, 1 errors.
Tests failed.