How do I get core.typed to pass the following SHA256 code?

377 views Asked by At

I thought I would try out core.typed in the hope of removing the :pre conditions in the following code.

(ns quizry.sha256
  (:require
   [clojure.core.typed :as ct])
  (:import
   [java.security MessageDigest]))

(defn utf8-array
  "input as an array of UTF-8 bytes"
  [input]
  {:pre [(string? input)]}
  (.getBytes input "UTF-8"))

(defn sha256-digest
  "sha-256 array digest of input"
  [input]
  {:pre [(string? input)]}
  (let [hasher (MessageDigest/getInstance "SHA-256")]
    (->> input utf8-array (.update hasher))
    (.digest hasher)))

(ct/ann sha256 [String -> String])

(defn sha256
  "generates the sha256 string hash of input"
  [input]
  {:pre [(string? input)]}
  (let [digest (-> input sha256-digest seq)]
    (apply str (map #(format "%02x" (bit-and % 0xff)) digest))))

If I run (clojure.core.typed/check-ns), I get the following:

Start collecting quizry.sha256
Finished collecting quizry.sha256
Collected 1 namespaces in 621.542571 msecs
Not checking clojure.core.typed (tagged :collect-only in ns metadata)
Start checking quizry.sha256
Checked quizry.sha256 in 1337.109049 msecs
Checked 2 namespaces (approx. 2326 lines) in 1990.843467 msecs
Type Error (quizry/sha256.clj:11:3) Unresolved instance method invocation 

Add type hints to resolve the host call.

Suggested methods:

 java.lang.String
 \
  public byte[] getBytes()
  public void getBytes(int, int, byte[], int)
  public byte[] getBytes(java.nio.charset.Charset)
  public byte[] getBytes(java.lang.String).

Hint: use *warn-on-reflection* to identify reflective calls
in: (.getBytes input UTF-8)


Type Error (quizry/sha256.clj:18:5) Unresolved instance method invocation .

Hint: use *warn-on-reflection* to identify reflective calls
in: (.update hasher (utf8-array input))


Type Error (quizry/sha256.clj:19:5) Cannot call instance method java.security.MessageDigest/digest on type (clojure.core.typed/U java.security.MessageDigest nil)
in: (.digest hasher)


Type Error (quizry/sha256.clj:28:22) Static method clojure.lang.Numbers/and could not be applied to arguments:


Domains:
    ct/AnyInteger ct/AnyInteger

Arguments:
    ct/Any (ct/Value 255)

Ranges:
    java.lang.Long

in: (clojure.lang.Numbers/and p1__36892# 255)
in: (format %02x (clojure.lang.Numbers/and p1__36892# 255))
uizry/sha256.clj:28:2

ExceptionInfo Type Checker: Found 4 errors  clojure.core/ex-info (core.clj:4403)

I am new to core.typed, and don't really understand the errors. I'm looking to get core.type to pass the following namespace. I would appreciate it even more if you also explained what these errors mean, and what I should be thinking when I see them. Thank you.

1

There are 1 answers

0
Ambrose On

Unresolved reflection are type errors in core.typed.

This is how core.typed tells you it's found reflection, and its best guesses as to which methods you mean to invoke.

Suggested methods:

 java.lang.String
 \
  public byte[] getBytes()
  public void getBytes(int, int, byte[], int)
  public byte[] getBytes(java.nio.charset.Charset)
  public byte[] getBytes(java.lang.String).

Hint: use *warn-on-reflection* to identify reflective calls
in: (.getBytes input UTF-8)

So there are 4 possible methods on java.lang.String that core.typed has identified for the (.getBytes input UTF-8) call. You obviously want the one with String parameter, so add type hints as usual to resolve the method.

(defn utf8-array
  "input as an array of UTF-8 bytes"
  [^String input]
  {:pre [(string? input)]}
  (.getBytes input "UTF-8"))