@@ -50,11 +50,22 @@ public IPersistentMap getMappings(){
5050 return mappings .get ();
5151}
5252
53+ /**
54+ * An interned mapping is one where a var's ns matches the current ns and its sym matches the mapping key.
55+ * Once established, interned mappings should never change.
56+ */
57+ private boolean isInternedMapping (Symbol sym , Object o ){
58+ return (o instanceof Var &&
59+ ((Var ) o ).ns == this &&
60+ ((Var ) o ).sym .equals (sym ));
61+ }
62+
5363public Var intern (Symbol sym ){
5464 if (sym .ns != null )
5565 {
5666 throw new IllegalArgumentException ("Can't intern namespace-qualified symbol" );
5767 }
68+
5869 IPersistentMap map = getMappings ();
5970 Object o ;
6071 Var v = null ;
@@ -66,39 +77,58 @@ public Var intern(Symbol sym){
6677 mappings .compareAndSet (map , newMap );
6778 map = getMappings ();
6879 }
69- if (o instanceof Var && (( Var ) o ). ns == this )
80+ if (isInternedMapping ( sym , o ))
7081 return (Var ) o ;
7182
7283 if (v == null )
7384 v = new Var (this , sym );
7485
75- warnOrFailOnReplace (sym , o , v );
76-
86+ if (checkReplacement (sym , o , v )){
87+ while (!mappings .compareAndSet (map , map .assoc (sym , v )))
88+ map = getMappings ();
7789
78- while (! mappings . compareAndSet ( map , map . assoc ( sym , v )))
79- map = getMappings ();
90+ return v ;
91+ }
8092
81- return v ;
93+ return ( Var ) o ;
8294}
8395
84- private void warnOrFailOnReplace (Symbol sym , Object o , Object v ){
85- if (o instanceof Var )
86- {
87- Namespace ns = ((Var )o ).ns ;
88- if (ns == this || (v instanceof Var && ((Var )v ).ns == RT .CLOJURE_NS ))
89- return ;
90- if (ns != RT .CLOJURE_NS )
91- throw new IllegalStateException (sym + " already refers to: " + o + " in namespace: " + name );
92- }
93- RT .errPrintWriter ().println ("WARNING: " + sym + " already refers to: " + o + " in namespace: " + name
94- + ", being replaced by: " + v );
96+ /*
97+ This method checks if a namespace's mapping is applicable and warns on problematic cases.
98+ It will return a boolean indicating if a mapping is replaceable.
99+ The semantics of what constitutes a legal replacement mapping is summarized as follows:
100+
101+ | classification | in namespace ns | newval = anything other than ns/name | newval = ns/name |
102+ |----------------+------------------------+--------------------------------------+-------------------------------------|
103+ | native mapping | name -> ns/name | no replace, warn-if newval not-core | no replace, warn-if newval not-core |
104+ | alias mapping | name -> other/whatever | warn + replace | warn + replace |
105+ */
106+ private boolean checkReplacement (Symbol sym , Object old , Object neu ){
107+ if (old instanceof Var ) {
108+ Namespace ons = ((Var )old ).ns ;
109+ Namespace nns = neu instanceof Var ? ((Var ) neu ).ns : null ;
110+
111+ if (isInternedMapping (sym , old )){
112+ if (nns != RT .CLOJURE_NS ){
113+ RT .errPrintWriter ().println ("REJECTED: attempt to replace interned var "
114+ + old + " with " + neu + " in " + name + ", you must ns-unmap first" );
115+ return false ;
116+ }
117+ else
118+ return false ;
119+ }
120+ }
121+ RT .errPrintWriter ().println ("WARNING: " + sym + " already refers to: " + old + " in namespace: " + name
122+ + ", being replaced by: " + neu );
123+ return true ;
95124}
96125
97126Object reference (Symbol sym , Object val ){
98127 if (sym .ns != null )
99128 {
100129 throw new IllegalArgumentException ("Can't intern namespace-qualified symbol" );
101130 }
131+
102132 IPersistentMap map = getMappings ();
103133 Object o ;
104134 while ((o = map .valAt (sym )) == null )
@@ -110,13 +140,14 @@ Object reference(Symbol sym, Object val){
110140 if (o == val )
111141 return o ;
112142
113- warnOrFailOnReplace (sym , o , val );
114-
115- while (!mappings .compareAndSet (map , map .assoc (sym , val )))
116- map = getMappings ();
143+ if (checkReplacement (sym , o , val )){
144+ while (!mappings .compareAndSet (map , map .assoc (sym , val )))
145+ map = getMappings ();
117146
118- return val ;
147+ return val ;
148+ }
119149
150+ return o ;
120151}
121152
122153public static boolean areDifferentInstancesOfSameClassName (Class cls1 , Class cls2 ) {
0 commit comments