Skip to content

Commit 548e331

Browse files
committed
feat: validate-call prefer param-tags
1 parent 9b5afc2 commit 548e331

1 file changed

Lines changed: 40 additions & 33 deletions

File tree

  • src/main/clojure/clojure/tools/analyzer/passes/jvm

src/main/clojure/clojure/tools/analyzer/passes/jvm/validate.clj

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -111,44 +111,51 @@
111111
:args (mapv (fn [a] (prewalk a cleanup)) args)}
112112
(source-info (:env ast)))))))))))
113113

114-
(defn validate-call [{:keys [class instance method args tag env op] :as ast}]
114+
(defn- found-method [ast args tag instance? instance m]
115+
(let [ret-tag (:return-type m)
116+
arg-tags (mapv u/maybe-class (:parameter-types m))
117+
args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags)
118+
class (u/maybe-class (:declaring-class m))]
119+
(merge' ast
120+
{:method (:name m)
121+
:validated? true
122+
:class class
123+
:o-tag ret-tag
124+
:tag (or tag ret-tag)
125+
:args args}
126+
(if instance?
127+
{:instance (assoc instance :tag class)}))))
128+
129+
(defn validate-call [{:keys [class instance method args tag env op param-tags] :as ast}]
115130
(let [argc (count args)
116131
instance? (= :instance-call op)
117132
f (if instance? u/instance-methods u/static-methods)
118133
tags (mapv :tag args)]
119134
(if-let [matching-methods (seq (f class method argc))]
120-
(let [[m & rest :as matching] (try-best-match tags matching-methods)]
121-
(if m
122-
(let [all-ret-equals? (apply = (mapv :return-type matching))]
123-
(if (or (empty? rest)
124-
(and all-ret-equals? ;; if the method signature is the same just pick the first one
125-
(apply = (mapv #(mapv u/maybe-class (:parameter-types %)) matching))))
126-
(let [ret-tag (:return-type m)
127-
arg-tags (mapv u/maybe-class (:parameter-types m))
128-
args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags)
129-
class (u/maybe-class (:declaring-class m))]
130-
(merge' ast
131-
{:method (:name m)
132-
:validated? true
133-
:class class
134-
:o-tag ret-tag
135-
:tag (or tag ret-tag)
136-
:args args}
137-
(if instance?
138-
{:instance (assoc instance :tag class)})))
139-
(if all-ret-equals?
140-
(let [ret-tag (:return-type m)]
141-
(assoc ast
142-
:o-tag Object
143-
:tag (or tag ret-tag)))
144-
ast)))
145-
(if instance?
146-
(assoc (dissoc ast :class) :tag Object :o-tag Object)
147-
(throw (ex-info (str "No matching method: " method " for class: " class " and given signature")
148-
(merge {:method method
149-
:class class
150-
:args (mapv (fn [a] (prewalk a cleanup)) args)}
151-
(source-info env)))))))
135+
;; try resolving via param-tags first
136+
(if-let [hinted-method (and param-tags
137+
(resolve-hinted-method matching-methods param-tags))]
138+
(found-method ast args tag instance? instance hinted-method)
139+
(let [[m & rest :as matching] (try-best-match tags matching-methods)]
140+
(if m
141+
(let [all-ret-equals? (apply = (mapv :return-type matching))]
142+
(if (or (empty? rest)
143+
(and all-ret-equals? ;; if the method signature is the same just pick the first one
144+
(apply = (mapv #(mapv u/maybe-class (:parameter-types %)) matching))))
145+
(found-method ast args tag instance? instance m)
146+
(if all-ret-equals?
147+
(let [ret-tag (:return-type m)]
148+
(assoc ast
149+
:o-tag Object
150+
:tag (or tag ret-tag)))
151+
ast)))
152+
(if instance?
153+
(assoc (dissoc ast :class) :tag Object :o-tag Object)
154+
(throw (ex-info (str "No matching method: " method " for class: " class " and given signature")
155+
(merge {:method method
156+
:class class
157+
:args (mapv (fn [a] (prewalk a cleanup)) args)}
158+
(source-info env))))))))
152159
(if instance?
153160
(assoc (dissoc ast :class) :tag Object :o-tag Object)
154161
(throw (ex-info (str "No matching method: " method " for class: " class " and arity: " argc)

0 commit comments

Comments
 (0)