diff --git a/src/main/clojure/cljs/core.cljc b/src/main/clojure/cljs/core.cljc index 61b705f93..a055f5adf 100644 --- a/src/main/clojure/cljs/core.cljc +++ b/src/main/clojure/cljs/core.cljc @@ -2072,14 +2072,6 @@ (missing-protocol ~(core/str psym "." fname) ~fsig)))) - ;; then check protocol fn in metadata (only when protocol is marked with :extend-via-metadata true) - check - (core/if-not (:extend-via-metadata opts) - check - `(if-let [meta-impl# (-> ~fsig (core/meta) (core/get '~fqn-fname))] - (meta-impl# ~@sig) - ~check)) - ;; then check protocol on js string,function,array,object (first dynamic check actually executed) check `(let [x# (if (nil? ~fsig) nil ~fsig) @@ -2088,9 +2080,10 @@ (m# ~@sig) ~check))] `(~sig ~check))) - expand-sig (core/fn [dyn-name slot sig] + expand-sig (core/fn [fname dyn-name slot sig] (core/let [sig (sig->syms sig) + fqn-fname (with-meta (fqn fname) {:cljs.analyzer/no-resolve true}) fsig (first sig) ;; check protocol property on object (first check executed) @@ -2099,7 +2092,15 @@ ;; Property access needed here. (not (nil? (. ~fsig ~(with-meta (symbol (core/str "-" slot)) {:protocol-prop true}))))) (. ~fsig ~slot ~@sig) - (~dyn-name ~@sig))] + (~dyn-name ~@sig)) + + ;; then check protocol fn in metadata (only when protocol is marked with :extend-via-metadata true) + check + (core/if-not (:extend-via-metadata opts) + check + `(if-let [meta-impl# (-> ~fsig (core/meta) (core/get '~fqn-fname))] + (meta-impl# ~@sig) + ~check))] `(~sig ~check))) psym (core/-> psym (vary-meta update-in [:jsdoc] conj "@interface") @@ -2147,7 +2148,7 @@ sigs))] (defn ~fname ~@(map (core/fn [sig] - (expand-sig dyn-name + (expand-sig fname dyn-name (with-meta (symbol (core/str slot "$arity$" (count sig))) {:protocol-prop true}) sig)) diff --git a/src/test/cljs/cljs/core_test.cljs b/src/test/cljs/cljs/core_test.cljs index 8c3ad289c..82e075744 100644 --- a/src/test/cljs/cljs/core_test.cljs +++ b/src/test/cljs/cljs/core_test.cljs @@ -1770,13 +1770,21 @@ (deftest test-cljs-2960 ;; protocol impl via metadata (is (= 1 (ext-meta-protocol (with-meta {} {`ext-meta-protocol (fn [_] 1)})))) - ;; actual impl before metadata - (is (= 2 (ext-meta-protocol (with-meta (SomeMetaImpl. 2) {`ext-meta-protocol (fn [_] 1)})))) + ;; metadata before actual impl + (is (= 1 (ext-meta-protocol (with-meta (SomeMetaImpl. 2) {`ext-meta-protocol (fn [_] 1)})))) ;; protocol not marked as :extend-via-metadata so fallthrough to no impl (is (thrown? js/Error (non-meta-protocol (with-meta {} {`non-meta-protocol (fn [_] 1)})))) ;; normal impl call just in case (is (= 2 (non-meta-protocol (with-meta (SomeMetaImpl. 2) {`non-meta-protocol (fn [_] 1)}))))) +(extend-type PersistentArrayMap + ExtMetaProtocol + (ext-meta-protocol [m] 2)) + +(deftest test-cljs-3313 + (testing "metadata protocol fn takes precedence over direct implementation" + (= 1 (ext-meta-protocol (with-meta (array-map) {`ext-meta-protocol (fn [_] 1)}))))) + (deftest test-cljs-3054 (testing "`into` behaves the same as Clojure" (is (nil? (into nil #{})))