Skip to content

Commit 221c25c

Browse files
committed
Do not erase a regular class with a static forwarder class.
This is a forward port of the upstream commit scala-js/scala-js@6c82635 Since dotc does not support warning suppression yet, we use a regular warning to report when we avoid emitting static forwarders.
1 parent 8d4babb commit 221c25c

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class JSCodeGen()(using genCtx: Context) {
6969
// Some state --------------------------------------------------------------
7070

7171
private val generatedClasses = mutable.ListBuffer.empty[js.ClassDef]
72+
private val generatedStaticForwarderClasses = mutable.ListBuffer.empty[(Symbol, js.ClassDef)]
7273

7374
private val currentClassSym = new ScopedVar[Symbol]
7475
private val currentMethodSym = new ScopedVar[Symbol]
@@ -111,6 +112,7 @@ class JSCodeGen()(using genCtx: Context) {
111112
genCompilationUnit(ctx.compilationUnit)
112113
} finally {
113114
generatedClasses.clear()
115+
generatedStaticForwarderClasses.clear()
114116
}
115117
}
116118

@@ -179,6 +181,39 @@ class JSCodeGen()(using genCtx: Context) {
179181

180182
for (tree <- generatedClasses)
181183
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+
}
182217
}
183218

184219
private def genIRFile(cunit: CompilationUnit, tree: ir.Trees.ClassDef): Unit = {
@@ -346,7 +381,7 @@ class JSCodeGen()(using genCtx: Context) {
346381
forwarders,
347382
Nil
348383
)(js.OptimizerHints.empty)
349-
generatedClasses += forwardersClassDef
384+
generatedStaticForwarderClasses += sym -> forwardersClassDef
350385
}
351386
}
352387
allMemberDefsExceptStaticForwarders

0 commit comments

Comments
 (0)