Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Check for>. Tweak subtyping for primitive int.

  • Loading branch information...
commit 9f1ee851096b29d68a2e0f92a492f89aaa854f56 1 parent 2450898
@frenchy64 frenchy64 authored
View
104 src/main/clojure/clojure/core/typed.clj
@@ -96,14 +96,114 @@
(defn loop>-ann [loop-of bnding-types]
loop-of)
+(defmacro for>
+ "Like for but requires annotation for each loop variable:
+ [a [1 2]] becomes [[a :- Long] [1 2]]
+ Also requires annotation for return type.
+
+ eg.
+ (for> :- Number
+ [[a :- (U nil AnyInteger)] [1 nil 2 3]
+ :when a]
+ (inc a))"
+ [tk ret-ann seq-exprs body-expr]
+ (@#'clojure.core/assert-args
+ (vector? seq-exprs) "a vector for its binding"
+ (even? (count seq-exprs)) "an even number of forms in binding vector")
+ (assert (#{:-} tk))
+ (let [to-groups (fn [seq-exprs]
+ (@#'clojure.core/reduce1 (fn [groups [k v]]
+ (if (keyword? k)
+ (conj (pop groups) (conj (peek groups) [k v]))
+ (conj groups [k v])))
+ [] (partition 2 seq-exprs)))
+ err (fn [& msg] (throw (IllegalArgumentException. ^String (apply str msg))))
+ emit-bind (fn emit-bind [[[bind expr & mod-pairs]
+ & [[_ next-expr] :as next-groups]]]
+ (let [_ (assert (and (vector? bind)
+ (#{3} (count bind))
+ (#{:-} (second bind)))
+ "Binder must be of the form [lhs :- type]")
+ bind-ann (nth bind 2)
+ bind (nth bind 0)
+ giter (gensym "iter__")
+ gxs (gensym "s__")
+ do-mod (fn do-mod [[[k v :as pair] & etc]]
+ (cond
+ (= k :let) `(let ~v ~(do-mod etc))
+ (= k :while) `(when ~v ~(do-mod etc))
+ (= k :when) `(if ~v
+ ~(do-mod etc)
+ (recur (rest ~gxs)))
+ (keyword? k) (err "Invalid 'for' keyword " k)
+ next-groups
+ `(let [iterys# ~(emit-bind next-groups)
+ fs# (seq (iterys# ~next-expr))]
+ (if fs#
+ (concat fs# (~giter (rest ~gxs)))
+ (recur (rest ~gxs))))
+ :else `(cons ~body-expr
+ (~giter (rest ~gxs)))))]
+ (if next-groups
+ #_"not the inner-most loop"
+ `(ann-form
+ (fn ~giter [~gxs]
+ (lazy-seq
+ (loop> [[~gxs :- (~'clojure.core.typed/Option (~'clojure.lang.Seqable ~bind-ann))] ~gxs]
+ (when-first [~bind ~gxs]
+ ~(do-mod mod-pairs)))))
+ [(~'clojure.core.typed/Option (~'clojure.lang.Seqable ~bind-ann)) ~'-> (~'clojure.lang.LazySeq ~ret-ann)])
+ #_"inner-most loop"
+ (let [gi (gensym "i__")
+ gb (gensym "b__")
+ do-cmod (fn do-cmod [[[k v :as pair] & etc]]
+ (cond
+ (= k :let) `(let ~v ~(do-cmod etc))
+ (= k :while) `(when ~v ~(do-cmod etc))
+ (= k :when) `(if ~v
+ ~(do-cmod etc)
+ (recur
+ (unchecked-inc ~gi)))
+ (keyword? k)
+ (err "Invalid 'for' keyword " k)
+ :else
+ `(do (chunk-append ~gb ~body-expr)
+ (recur (unchecked-inc ~gi)))))]
+ `(ann-form
+ (fn ~giter [~gxs]
+ (lazy-seq
+ (loop> [[~gxs :- (~'clojure.core.typed/Option (~'clojure.lang.Seqable ~bind-ann))] ~gxs]
+ (when-let [~gxs (seq ~gxs)]
+ (if (chunked-seq? ~gxs)
+ (let [c# (chunk-first ~gxs)
+ size# (int (count c#))
+ ~gb (ann-form (chunk-buffer size#)
+ (~'clojure.lang.ChunkBuffer Number))]
+ (if (loop> [[~gi :- (~'U ~'Long ~'Integer)] (int 0)]
+ (if (< ~gi size#)
+ (let [;~bind (.nth c# ~gi)]
+ ~bind (nth c# ~gi)]
+ ~(do-cmod mod-pairs))
+ true))
+ (chunk-cons
+ (chunk ~gb)
+ (~giter (chunk-rest ~gxs)))
+ (chunk-cons (chunk ~gb) nil)))
+ (let [~bind (first ~gxs)]
+ ~(do-mod mod-pairs)))))))
+ [(~'clojure.core.typed/Option (~'clojure.lang.Seqable ~bind-ann)) ~'->
+ (~'clojure.lang.LazySeq ~ret-ann)])))))]
+ `(let [iter# ~(emit-bind (to-groups seq-exprs))]
+ (iter# ~(second seq-exprs)))))
+
(defmacro doseq>
"Like doseq but requires annotation for each loop variable:
[a [1 2]] becomes [[a :- Long] [1 2]]
eg.
(doseq> [[a :- (U nil AnyInteger)] [1 nil 2 3]
- :when a]
- (inc a))"
+ :when a]
+ (inc a))"
[seq-exprs & body]
(@#'clojure.core/assert-args
(vector? seq-exprs) "a vector for its binding"
View
2  src/main/clojure/clojure/core/typed/alter.clj
@@ -35,6 +35,8 @@
{Seqable (Seqable a)
IPersistentCollection (IPersistentCollection a)})
+(alter-class clojure.lang.ChunkBuffer [[a :variance :invariant]])
+
(alter-class clojure.lang.IChunkedSeq [[a :variance :covariant]]
:replace
{Seqable (Seqable a)
View
14 src/main/clojure/clojure/core/typed/ann.clj
@@ -612,5 +612,17 @@
[(Seqable x) -> (clojure.lang.IChunk x)]))
(ann clojure.core/chunk-rest
(All [x]
- [(Seqable x) -> (ISeq x)]))
+ [(Seqable x) -> (Seqable x)]))
+(ann clojure.core/chunk-buffer
+ (All [x]
+ [(U Integer Long) -> (clojure.lang.ChunkBuffer x)]))
+(ann clojure.core/chunk
+ (All [x]
+ [(clojure.lang.ChunkBuffer x) -> (clojure.lang.IChunk x)]))
+(ann clojure.core/chunk-cons
+ (All [x]
+ [(clojure.lang.IChunk x) (Option (Seqable x)) -> (Option (Seqable x))]))
+(ann clojure.core/chunk-append
+ (All [x]
+ [(clojure.lang.ChunkBuffer x) x -> Any]))
;;END CHUNK HACKS
View
4 src/main/clojure/clojure/core/typed/subtype.clj
@@ -561,10 +561,10 @@
(defn coerse-RClass-primitive
[s t]
(cond
- ; (U Integer Long) <: int
+ ; (U Integer Long) <: (U int long)
(and
(#{(RClass-of Integer) (RClass-of Long)} s)
- (#{(RClass-of 'int)} t))
+ (#{(RClass-of 'int) (RClass-of 'long)} t))
true
:else
View
15 src/test/clojure/clojure/core/typed/test/core.clj
@@ -1231,3 +1231,18 @@
(is (thrown? Exception
(cf (clojure.core.typed/doseq> [[a :- (U clojure.core.typed/AnyInteger nil)] [1 nil 2 3]]
(inc a))))))
+
+(deftest for>-test
+ (is (cf
+ (clojure.core.typed/for> :- Number
+ [[a :- (U nil Number)] [1 nil 2 3]
+ [b :- Number] [1 2 3]
+ :when a]
+ (+ a b))
+ (clojure.lang.LazySeq Number)))
+ (is (thrown? Exception
+ (cf
+ (clojure.core.typed/for> :- Number
+ [[a :- (U clojure.lang.Symbol nil Number)] [1 nil 2 3]
+ [b :- Number] [1 2 3]]
+ (+ a b))))))
Please sign in to comment.
Something went wrong with that request. Please try again.