@@ -69,6 +69,7 @@ class JSCodeGen()(using genCtx: Context) {
69
69
// Some state --------------------------------------------------------------
70
70
71
71
private val generatedClasses = mutable.ListBuffer .empty[js.ClassDef ]
72
+ private val generatedStaticForwarderClasses = mutable.ListBuffer .empty[(Symbol , js.ClassDef )]
72
73
73
74
private val currentClassSym = new ScopedVar [Symbol ]
74
75
private val currentMethodSym = new ScopedVar [Symbol ]
@@ -111,6 +112,7 @@ class JSCodeGen()(using genCtx: Context) {
111
112
genCompilationUnit(ctx.compilationUnit)
112
113
} finally {
113
114
generatedClasses.clear()
115
+ generatedStaticForwarderClasses.clear()
114
116
}
115
117
}
116
118
@@ -179,6 +181,39 @@ class JSCodeGen()(using genCtx: Context) {
179
181
180
182
for (tree <- generatedClasses)
181
183
genIRFile(cunit, tree)
184
+
185
+ if (generatedStaticForwarderClasses.nonEmpty) {
186
+ /* #4148 Add generated static forwarder classes, except those that
187
+ * would collide with regular classes on case insensitive file systems.
188
+ */
189
+
190
+ /* I could not find any reference anywhere about what locale is used
191
+ * by case insensitive file systems to compare case-insensitively.
192
+ * In doubt, force the English locale, which is probably going to do
193
+ * the right thing in virtually all cases (especially if users stick
194
+ * to ASCII class names), and it has the merit of being deterministic,
195
+ * as opposed to using the OS' default locale.
196
+ * The JVM backend performs a similar test to emit a warning for
197
+ * conflicting top-level classes. However, it uses `toLowerCase()`
198
+ * without argument, which is not deterministic.
199
+ */
200
+ def caseInsensitiveNameOf (classDef : js.ClassDef ): String =
201
+ classDef.name.name.nameString.toLowerCase(java.util.Locale .ENGLISH )
202
+
203
+ val generatedCaseInsensitiveNames =
204
+ generatedClasses.map(caseInsensitiveNameOf).toSet
205
+
206
+ for ((site, classDef) <- generatedStaticForwarderClasses) {
207
+ if (! generatedCaseInsensitiveNames.contains(caseInsensitiveNameOf(classDef))) {
208
+ genIRFile(cunit, classDef)
209
+ } else {
210
+ report.warning(
211
+ s " Not generating the static forwarders of ${classDef.name.name.nameString} " +
212
+ " because its name differs only in case from the name of another class or trait in this compilation unit." ,
213
+ site.srcPos)
214
+ }
215
+ }
216
+ }
182
217
}
183
218
184
219
private def genIRFile (cunit : CompilationUnit , tree : ir.Trees .ClassDef ): Unit = {
@@ -346,7 +381,7 @@ class JSCodeGen()(using genCtx: Context) {
346
381
forwarders,
347
382
Nil
348
383
)(js.OptimizerHints .empty)
349
- generatedClasses += forwardersClassDef
384
+ generatedStaticForwarderClasses += sym -> forwardersClassDef
350
385
}
351
386
}
352
387
allMemberDefsExceptStaticForwarders
0 commit comments