Skip to content

Commit 1a155ad

Browse files
mfikesswannodette
authored andcommitted
CLJS-2883: Instrumentation fails compilation with a large number of spec'd functions
When instrumenting, unstrumenting, or checking, we normally evaluate the suppied form in order to convert it to an (unquoted) symbol or collection of symbols. In the case that this is all speced vars or all checkable syms, this quoted list can be large enough to cause eval to fail. Fortunately, in this special case there is no need to actually apply eval because we know the list of symbols is the second item in the form.
1 parent 9e1ff22 commit 1a155ad

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

src/main/cljs/cljs/spec/test/alpha.cljc

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ returns the set of all symbols naming vars in those nses."
8383
[sym])))
8484
(collectionize sym-or-syms)))
8585

86+
(defn- form->sym-or-syms
87+
"Helper for extracting a symbol or symbols from a (potentially
88+
user-supplied) quoted form. In the case that the form has ::no-eval meta, we
89+
know it was generated by us and we directly extract the result, assuming the
90+
shape of the form. This avoids applying eval to extremely large forms in the
91+
latter case."
92+
[sym-or-syms]
93+
(if (::no-eval (meta sym-or-syms))
94+
(second sym-or-syms)
95+
(eval sym-or-syms)))
96+
8697
(defmacro instrument
8798
"Instruments the vars named by sym-or-syms, a symbol or collection
8899
of symbols, or all instrumentable vars if sym-or-syms is not
@@ -122,12 +133,12 @@ invokes the fn you provide, enabling arbitrary stubbing and mocking.
122133
123134
Returns a collection of syms naming the vars instrumented."
124135
([]
125-
`(instrument '[~@(#?(:clj s/speced-vars
126-
:cljs cljs.spec.alpha$macros/speced-vars))]))
136+
`(instrument ^::no-eval '[~@(#?(:clj s/speced-vars
137+
:cljs cljs.spec.alpha$macros/speced-vars))]))
127138
([xs]
128139
`(instrument ~xs nil))
129140
([sym-or-syms opts]
130-
(let [syms (sym-or-syms->syms (eval sym-or-syms))
141+
(let [syms (sym-or-syms->syms (form->sym-or-syms sym-or-syms))
131142
opts-sym (gensym "opts")]
132143
`(let [~opts-sym ~opts]
133144
(reduce
@@ -148,9 +159,9 @@ Returns a collection of syms naming the vars instrumented."
148159
as in instrument. With no args, unstruments all instrumented vars.
149160
Returns a collection of syms naming the vars unstrumented."
150161
([]
151-
`(unstrument '[~@(deref instrumented-vars)]))
162+
`(unstrument ^::no-eval '[~@(deref instrumented-vars)]))
152163
([sym-or-syms]
153-
(let [syms (sym-or-syms->syms (eval sym-or-syms))]
164+
(let [syms (sym-or-syms->syms (form->sym-or-syms sym-or-syms))]
154165
`(reduce
155166
(fn [ret# f#]
156167
(let [sym# (f#)]
@@ -256,11 +267,11 @@ spec itself will have an ::s/failure value in ex-data:
256267
:instrument invalid args detected by instrument
257268
"
258269
([]
259-
`(check '~(checkable-syms*)))
270+
`(check ^::no-eval '~(checkable-syms*)))
260271
([sym-or-syms]
261272
`(check ~sym-or-syms nil))
262273
([sym-or-syms opts]
263-
(let [syms (sym-or-syms->syms (eval sym-or-syms))
274+
(let [syms (sym-or-syms->syms (form->sym-or-syms sym-or-syms))
264275
opts-sym (gensym "opts")]
265276
`(let [~opts-sym ~opts]
266277
[~@(->> syms

0 commit comments

Comments
 (0)