self-host: Doesn't load dep ns when loading own cache
Description
Background: Both load-fn and eval-fn support the concept of passing JavaScript and analysis cache info. Such data passed to eval-fn should be able to be stored and subsequently passed to load-fn upon subsequent runs in order to effect analysis/compilation caching.
If one namespace depends on another then transitive loading occurs if no caching is involved. But if cached information it returned to load-fn when the top-level namespace is loaded, then transitive loading does not occur.
My speculation is that this is the case because, while the analysis cache is incorporated here
Then if you start fresh, but go through the same sequence, consuming cached information, you start off the same with load-fn being called the same way:
{:name foo.core, :macros nil, :path "foo/core"}
and with the callback now being passed cached information back in return:
Broke out with a few explicitly named helper functions. Let me know if I took it too far. Also, feel free to simply modify this to suit.
David Nolen
September 2, 2015 at 10:51 PM
Lets break out helper functions for this one please. Thanks!
Mike Fikes
September 2, 2015 at 9:55 PM
This appears to be a fairly straightforward patch, but attached it with a -1 revision indicator in case it ultimately needs a few rounds of review. (IMHO, there is definitely no urgency to review this, as it is a self-host ticket.)
David Nolen
August 30, 2015 at 4:34 PM
A patch for this is welcome. Analysis caches for a ns include all the information needed to load lib and macro dependencies.
Background: Both load-fn and eval-fn support the concept of passing JavaScript and analysis cache info. Such data passed to eval-fn should be able to be stored and subsequently passed to load-fn upon subsequent runs in order to effect analysis/compilation caching.
If one namespace depends on another then transitive loading occurs if no caching is involved. But if cached information it returned to load-fn when the top-level namespace is loaded, then transitive loading does not occur.
My speculation is that this is the case because, while the analysis cache is incorporated here
https://github.com/clojure/clojurescript/blob/r1.7.122/src/main/cljs/cljs/js.cljs#L206-L208
nothing further is done to load dependent namespaces as is done when ClojureScript source is passed in the callback.
Here is a concrete example. Let
foo.core
depend onbar.core
:(ns foo.core (:require bar.core)) (prn bar.core/x)
(ns bar.core) (def x 2)
If you require
foo.core
(via anns
form passed toeval-str
), then load-fn is called with{:name foo.core, :macros nil, :path "foo/core"}
and it is called back upon with the loaded ClojureScript source:
{:lang :clj, :source "(ns foo.core\n (:require bar.core))\n\n(prn bar.core/x)\n"}
and the embedded
:require
then causes load-fn to be invoked forbar.core
:{:name bar.core, :macros nil, :path "bar/core"}
with its source being passed to the callback:
{:lang :clj, :source "(ns bar.core)\n\n(def x 2)\n"}
Then the evaluation phase begins with two evaluations (done properly in reverse dependency order):
{:lang :clj, :name bar.core, :path "bar/core", :source "goog.provide(\"bar.core\");\nbar.core.x = 2;\n", :cache {:use-macros nil, :excludes #{}, :name bar.core, :imports nil, :requires nil, :uses nil, :defs {x {:name bar.core/x, :file nil, :line 3, :column 1, :end-line 3, :end-column 7, :meta {:file bar.core, :line 3, :column 6, :end-line 3, :end-column 7}}}, :require-macros nil, :doc nil}}
and
{:lang :clj, :name foo.core, :path "foo/core", :source "goog.provide(\"foo.core\");\ncljs.core.prn.call(null,bar.core.x);\n", :cache {:name foo.core, :doc nil, :excludes #{}, :use-macros nil, :require-macros nil, :uses nil, :requires {bar.core bar.core}, :imports nil}}
which causes
2
to be printed.Then if you start fresh, but go through the same sequence, consuming cached information, you start off the same with load-fn being called the same way:
{:name foo.core, :macros nil, :path "foo/core"}
and with the callback now being passed cached information back in return:
{:lang :js, :source "goog.provide(\"foo.core\");\ncljs.core.prn.call(null,bar.core.x);\n", :cache {:name foo.core, :doc nil, :excludes #{}, :use-macros nil, :require-macros nil, :uses nil, :requires {bar.core bar.core}, :imports nil}}
This JavaScript is evaluated by
cljs.js
herehttps://github.com/clojure/clojurescript/blob/r1.7.122/src/main/cljs/cljs/js.cljs#L205
and this causes this to be printed
Can't find variable: bar
Perhaps this isn't a defect if instead it is expected that clients of
cljs.js
handle the loading of dependent namespaces when caching is involved.