In this code, the type checker does not realize that calling (every? string? [v1 v2 v3]) is equivalent to (and (string? v1) (string? v2) (string v3)) when using it as a guard to ensure v1, v2, and v3 are all strings. This is probably related to the other type inference bug in #135.
(t/ann prepare-execute-one! [t/Str (t/HVec [(t/U t/Str t/Int) :*])) :-> (t/Option (t/Map t/Kw t/Any))])
(t/defalias Vars (t/HMap :mandatory {:v1 t/Str
:v2 t/Str
:v3 t/Str
:v4 t/Str
:v5 t/Str}
:complete? true))
(t/ann get-vars [:-> Vars])
(defn get-vars []
(let [res (prepare-execute-one!
"SELECT v1, v2, v3, v4, v5 FROM vars" [])
v1 (t/tc-ignore (:v1 res))
v2 (t/tc-ignore (:v2 res))
v4 (t/tc-ignore (:v3 res))
v4 (t/tc-ignore (:v4 res))
v5 (t/tc-ignore (:v5 res))]
(if (every? string? [v1 v2 v3 v4 v5])
{:v1 v1
:v2 v2
:v3 v3
:v4 v4
:v5 v5}
(throw ...))))
Instead the type checker gives the errors below.
Type mismatch:
Expected: t/Str
Actual: t/Any
in:
v1
Type mismatch:
Expected: t/Str
Actual: t/Any
in:
v2
and so on ...
However calling string? on each variable explicitly like this does type check.
(defn get-vars []
(let [res (prepare-execute-one!
"SELECT v1, v2, v3, v4, v5 FROM vars" [])
v1 (t/tc-ignore (:v1 res))
v2 (t/tc-ignore (:v2 res))
v4 (t/tc-ignore (:v3 res))
v4 (t/tc-ignore (:v4 res))
v5 (t/tc-ignore (:v5 res))]
(if (and (string? v1) (string? v2) (string? v3) (string? v4) (string? v5))
{:v1 v1
:v2 v2
:v3 v3
:v4 v4
:v5 v5}
(throw ...))))
In this code, the type checker does not realize that calling
(every? string? [v1 v2 v3])is equivalent to(and (string? v1) (string? v2) (string v3))when using it as a guard to ensure v1, v2, and v3 are all strings. This is probably related to the other type inference bug in #135.Instead the type checker gives the errors below.
However calling string? on each variable explicitly like this does type check.