arohner / spectrum

Other
592 stars 20 forks source link

Add special case (ann) for clojure.core/keyword #24

Open setzer22 opened 7 years ago

setzer22 commented 7 years ago

clojure.core/keyword takes a string and returns a keyword. However, in order to support certain behaviours the function returns nil whenever it gets something that is not a string, symbol or keyword, instead of crashing.

This is unfortunate for type checking, since you cannot assume keyword will return not-nil even when the type checker can prove that it's being called with a string, forcing you to pollute the codebase with nilable specs.

This can be fixed with the following ann:

(spectrum.ann/ann #'keyword
                  (fn [fnspec argspec]
                    (if (#{#'clojure.core/symbol?
                           #'clojure.core/keyword?
                           #'clojure.core/string?}
                         (-> argspec :ps first :pred))
                      (-> fnspec
                          (update-in [:ret :ps] pop)
                          (update-in [:ret :ks] pop))
                      fnspec)))

Would this be a good addition to ann.clj?

arohner commented 7 years ago

Yes, keyword needs an ann, and would make a good addition. If you're interested in making a PR, a few notes:

(= (c/pred-spec #'keyword?) (check/type-of '(keyword x) {:x (c/pred-spec #'string?)}))

Thanks!

setzer22 commented 7 years ago

I'd be glad to contribute! I'll be looking at it this weekend. Thanks for the comments!

divs1210 commented 5 years ago

is this ticket still valid?

spectrum.repl> (f/infer-var #'keyword)
[fn
 {[cat ?t±897] [or [#'clojure.core/keyword? [value nil]]],
  [cat
   [or [#'clojure.core/string? [value nil]]]
   [or [#'clojure.core/string? [value nil]]]]
  [or [#'clojure.core/keyword? [value nil]]]}]