deftype/record: clojure.lang collection interfaces + protocol identity
Running clojure.core.match (a macro-heavy library that builds its compiler out of deftypes implementing clojure.lang interfaces) shook out a cluster of general gaps. Its own suite goes from not-loading to 111/115 assertions. - deftype/defrecord implementing a clojure.lang collection interface now drives the core fns: Indexed -> nth, Counted -> count, Associative -> assoc, ILookup -> get/valAt (non-field keys only, so a method's own field bindings don't recurse), ISeq -> seq/first/rest, IPersistentCollection -> conj, IFn -> the value is callable. A jrec is still a map of fields by default; the interface method wins when declared. - Multi-arity inline methods are grouped into one fn (a type with (nth [_ i]) and (nth [_ i x]) kept only the last before). Built as data, not a nested syntax-quote, so a `(= ~ocr ~l) method body keeps its unquotes. - instance?/satisfies? recognize a protocol a type implements, including a MARKER protocol with no methods (core.match's IPseudoPattern) — deftype/defrecord now record protocol satisfaction even with zero methods. Added ILookup/Indexed/ Counted to the instance? taxonomy for the built-in collections. - Syntax-quote: a fully-qualified class name (clojure.lang.ILookup) stays bare instead of being namespace-qualified; (unquote x) is detected in a lazy seq (a macro that builds its template with map, e.g. deftype's rewrite-set). - clojure.set union/intersection/difference are variadic (& sets) + union 0-arity. - java map view methods: keySet/values/entrySet/size/isEmpty. - deprecated java.util.Date getters (getYear/getMonth/...) + the multi-arg (Date. year-1900 month0 date hrs min) constructor. Seed change (deftype/defrecord macros + clojure.set) -> re-minted; the rest are runtime. 11 JVM-certified corpus rows; make test + shakesmoke green.
This commit is contained in:
parent
3cbfa8719c
commit
f5455115a0
12 changed files with 1044 additions and 907 deletions
|
|
@ -323,16 +323,31 @@
|
|||
;; inline impls register for dispatch but are NOT extenders of the
|
||||
;; protocol (the JVM compiles them into the class) — register-inline-method,
|
||||
;; not extend-type.
|
||||
;; Several bodies for one method name are distinct arities (a type that
|
||||
;; implements clojure.lang.Indexed has (nth [_ i]) AND (nth [_ i x])):
|
||||
;; group them into one multi-arity fn so dispatch picks the clause by arg
|
||||
;; count, instead of the last clause clobbering the rest.
|
||||
impl (fn [proto specs]
|
||||
`(do
|
||||
~@(map (fn [spec]
|
||||
(let [argv (nth spec 1)
|
||||
inst (first argv)
|
||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))
|
||||
mbody (map (fn [bf] (rewrite-set inst bf)) (drop 2 spec))]
|
||||
`(register-inline-method ~(name tname) ~(name proto) ~(name (first spec))
|
||||
(fn ~argv (let [~@binds] ~@mbody)))))
|
||||
specs)))]
|
||||
(loop [ss (seq specs) methods {} order []]
|
||||
(if (empty? ss)
|
||||
`(do (register-inline-protocol! ~(name tname) ~(name proto))
|
||||
~@(map (fn [mname]
|
||||
`(register-inline-method ~(name tname) ~(name proto) ~mname
|
||||
(fn ~@(get methods mname))))
|
||||
order))
|
||||
(let [spec (first ss)
|
||||
mname (name (first spec))
|
||||
argv (nth spec 1)
|
||||
inst (first argv)
|
||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))
|
||||
mbody (map (fn [bf] (rewrite-set inst bf)) (drop 2 spec))
|
||||
;; build the clause as DATA, not via a syntax-quote: a body
|
||||
;; that is itself a syntax-quote (`(= ~ocr ~l)) would have its
|
||||
;; ~unquotes consumed a level early if re-spliced through one.
|
||||
clause (list argv (list* 'let binds mbody))]
|
||||
(recur (rest ss)
|
||||
(assoc methods mname (conj (get methods mname []) clause))
|
||||
(if (contains? methods mname) order (conj order mname)))))))]
|
||||
`(do
|
||||
(def ~tname (make-deftype-ctor (quote ~tname) [~@field-kws] [~@field-tags] [~@field-muts]))
|
||||
(def ~arrow ~tname)
|
||||
|
|
@ -476,19 +491,29 @@
|
|||
;; inline impls register for dispatch but are NOT extenders of the
|
||||
;; protocol (the JVM compiles them into the class) — register-inline-method,
|
||||
;; not extend-type.
|
||||
;; group multi-arity method bodies into one fn (see deftype's impl).
|
||||
impl (fn [proto specs]
|
||||
`(do
|
||||
~@(map (fn [spec]
|
||||
(let [argv (nth spec 1)
|
||||
inst (first argv)
|
||||
;; hint `this` with the record type so the inference
|
||||
;; types it and its field reads bare-index
|
||||
;; instead of going through the runtime tag guard.
|
||||
hinted (assoc argv 0 (vary-meta inst assoc :tag (name name-sym)))
|
||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))]
|
||||
`(register-inline-method ~(name name-sym) ~(name proto) ~(name (first spec))
|
||||
(fn ~hinted (let [~@binds] ~@(drop 2 spec))))))
|
||||
specs)))]
|
||||
(loop [ss (seq specs) methods {} order []]
|
||||
(if (empty? ss)
|
||||
`(do (register-inline-protocol! ~(name name-sym) ~(name proto))
|
||||
~@(map (fn [mname]
|
||||
`(register-inline-method ~(name name-sym) ~(name proto) ~mname
|
||||
(fn ~@(get methods mname))))
|
||||
order))
|
||||
(let [spec (first ss)
|
||||
mname (name (first spec))
|
||||
argv (nth spec 1)
|
||||
inst (first argv)
|
||||
;; hint `this` with the record type so the inference types it
|
||||
;; and its field reads bare-index instead of the runtime guard.
|
||||
hinted (assoc argv 0 (vary-meta inst assoc :tag (name name-sym)))
|
||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))
|
||||
;; clause as DATA (see deftype): a syntax-quote body must not
|
||||
;; be re-spliced through another syntax-quote.
|
||||
clause (list hinted (list* 'let binds (drop 2 spec)))]
|
||||
(recur (rest ss)
|
||||
(assoc methods mname (conj (get methods mname []) clause))
|
||||
(if (contains? methods mname) order (conj order mname)))))))]
|
||||
`(do
|
||||
;; deftype already defines ->name (= the ctor); no (name. …) interop needed,
|
||||
;; so defrecord compiles too. map->name builds via that ctor.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue