Skip to content

Commit

Permalink
CLJS-3286: ns form does not merge ns-info
Browse files Browse the repository at this point in the history
In self-host, the ns form overwrites existing mappings instead of merging them. As in Clojure, one should be able to call (ns X) to enter a namespace without modifying it.
  • Loading branch information
Matthew Huebert authored and swannodette committed Jan 4, 2021
1 parent 73cba74 commit 9d3b8ec
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 35 deletions.
70 changes: 35 additions & 35 deletions src/main/clojure/cljs/analyzer.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -3036,6 +3036,38 @@
(symbol (str name-str "$macros"))
name)))

(defn- check-duplicate-aliases
[env old new]
(let [ns-name (:name old)]
(doseq [k [:requires :require-macros]]
(let [old-aliases (get old k)
new-aliases (get new k)]
(when-some [alias (some (set (keys new-aliases))
(->> old-aliases
(remove (fn [[k v :as entry]]
(or (= k v)
(= entry (find new-aliases k)))))
keys))]
(throw (error env
(str "Alias " alias " already exists in namespace " ns-name
", aliasing " (get old-aliases alias)))))))))

(defn- merge-ns-info [old new env]
(if (pos? (count old))
(let [deep-merge-keys
[:use-macros :require-macros :rename-macros
:uses :requires :renames :imports]]
#?(:clj
(when *check-alias-dupes*
(check-duplicate-aliases env old new)))
(merge
old
(select-keys new [:excludes])
(merge-with merge
(select-keys old deep-merge-keys)
(select-keys new deep-merge-keys))))
new))

(defmethod parse 'ns
[_ env [_ name & args :as form] _ opts]
(when-not *allow-ns*
Expand Down Expand Up @@ -3129,7 +3161,7 @@
:requires requires
:renames (merge renames core-renames)
:imports imports}]
(swap! env/*compiler* update-in [::namespaces name] merge ns-info)
(swap! env/*compiler* update-in [::namespaces name] merge-ns-info ns-info env)
(merge {:op :ns
:env env
:form form
Expand All @@ -3144,22 +3176,6 @@
(update-in [:requires]
(fn [m] (with-meta m {(@reload :require) true})))))))))

(defn- check-duplicate-aliases
[env old new]
(let [ns-name (:name old)]
(doseq [k [:requires :require-macros]]
(let [old-aliases (get old k)
new-aliases (get new k)]
(when-some [alias (some (set (keys new-aliases))
(->> old-aliases
(remove (fn [[k v :as entry]]
(or (= k v)
(= entry (find new-aliases k)))))
keys))]
(throw (error env
(str "Alias " alias " already exists in namespace " ns-name
", aliasing " (get old-aliases alias)))))))))

(defmethod parse 'ns*
[_ env [_ quoted-specs :as form] _ opts]
(when-let [not-quoted (->> (remove keyword? quoted-specs)
Expand Down Expand Up @@ -3222,24 +3238,8 @@
:uses uses
:requires requires
:renames (merge renames core-renames)
:imports imports}
ns-info
(let [ns-info' (get-in @env/*compiler* [::namespaces name])]
(if (pos? (count ns-info'))
(let [merge-keys
[:use-macros :require-macros :rename-macros
:uses :requires :renames :imports]]
#?(:clj
(when *check-alias-dupes*
(check-duplicate-aliases env ns-info' require-info)))
(merge
ns-info'
{:excludes excludes}
(merge-with merge
(select-keys ns-info' merge-keys)
(select-keys require-info merge-keys))))
require-info))]
(swap! env/*compiler* update-in [::namespaces name] merge ns-info)
:imports imports}]
(swap! env/*compiler* update-in [::namespaces name] merge-ns-info require-info env)
(merge {:op :ns*
:env env
:form form
Expand Down
13 changes: 13 additions & 0 deletions src/test/self/self_host/test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,19 @@
(is (== 1 value))
(inc! l))))))

(deftest test-ns-merge
(async done
(cljs/eval-str st
"(ns foo.bar (:require [bootstrap-test.core :refer [foo]]))
(ns foo.bar)
(foo 1 1)"
nil
{:eval node-eval
:load node-load}
(fn [{:keys [value error]}]
(is (nil? error))
(done)))))

(deftest test-cljs-1651
(let [st (cljs/empty-state)]
(async done
Expand Down

0 comments on commit 9d3b8ec

Please sign in to comment.