|
53 | 53 | :form form} |
54 | 54 | (source-info env)))))))) |
55 | 55 |
|
| 56 | +(defn- resolve-method-by-param-tags [methods param-tags ^Class class desc env] |
| 57 | + (or (resolve-hinted-method methods param-tags) |
| 58 | + (throw (ex-info (str "param-tags " (pr-str param-tags) |
| 59 | + " insufficient to resolve " desc |
| 60 | + " in class " (.getName class)) |
| 61 | + (merge {:class class :param-tags param-tags} |
| 62 | + (source-info env)))))) |
| 63 | + |
| 64 | +(defn- tag-args-from-method [ast m] |
| 65 | + (let [arg-tags (mapv u/maybe-class (:parameter-types m))] |
| 66 | + (assoc ast |
| 67 | + :args (mapv (fn [arg tag] (assoc arg :tag tag)) (:args ast) arg-tags) |
| 68 | + :validated? true))) |
| 69 | + |
| 70 | +(defn- found-method [ast tag instance? m] |
| 71 | + (let [ret-tag (:return-type m) |
| 72 | + class (u/maybe-class (:declaring-class m))] |
| 73 | + (merge' (-> ast (tag-args-from-method m)) |
| 74 | + {:method (:name m) |
| 75 | + :class class |
| 76 | + :o-tag ret-tag |
| 77 | + :tag (or tag ret-tag)} |
| 78 | + (when instance? |
| 79 | + {:instance (assoc (:instance ast) :tag class)})))) |
| 80 | + |
56 | 81 | (defmethod -validate :method-value |
57 | 82 | [{:keys [class method kind param-tags methods env] :as ast}] |
58 | 83 | (let [class (u/maybe-class class)] |
59 | 84 | (if param-tags |
60 | | - (if-let [m (resolve-hinted-method methods param-tags)] |
| 85 | + (let [m (resolve-method-by-param-tags methods param-tags class |
| 86 | + (str (name kind) " method " method) env)] |
61 | 87 | (assoc ast |
62 | 88 | :class class |
63 | 89 | :methods [m] |
64 | | - :validated? true) |
65 | | - (throw (ex-info (str "param-tags " (pr-str param-tags) |
66 | | - " insufficient to resolve " (name kind) " method " |
67 | | - method " in class " (.getName ^Class class)) |
68 | | - (merge {:class class |
69 | | - :method method |
70 | | - :param-tags param-tags} |
71 | | - (source-info env))))) |
| 90 | + :validated? true)) |
72 | 91 | (assoc ast |
73 | 92 | :class class |
74 | 93 | :validated? true)))) |
|
83 | 102 | ast) |
84 | 103 |
|
85 | 104 | (defmethod -validate :new |
86 | | - [{:keys [args] :as ast}] |
| 105 | + [{:keys [args param-tags methods] :as ast}] |
87 | 106 | (if (:validated? ast) |
88 | 107 | ast |
89 | 108 | (if-not (= :class (-> ast :class :type)) |
90 | 109 | (throw (ex-info (str "Unable to resolve classname: " (:form (:class ast))) |
91 | 110 | (merge {:class (:form (:class ast)) |
92 | 111 | :ast ast} |
93 | 112 | (source-info (:env ast))))) |
94 | | - (let [^Class class (-> ast :class :val) |
95 | | - c-name (symbol (.getName class)) |
96 | | - argc (count args) |
97 | | - tags (mapv :tag args)] |
98 | | - (let [[ctor & rest] (->> (filter #(= (count (:parameter-types %)) argc) |
99 | | - (u/members class c-name)) |
100 | | - (try-best-match tags))] |
101 | | - (if ctor |
102 | | - (if (empty? rest) |
103 | | - (let [arg-tags (mapv u/maybe-class (:parameter-types ctor)) |
104 | | - args (mapv (fn [arg tag] (assoc arg :tag tag)) args arg-tags)] |
105 | | - (assoc ast |
106 | | - :args args |
107 | | - :validated? true)) |
108 | | - ast) |
109 | | - (throw (ex-info (str "no ctor found for ctor of class: " class " and given signature") |
110 | | - (merge {:class class |
111 | | - :args (mapv (fn [a] (prewalk a cleanup)) args)} |
112 | | - (source-info (:env ast))))))))))) |
113 | | - |
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)})))) |
| 113 | + (let [^Class class (-> ast :class :val)] |
| 114 | + (if param-tags |
| 115 | + (-> ast (tag-args-from-method (resolve-method-by-param-tags methods param-tags class "constructor" (:env ast)))) |
| 116 | + (let [c-name (symbol (.getName class)) |
| 117 | + argc (count args) |
| 118 | + tags (mapv :tag args) |
| 119 | + [ctor & rest] (->> (filter #(= (count (:parameter-types %)) argc) |
| 120 | + (u/members class c-name)) |
| 121 | + (try-best-match tags))] |
| 122 | + (if ctor |
| 123 | + (if (empty? rest) |
| 124 | + (-> ast (tag-args-from-method ctor)) |
| 125 | + ast) |
| 126 | + (throw (ex-info (str "no ctor found for ctor of class: " class " and given signature") |
| 127 | + (merge {:class class |
| 128 | + :args (mapv (fn [a] (prewalk a cleanup)) args)} |
| 129 | + (source-info (:env ast)))))))))))) |
128 | 130 |
|
129 | | -(defn validate-call [{:keys [class instance method args tag env op param-tags] :as ast}] |
| 131 | +(defn validate-call [{:keys [class instance method args tag env op param-tags methods] :as ast}] |
130 | 132 | (let [argc (count args) |
131 | 133 | instance? (= :instance-call op) |
132 | | - f (if instance? u/instance-methods u/static-methods) |
133 | 134 | tags (mapv :tag args)] |
134 | | - (if-let [matching-methods (seq (f class method argc))] |
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) |
| 135 | + (if param-tags |
| 136 | + (-> ast |
| 137 | + (found-method tag instance? |
| 138 | + (resolve-method-by-param-tags methods param-tags class |
| 139 | + (str (if instance? "instance" "static") " method " method) |
| 140 | + env))) |
| 141 | + (if-let [matching-methods (seq ((if instance? u/instance-methods u/static-methods) |
| 142 | + class method argc))] |
139 | 143 | (let [[m & rest :as matching] (try-best-match tags matching-methods)] |
140 | 144 | (if m |
141 | 145 | (let [all-ret-equals? (apply = (mapv :return-type matching))] |
142 | 146 | (if (or (empty? rest) |
143 | 147 | (and all-ret-equals? ;; if the method signature is the same just pick the first one |
144 | 148 | (apply = (mapv #(mapv u/maybe-class (:parameter-types %)) matching)))) |
145 | | - (found-method ast args tag instance? instance m) |
| 149 | + (-> ast (found-method tag instance? m)) |
146 | 150 | (if all-ret-equals? |
147 | 151 | (let [ret-tag (:return-type m)] |
148 | 152 | (assoc ast |
|
155 | 159 | (merge {:method method |
156 | 160 | :class class |
157 | 161 | :args (mapv (fn [a] (prewalk a cleanup)) args)} |
158 | | - (source-info env)))))))) |
159 | | - (if instance? |
160 | | - (assoc (dissoc ast :class) :tag Object :o-tag Object) |
161 | | - (throw (ex-info (str "No matching method: " method " for class: " class " and arity: " argc) |
162 | | - (merge {:method method |
163 | | - :class class |
164 | | - :argc argc} |
165 | | - (source-info env)))))))) |
| 162 | + (source-info env))))))) |
| 163 | + (if instance? |
| 164 | + (assoc (dissoc ast :class) :tag Object :o-tag Object) |
| 165 | + (throw (ex-info (str "No matching method: " method " for class: " class " and arity: " argc) |
| 166 | + (merge {:method method |
| 167 | + :class class |
| 168 | + :argc argc} |
| 169 | + (source-info env))))))))) |
166 | 170 |
|
167 | 171 | (defmethod -validate :static-call |
168 | 172 | [ast] |
|
0 commit comments