Fix [_ _] inline method field binding + Var protocol dispatch
Two gaps reitit-core surfaced (now 322/0/1 -> 327/0/0): - A deftype/defrecord inline method with two _ params, (m [_ _] field), read the field as nil: mk-clause bound fields off (get _ :field) where _ was the first param, but the second _ shadowed it. Each _ param is now renamed to a fresh symbol so the instance is unambiguous. - A var did not dispatch to a protocol's clojure.lang.Var extension (reitit extends Expand to Var for a #'handler route): value-host-tags gained a var arm (Var/clojure.lang.Var/IDeref/IFn) and host-type-set gained Var/IDeref so the extension keys under Var. deftype/defrecord is a seed source, re-minted.
This commit is contained in:
parent
9404512b97
commit
6b99591266
5 changed files with 633 additions and 621 deletions
|
|
@ -450,6 +450,9 @@
|
||||||
"Map" "java.util.Map" "Iterable" "java.lang.Iterable" "Object"))
|
"Map" "java.util.Map" "Iterable" "java.lang.Iterable" "Object"))
|
||||||
((pset? obj) '("PersistentHashSet" "APersistentSet" "IPersistentSet" "Set" "java.util.Set" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
((pset? obj) '("PersistentHashSet" "APersistentSet" "IPersistentSet" "Set" "java.util.Set" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||||
((or (cseq? obj) (empty-list-t? obj)) '("ASeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
((or (cseq? obj) (empty-list-t? obj)) '("ASeq" "ISeq" "IPersistentCollection" "Sequential" "Collection" "Iterable" "java.lang.Iterable" "Object"))
|
||||||
|
;; a var is clojure.lang.Var (also IDeref / IFn) — reitit's Expand protocol
|
||||||
|
;; extends to Var so a #'handler route dispatches.
|
||||||
|
((var-cell? obj) '("Var" "clojure.lang.Var" "IDeref" "IFn" "Object"))
|
||||||
;; java.net.URI jhost — extend-protocol java.net.URI (hiccup ToURI/ToStr).
|
;; java.net.URI jhost — extend-protocol java.net.URI (hiccup ToURI/ToStr).
|
||||||
((and (jhost? obj) (string=? (jhost-tag obj) "uri")) '("URI" "java.net.URI" "Object"))
|
((and (jhost? obj) (string=? (jhost-tag obj) "uri")) '("URI" "java.net.URI" "Object"))
|
||||||
;; a ByteBuffer — extend-protocol java.nio.ByteBuffer (aws-api util).
|
;; a ByteBuffer — extend-protocol java.nio.ByteBuffer (aws-api util).
|
||||||
|
|
@ -560,7 +563,7 @@
|
||||||
'("Long" "Integer" "Number" "Double" "Ratio" "BigInt" "BigInteger"
|
'("Long" "Integer" "Number" "Double" "Ratio" "BigInt" "BigInteger"
|
||||||
"String" "CharSequence" "Boolean" "Character"
|
"String" "CharSequence" "Boolean" "Character"
|
||||||
"Keyword" "Symbol" "Named" "Object" "nil"
|
"Keyword" "Symbol" "Named" "Object" "nil"
|
||||||
"Fn" "IFn" "AFn" "URI"
|
"Fn" "IFn" "AFn" "URI" "Var" "IDeref"
|
||||||
"PersistentVector" "APersistentVector" "IPersistentVector"
|
"PersistentVector" "APersistentVector" "IPersistentVector"
|
||||||
"PersistentArrayMap" "APersistentMap" "IPersistentMap"
|
"PersistentArrayMap" "APersistentMap" "IPersistentMap"
|
||||||
"PersistentHashSet" "APersistentSet" "IPersistentSet"
|
"PersistentHashSet" "APersistentSet" "IPersistentSet"
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -377,7 +377,9 @@
|
||||||
;; The clause is DATA, not a syntax-quote: a body that is itself a syntax-
|
;; The clause is DATA, not a syntax-quote: a body that is itself a syntax-
|
||||||
;; quote would have its ~unquotes consumed a level early if re-spliced.
|
;; quote would have its ~unquotes consumed a level early if re-spliced.
|
||||||
mk-clause (fn [spec]
|
mk-clause (fn [spec]
|
||||||
(let [argv (nth spec 1)
|
;; fresh-name each _ param so two _ params don't collide on the
|
||||||
|
;; field binds / live-read instance (see defrecord's mk-clause).
|
||||||
|
(let [argv (mapv (fn [p] (if (= p (quote _)) (gensym "_p") p)) (nth spec 1))
|
||||||
inst (first argv)
|
inst (first argv)
|
||||||
;; let-bind only immutable fields; mutable ones are read live
|
;; let-bind only immutable fields; mutable ones are read live
|
||||||
;; via rewrite-body so a set! within the method is observed.
|
;; via rewrite-body so a set! within the method is observed.
|
||||||
|
|
@ -597,7 +599,11 @@
|
||||||
;; one clause from a spec; `this` is hinted with the record type so the
|
;; one clause from a spec; `this` is hinted with the record type so the
|
||||||
;; inference reads its fields bare-index. Clause as DATA (see deftype).
|
;; inference reads its fields bare-index. Clause as DATA (see deftype).
|
||||||
mk-clause (fn [spec]
|
mk-clause (fn [spec]
|
||||||
(let [argv (nth spec 1)
|
;; rename each _ parameter to a fresh symbol so two _ params
|
||||||
|
;; (the common (m [_ _] …) on a 1-arg protocol method) don't
|
||||||
|
;; collide — the field binds read (get this :field) off the
|
||||||
|
;; FIRST param, which an ignored second _ would otherwise shadow.
|
||||||
|
(let [argv (mapv (fn [p] (if (= p (quote _)) (gensym "_p") p)) (nth spec 1))
|
||||||
inst (first argv)
|
inst (first argv)
|
||||||
hinted (assoc argv 0 (vary-meta inst assoc :tag (name name-sym)))
|
hinted (assoc argv 0 (vary-meta inst assoc :tag (name name-sym)))
|
||||||
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))]
|
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))]
|
||||||
|
|
|
||||||
|
|
@ -570,4 +570,7 @@
|
||||||
{:suite "macro-args" :expr "(do (defmacro sm [x] [(set? x) (map? x)]) (sm #{1 2}))" :expected "[true false]"}
|
{:suite "macro-args" :expr "(do (defmacro sm [x] [(set? x) (map? x)]) (sm #{1 2}))" :expected "[true false]"}
|
||||||
{:suite "macro-args" :expr "(do (defmacro ws [x] (conj x :z)) (= #{1 :z} (ws #{1})))" :expected "true"}
|
{:suite "macro-args" :expr "(do (defmacro ws [x] (conj x :z)) (= #{1 :z} (ws #{1})))" :expected "true"}
|
||||||
{:suite "macro-args" :expr "(do (defmacro vm [x] (vector? x)) (vm [1 2]))" :expected "true"}
|
{:suite "macro-args" :expr "(do (defmacro vm [x] (vector? x)) (vm [1 2]))" :expected "true"}
|
||||||
|
{:suite "deftype-method" :expr "(do (defprotocol P (m [_ o])) (defrecord R [n] P (m [_ _] n)) (m (->R 5) :x))" :expected "5"}
|
||||||
|
{:suite "deftype-method" :expr "(do (defprotocol P2 (m2 [_ o])) (deftype T [n] P2 (m2 [_ _] n)) (m2 (->T 7) :x))" :expected "7"}
|
||||||
|
{:suite "protocol-host" :expr "(do (defprotocol Q (e [_])) (extend-protocol Q clojure.lang.Var (e [_] :var)) [(satisfies? Q (var map)) (e (var map))])" :expected "[true :var]"}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue