@@ -17,20 +17,12 @@ import scala.collection.mutable
17
17
import scala .tools .nsc ._
18
18
19
19
import org .scalajs .ir
20
- import ir .{Trees => js , Types => jstpe }
20
+ import org . scalajs . ir .{Definitions => defs , Trees => js , Types => jstpe }
21
21
22
22
import org .scalajs .nscplugin .util .{ScopedVar , VarBox }
23
23
import ScopedVar .withScopedVars
24
24
25
- /** Encoding of symbol names for JavaScript
26
- *
27
- * Some issues that this encoding solves:
28
- * * Overloading: encode the full signature in the JS name
29
- * * Same scope for fields and methods of a class
30
- * * Global access to classes and modules (by their full name)
31
- *
32
- * @author Sébastien Doeraene
33
- */
25
+ /** Encoding of symbol names for the IR. */
34
26
trait JSEncoding [G <: Global with Singleton ] extends SubComponent {
35
27
self : GenJSCode [G ] =>
36
28
@@ -51,24 +43,28 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
51
43
* local name scope using [[reserveLocalName ]]. Otherwise, this name can
52
44
* clash with another local identifier.
53
45
*/
54
- final val JSSuperClassParamName = " $superClass"
46
+ final val JSSuperClassParamName = defs. LocalName ( " $superClass" )
55
47
56
48
// Fresh local name generator ----------------------------------------------
57
49
58
50
private val usedLocalNames = new ScopedVar [mutable.Set [String ]]
59
- private val returnLabelName = new ScopedVar [VarBox [Option [String ]]]
60
- private val localSymbolNames = new ScopedVar [mutable.Map [Symbol , String ]]
51
+ private val localSymbolNames = new ScopedVar [mutable.Map [Symbol , defs.LocalName ]]
52
+ private val usedLabelNames = new ScopedVar [mutable.Set [String ]]
53
+ private val labelSymbolNames = new ScopedVar [mutable.Map [Symbol , defs.LabelName ]]
54
+ private val returnLabelName = new ScopedVar [VarBox [Option [defs.LabelName ]]]
61
55
private val isReserved = Set (" arguments" , " eval" )
62
56
63
57
def withNewLocalNameScope [A ](body : => A ): A = {
64
58
withScopedVars(
65
59
usedLocalNames := mutable.Set .empty,
66
- returnLabelName := null ,
67
- localSymbolNames := mutable.Map .empty
60
+ localSymbolNames := mutable.Map .empty,
61
+ usedLabelNames := mutable.Set .empty,
62
+ labelSymbolNames := mutable.Map .empty,
63
+ returnLabelName := null
68
64
)(body)
69
65
}
70
66
71
- def reserveLocalName (name : String ): Unit = {
67
+ def reserveLocalName (name : defs. LocalName ): Unit = {
72
68
require(usedLocalNames.isEmpty,
73
69
s " Trying to reserve the name ' $name' but names have already been " +
74
70
" allocated" )
@@ -85,48 +81,61 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
85
81
case None =>
86
82
inner
87
83
case Some (labelName) =>
88
- js.Labeled (js.Ident (labelName), tpe, inner)
84
+ js.Labeled (js.LabelIdent (labelName), tpe, inner)
89
85
}
90
86
}
91
87
}
92
88
93
- private def freshName (base : String = " x" ): String = {
89
+ private def freshNameGeneric [N <: String ](base : String ,
90
+ usedNamesSet : mutable.Set [String ], createNameFun : String => N ): N = {
94
91
var suffix = 1
95
92
var longName = base
96
- while (usedLocalNames (longName) || isReserved(longName)) {
93
+ while (usedNamesSet (longName) || isReserved(longName)) {
97
94
suffix += 1
98
- longName = base+ " $" + suffix
95
+ longName = base + " $" + suffix
99
96
}
100
- usedLocalNames += longName
101
- mangleJSName(longName)
97
+ usedNamesSet += longName
98
+ createNameFun( mangleJSName(longName) )
102
99
}
103
100
104
- def freshLocalIdent ()( implicit pos : ir. Position ): js. Ident =
105
- js. Ident (freshName(), None )
101
+ private def freshName ( base : String ): defs. LocalName =
102
+ freshNameGeneric(base, usedLocalNames, defs. LocalName (_) )
106
103
107
- def freshLocalIdent (base : String )(implicit pos : ir.Position ): js.Ident =
108
- js.Ident (freshName(base ), Some (base) )
104
+ def freshLocalIdent ()(implicit pos : ir.Position ): js.LocalIdent =
105
+ js.LocalIdent (freshName(" x " ), None )
109
106
110
- private def localSymbolName (sym : Symbol ): String =
107
+ def freshLocalIdent (base : String )(implicit pos : ir.Position ): js.LocalIdent =
108
+ js.LocalIdent (freshName(base), Some (base))
109
+
110
+ private def localSymbolName (sym : Symbol ): defs.LocalName =
111
111
localSymbolNames.getOrElseUpdate(sym, freshName(sym.name.toString))
112
112
113
- def getEnclosingReturnLabel ()(implicit pos : ir.Position ): js.Ident = {
113
+ private def freshLabelName (base : String ): defs.LabelName =
114
+ freshNameGeneric(base, usedLabelNames, defs.LabelName (_))
115
+
116
+ def freshLabelIdent (base : String )(implicit pos : ir.Position ): js.LabelIdent =
117
+ js.LabelIdent (freshLabelName(base))
118
+
119
+ private def labelSymbolName (sym : Symbol ): defs.LabelName =
120
+ labelSymbolNames.getOrElseUpdate(sym, freshLabelName(sym.name.toString))
121
+
122
+ def getEnclosingReturnLabel ()(implicit pos : ir.Position ): js.LabelIdent = {
114
123
val box = returnLabelName.get
115
124
if (box == null )
116
125
throw new IllegalStateException (s " No enclosing returnable scope at $pos" )
117
126
if (box.value.isEmpty)
118
- box.value = Some (freshName (" _return" ))
119
- js.Ident (box.value.get)
127
+ box.value = Some (freshLabelName (" _return" ))
128
+ js.LabelIdent (box.value.get)
120
129
}
121
130
122
131
// Encoding methods ----------------------------------------------------------
123
132
124
- def encodeLabelSym (sym : Symbol )(implicit pos : Position ): js.Ident = {
133
+ def encodeLabelSym (sym : Symbol )(implicit pos : Position ): js.LabelIdent = {
125
134
require(sym.isLabel, " encodeLabelSym called with non-label symbol: " + sym)
126
- js.Ident (localSymbolName (sym), Some (sym.unexpandedName.decoded ))
135
+ js.LabelIdent (labelSymbolName (sym))
127
136
}
128
137
129
- def encodeFieldSym (sym : Symbol )(implicit pos : Position ): js.Ident = {
138
+ def encodeFieldSym (sym : Symbol )(implicit pos : Position ): js.FieldIdent = {
130
139
require(sym.owner.isClass && sym.isTerm && ! sym.isMethod && ! sym.isModule,
131
140
" encodeFieldSym called with non-field symbol: " + sym)
132
141
@@ -135,11 +144,12 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
135
144
if (name0.charAt(name0.length()- 1 ) != ' ' ) name0
136
145
else name0.substring(0 , name0.length()- 1 )
137
146
138
- js.Ident (mangleJSName(name), Some (sym.unexpandedName.decoded))
147
+ js.FieldIdent (defs.FieldName (mangleJSName(name)),
148
+ Some (sym.unexpandedName.decoded))
139
149
}
140
150
141
151
def encodeMethodSym (sym : Symbol , reflProxy : Boolean = false )(
142
- implicit pos : Position ): js.Ident = {
152
+ implicit pos : Position ): js.MethodIdent = {
143
153
144
154
require(sym.isMethod,
145
155
" encodeMethodSym called with non-method symbol: " + sym)
@@ -150,19 +160,20 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
150
160
151
161
val paramsString = makeParamsString(sym, reflProxy)
152
162
153
- js.Ident ( encodedName + paramsString,
163
+ js.MethodIdent (defs. MethodName ( encodedName + paramsString) ,
154
164
Some (sym.unexpandedName.decoded + paramsString))
155
165
}
156
166
157
- def encodeStaticMemberSym (sym : Symbol )(implicit pos : Position ): js.Ident = {
167
+ def encodeStaticMemberSym (sym : Symbol )(implicit pos : Position ): js.MethodIdent = {
158
168
require(sym.isStaticMember,
159
169
" encodeStaticMemberSym called with non-static symbol: " + sym)
160
- js.Ident (
161
- mangleJSName(encodeMemberNameInternal(sym)) + " __" + internalName(sym.tpe),
170
+ js.MethodIdent (
171
+ defs.MethodName (
172
+ mangleJSName(encodeMemberNameInternal(sym)) + " __" + internalName(sym.tpe)),
162
173
Some (sym.unexpandedName.decoded))
163
174
}
164
175
165
- def encodeLocalSym (sym : Symbol )(implicit pos : Position ): js.Ident = {
176
+ def encodeLocalSym (sym : Symbol )(implicit pos : Position ): js.LocalIdent = {
166
177
/* The isValueParameter case is necessary to work around an internal bug
167
178
* of scalac: for some @varargs methods, the owner of some parameters is
168
179
* the enclosing class rather the method, so !sym.owner.isClass fails.
@@ -172,7 +183,7 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
172
183
require(sym.isValueParameter ||
173
184
(! sym.owner.isClass && sym.isTerm && ! sym.isMethod && ! sym.isModule),
174
185
" encodeLocalSym called with non-local symbol: " + sym)
175
- js.Ident (localSymbolName(sym), Some (sym.unexpandedName.decoded))
186
+ js.LocalIdent (localSymbolName(sym), Some (sym.unexpandedName.decoded))
176
187
}
177
188
178
189
def foreignIsImplClass (sym : Symbol ): Boolean =
@@ -191,24 +202,26 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent {
191
202
def encodeClassRef (sym : Symbol ): jstpe.ClassRef =
192
203
jstpe.ClassRef (encodeClassFullName(sym))
193
204
194
- def encodeClassFullNameIdent (sym : Symbol )(implicit pos : Position ): js.Ident = {
195
- js.Ident (encodeClassFullName(sym), Some (sym.fullName))
196
- }
205
+ def encodeClassFullNameIdent (sym : Symbol )(implicit pos : Position ): js.ClassIdent =
206
+ js.ClassIdent (encodeClassFullName(sym), Some (sym.fullName))
207
+
208
+ private val BoxedStringModuleClassName = defs.ClassName (" jl_String$" )
209
+ private val BoxedVoidModuleClassName = defs.ClassName (" jl_Void$" )
197
210
198
- def encodeClassFullName (sym : Symbol ): String = {
211
+ def encodeClassFullName (sym : Symbol ): defs. ClassName = {
199
212
assert(! sym.isPrimitiveValueClass,
200
213
s " Illegal encodeClassFullName( ${sym.fullName}" )
201
214
if (sym == jsDefinitions.HackedStringClass ) {
202
215
ir.Definitions .BoxedStringClass
203
216
} else if (sym == jsDefinitions.HackedStringModClass ) {
204
- " jl_String$ "
217
+ BoxedStringModuleClassName
205
218
} else if (sym == definitions.BoxedUnitClass ) {
206
219
// Rewire scala.runtime.BoxedUnit to java.lang.Void, as the IR expects
207
220
// BoxedUnit$ is a JVM artifact
208
221
ir.Definitions .BoxedUnitClass
209
222
} else if (sym == jsDefinitions.BoxedUnitModClass ) {
210
223
// Same for its module class
211
- " jl_Void$ "
224
+ BoxedVoidModuleClassName
212
225
} else {
213
226
ir.Definitions .encodeClassName(
214
227
sym.fullName + (if (needsModuleClassSuffix(sym)) " $" else " " ))
0 commit comments