|
111 | 111 | :args (mapv (fn [a] (prewalk a cleanup)) args)} |
112 | 112 | (source-info (:env ast))))))))))) |
113 | 113 |
|
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}] |
115 | 130 | (let [argc (count args) |
116 | 131 | instance? (= :instance-call op) |
117 | 132 | f (if instance? u/instance-methods u/static-methods) |
118 | 133 | tags (mapv :tag args)] |
119 | 134 | (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)))))))) |
152 | 159 | (if instance? |
153 | 160 | (assoc (dissoc ast :class) :tag Object :o-tag Object) |
154 | 161 | (throw (ex-info (str "No matching method: " method " for class: " class " and arity: " argc) |
|
0 commit comments