core-typed

robewald 2025-06-02T12:02:57.197829Z

I try to understand how HMaps are supposed to work when typechecking. Consider this code:

(ns ^:typed.clojure scr.foo
  (:require [typed.clojure :as t]))

(t/ann ^:no-check foo  [t/Str -> (HMap :complete? false)])
(defn foo [q]
  {(keyword q)  "hello"})

(t/ann bar [-> (HMap :mandatory {:f t/Str} :complete? false)])
(defn bar []
  (foo "f"))

(comment
  (t/check-ns-clj 'scr.foo))
Typechecking results in:
Type mismatch:
Expected: 	(t/HMap :mandatory {:f t/Str})
Actual: 	(t/HMap :mandatory {})
in:
(foo "f")
I expected that the type of bar is more specific than foo and thus typechecks. How can I achieve this?

2025-06-02T17:36:43.120269Z

You're right about everything except and thus typechecks. This would only type check if foo is more specific than bar.

2025-06-02T17:42:02.918849Z

As for how to achieve this, that's tough with Typed Clojure. The nuclear option is to make foo a macro. I don't think types are expressive enough to track (foo "f") => {:f "hello"}.

2025-06-02T17:42:57.685159Z

There might be a fancy way with t/Assoc, but I'm not sure.

2025-06-02T17:44:15.810259Z

I'm planning on having the type checker inline particular calls on an opt-in basis. It would be handy if the checker treated foo like a macro without having to actually change it.