Skip to content

Commit f312d5d

Browse files
committed
CLJS-2950: Direct field access for keyword lookup on records
1 parent 3768e77 commit f312d5d

File tree

3 files changed

+34
-3
lines changed

3 files changed

+34
-3
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3558,6 +3558,23 @@
35583558
[argc method-params]
35593559
(boolean (some #{argc} (map count method-params))))
35603560

3561+
(defn- record-tag?
3562+
[tag]
3563+
(boolean (and (symbol? tag)
3564+
(some? (namespace tag))
3565+
(get-in @env/*compiler* [::namespaces (symbol (namespace tag)) :defs (symbol (name tag)) :record]))))
3566+
3567+
(defn- record-basis
3568+
[tag]
3569+
(let [positional-factory (symbol (str "->" (name tag)))
3570+
fields (first (get-in @env/*compiler* [::namespaces (symbol (namespace tag)) :defs positional-factory :method-params]))]
3571+
(into #{} fields)))
3572+
3573+
(defn- record-with-field?
3574+
[tag field]
3575+
(and (record-tag? tag)
3576+
(contains? (record-basis tag) field)))
3577+
35613578
(defn parse-invoke*
35623579
[env [f & args :as form]]
35633580
(let [enve (assoc env :context :expr)
@@ -3611,8 +3628,14 @@
36113628
~@(if bind-args? arg-syms args)))))
36123629
(let [ana-expr #(analyze enve %)
36133630
argexprs (mapv ana-expr args)]
3614-
{:env env :op :invoke :form form :fn fexpr :args argexprs
3615-
:children [:fn :args]}))))
3631+
(if (and (and (keyword? f)
3632+
(nil? (namespace f)))
3633+
(== 1 (count args))
3634+
(record-with-field? (:tag (first argexprs)) (symbol (name f))))
3635+
(let [field-access-form (list* (symbol (str ".-" (name f))) args)]
3636+
(analyze env field-access-form))
3637+
{:env env :op :invoke :form form :fn fexpr :args argexprs
3638+
:children [:fn :args]})))))
36163639

36173640
(defn parse-invoke
36183641
[env form]

src/test/cljs/cljs/invoke_test.cljs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@
3434
(declare ^{:arglists '([a b])} declared-fn)
3535

3636
(declared-fn 1 2)
37+
38+
(defrecord Foo [foo-field-a foo-field-b])
39+
40+
(def foo-record (->Foo 1 2))
41+
42+
(:foo-field-a foo-record)

src/test/clojure/cljs/compiler_tests.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@
281281
(is (re-find #"(?m)^.*var .*=.*inv_arg1.cljs.core.IFn._invoke.arity.0 \?.*$"
282282
content))
283283
;; CLJS-1871: A declare hinted with :arglists meta should result in static dispatch
284-
(is (str/includes? content "cljs.invoke_test.declared_fn(")))))
284+
(is (str/includes? content "cljs.invoke_test.declared_fn("))
285+
;; CLJS-2950: Direct field access for keyword lookup on records
286+
(is (str/includes? content "cljs.invoke_test.foo_record.foo_field_a;")))))
285287
#_(test-vars [#'test-optimized-invoke-emit])
286288

287289
;; CLJS-1225

0 commit comments

Comments
 (0)