From 236dca28d95a70d25b53bb7f085687f62b9cdb16 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sun, 14 Jun 2026 23:00:48 -0400 Subject: [PATCH] satisfies? recognizes reify, consistent with instance? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A reify's protocol methods are instance-local, so they aren't in the global type registry that type-satisfies? consults — satisfies? returned false for a reify even when it implemented the protocol. Check the protocols the reify records on itself (the same :jolt/protocols list instance? uses), matching short names like instance? does. Covers single- and multi-protocol reify. --- src/jolt/evaluator.janet | 18 +++++++++++++----- test/spec/protocols-spec.janet | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/jolt/evaluator.janet b/src/jolt/evaluator.janet index 524e472..3cebf84 100644 --- a/src/jolt/evaluator.janet +++ b/src/jolt/evaluator.janet @@ -1725,16 +1725,24 @@ (let [tbl (get mm-var :jolt/methods)] (when tbl (each k (keys tbl) (set m (phm-assoc m k (get tbl k)))))) m))) - # satisfies?: evaluated protocol value + instance (matches the prior arm). + # satisfies?: evaluated protocol value + instance. Recognizes a reify the same + # way instance? does — by the protocols it records on itself (a reify's methods + # are instance-local, so they aren't in the global type registry that + # type-satisfies? consults). (ns-intern core "satisfies?" (fn [proto obj] + (def pn (proto :name)) + (def pn-str (if (struct? pn) (pn :name) pn)) + (def protos (if (table? obj) (get obj :jolt/protocols))) (def type-tag (or (record-tag obj) (if (and (table? obj) (get obj :jolt/protocol-methods)) (get obj :jolt/deftype)))) - (if type-tag - (let [pn (proto :name) - pn-str (if (struct? pn) (pn :name) pn)] - (type-satisfies? ctx type-tag pn-str)) + (cond + (and protos (string? pn-str) + (truthy? (some (fn [p] (= (last (string/split "." p)) + (last (string/split "." pn-str)))) + protos))) true + type-tag (type-satisfies? ctx type-tag pn-str) false))) # instance?: the overlay macro passes the TYPE NAME quoted (class names don't # evaluate to values on jolt); the value arg arrives evaluated. diff --git a/test/spec/protocols-spec.janet b/test/spec/protocols-spec.janet index b6606cf..b14a723 100644 --- a/test/spec/protocols-spec.janet +++ b/test/spec/protocols-spec.janet @@ -42,6 +42,12 @@ "(do (defprotocol P (m [_])) (defrecord R [] P (m [_] 1)) (satisfies? P (->R)))"] ["satisfies? false" "false" "(do (defprotocol P (m [_])) (defrecord R []) (satisfies? P (->R)))"] + ["satisfies? reify" "true" + "(do (defprotocol P (m [_])) (satisfies? P (reify P (m [_] 1))))"] + ["satisfies? reify multi-protocol" "[true true]" + "(do (defprotocol P (m [_])) (defprotocol Q (n [_])) (let [r (reify P (m [_] 1) Q (n [_] 2))] [(satisfies? P r) (satisfies? Q r)]))"] + ["satisfies? reify other proto" "false" + "(do (defprotocol P (m [_])) (defprotocol Q (n [_])) (satisfies? Q (reify P (m [_] 1))))"] ["instance? record" "true" "(do (defrecord R [a]) (instance? R (->R 1)))"] ["dot constructor" "5"