-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix nested inline fn expansion #34
base: master
Are you sure you want to change the base?
Conversation
((nil . ((indent-tabs-mode . nil) | ||
(require-final-newline . t))) | ||
(clojure-mode . ((cljr-favor-prefix-notation . nil)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a bit of editor config settings for people who use Emacs
005d071
to
93c2875
Compare
project.clj
Outdated
:profiles {:provided {:dependencies [[org.clojure/clojure "1.8.0"]]}} | ||
:profiles {:dev {:dependencies [[org.clojure/clojure "1.10.1"] | ||
[pjstadig/humane-test-output "0.10.0"]] | ||
:injections [(require 'pjstadig.humane-test-output) | ||
(pjstadig.humane-test-output/activate!)]}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the :provided
profile to a :dev
one and added humane-test-output
to make test failures easier to read
93c2875
to
1b81669
Compare
:dev {:dependencies [[org.clojure/clojure "1.10.1"] | ||
[pjstadig/humane-test-output "0.10.0"]] | ||
:injections [(require 'pjstadig.humane-test-output) | ||
(pjstadig.humane-test-output/activate!)]}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a :dev
profile that uses Clojure 1.10.1 by default and adds humane-test-output
to make the tests easier to read
:javac-options ["-target" "1.6" "-source" "1.6"]) | ||
:javac-options ["-target" "1.7" "-source" "1.7"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using Java 14 locally and it doesn't support compiling to Java 1.6 bytecode. I think dropping 1.6 support makes sense -- Clojure 1.10+ requires Java 8+ and Clojure 1.5+ requires Java 7 for all features to work out-of-the-box
'def def-handler | ||
'fn* fn-handler | ||
'let* let-handler | ||
'loop* let-handler | ||
'letfn* letfn-handler | ||
'case* case-handler | ||
'try try-handler | ||
'catch catch-handler | ||
'reify* reify-handler | ||
'deftype* deftype-handler | ||
'. dot-handler | ||
#(doall (map %1 %2))) | ||
walk-exprs' (special-meta x))) | ||
|
||
(instance? java.util.Map$Entry x) | ||
(clojure.lang.MapEntry. | ||
(walk-exprs' (key x)) | ||
(walk-exprs' (val x))) | ||
|
||
(or | ||
(set? x) | ||
(vector? x)) | ||
(into (empty x) (map walk-exprs' x)) | ||
|
||
(instance? clojure.lang.IRecord x) | ||
x | ||
|
||
(map? x) | ||
(into (empty x) (map walk-exprs' x)) | ||
|
||
;; special case to handle clojure.test | ||
(and (symbol? x) (-> x meta :test)) | ||
(vary-meta x update-in [:test] walk-exprs') | ||
|
||
:else | ||
x)] | ||
(if (instance? clojure.lang.IObj x') | ||
(with-meta x' (merge (meta x) (meta x'))) | ||
x'))))) | ||
(cmp/with-base-env | ||
(let [x (try | ||
(macroexpand x special-form?) | ||
(catch ClassNotFoundException _ | ||
x)) | ||
walk-exprs' (partial walk-exprs predicate handler special-form?) | ||
x' (cond | ||
|
||
(and (head= x 'var) (predicate x)) | ||
(handler (eval x)) | ||
|
||
(and (head= x 'quote) (not (predicate x))) | ||
x | ||
|
||
(predicate x) | ||
(handler x) | ||
|
||
(seq? x) | ||
(if (or (and (not try-clause?) | ||
(#{'catch 'finally} (first x))) | ||
(not (contains? special-forms (first x)))) | ||
(doall (map walk-exprs' x)) | ||
((condp = (first x) | ||
'do do-handler | ||
'def def-handler | ||
'fn* fn-handler | ||
'let* let-handler | ||
'loop* let-handler | ||
'letfn* letfn-handler | ||
'case* case-handler | ||
'try try-handler | ||
'catch catch-handler | ||
'reify* reify-handler | ||
'deftype* deftype-handler | ||
'. dot-handler | ||
#(doall (map %1 %2))) | ||
walk-exprs' (special-meta x))) | ||
|
||
(instance? java.util.Map$Entry x) | ||
(clojure.lang.MapEntry. | ||
(walk-exprs' (key x)) | ||
(walk-exprs' (val x))) | ||
|
||
(or | ||
(set? x) | ||
(vector? x)) | ||
(into (empty x) (map walk-exprs' x)) | ||
|
||
(instance? clojure.lang.IRecord x) | ||
x | ||
|
||
(map? x) | ||
(into (empty x) (map walk-exprs' x)) | ||
|
||
;; special case to handle clojure.test | ||
(and (symbol? x) (-> x meta :test)) | ||
(vary-meta x update-in [:test] walk-exprs') | ||
|
||
:else | ||
x)] | ||
(merge-meta x' (meta x)))))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only change here was to fix the indentation and use the merge-meta
helper function I wrote to simplify things a bit
@ztellman bump |
Hi, I'm sorry for my lack of response so far, this isn't a repo I've thought about in quite some time. If it were to get moved over to the |
Fixes #33
The root cause of the issue was that the last form in expanded inline function calls would be marked with
^::transformed
metadata to prevent infinite expansions in cases where the resultant form looked like it could be an inline function form. e.g.(inc 1)
expands to(. clojure.lang.Numbers (inc 1))
; the intention was that by marking the(inc 1)
as^::transformed
we would know not to try to expand it as an inline function a second time. This however caused problems when using inlineable functions inside other inlineable functions -- see #33.After poking around a bit I determined the
^::transformed
metadata isn't needed because the code that handles java interop forms (dothandler
) does not apply the expression-walking function to the method form (e.g.(inc 1)
) or the parent.
Java interop form. I added tests to verify that this indeed works as expected even without marking things as^::transformed
.As part of figuring out how to fix this issue I did a bit of refactoring and broke
macroexpand
out into a series of smaller functions to make it easier to follow. I added a bunch of extra tests around this refactored code. Hope that's ok!