Skip to content

Fix tests on case-insensitive filesystems #4120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions compiler/src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
*/
class Worker1(needsOutFolder: Boolean) {

val caseInsensitively = scala.collection.mutable.Map.empty[String, Symbol]
val caseInsensitively = scala.collection.mutable.HashMap.empty[String, Symbol]

def run(): Unit = {
while (true) {
Expand Down Expand Up @@ -190,19 +190,25 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
val claszSymbol = cd.symbol

// GenASM checks this before classfiles are emitted, https://github.com/scala/scala/commit/e4d1d930693ac75d8eb64c2c3c69f2fc22bec739
val lowercaseJavaClassName = claszSymbol.name.toString.toLowerCase
caseInsensitively.get(lowercaseJavaClassName) match {
case None =>
caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
case Some(dupClassSym) =>
// Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting
if (claszSymbol.name.toString < dupClassSym.name.toString)
ctx.warning(s"Class ${claszSymbol.name} differs only in case from ${dupClassSym.name}. " +
"Such classes will overwrite one another on case-insensitive filesystems.", claszSymbol.pos)
else
ctx.warning(s"Class ${dupClassSym.name} differs only in case from ${claszSymbol.name}. " +
"Such classes will overwrite one another on case-insensitive filesystems.", dupClassSym.pos)
def checkName(claszSymbol: Symbol): Unit = {
val lowercaseJavaClassName = claszSymbol.effectiveName.toString.toLowerCase
caseInsensitively.get(lowercaseJavaClassName) match {
case None =>
caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
case Some(dupClassSym) =>
if (claszSymbol.effectiveName.toString != dupClassSym.effectiveName.toString) {
// Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting
val (cl1, cl2) =
if (claszSymbol.effectiveName.toString < dupClassSym.effectiveName.toString) (claszSymbol, dupClassSym)
else (dupClassSym, claszSymbol)
ctx.warning(s"Class ${cl1.effectiveName} differs only in case from ${cl2.effectiveName}. " +
"Such classes will overwrite one another on case-insensitive filesystems.", cl1.pos)
}
}
}
checkName(claszSymbol)
if (int.symHelper(claszSymbol).isModuleClass)
checkName(claszSymbol.companionModule)

// -------------- mirror class, if needed --------------
val mirrorC =
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class CompilationTests extends ParallelTesting {
compileFile("tests/pos-special/i3323.scala", defaultOptions.and("-Xfatal-warnings")) +
compileFile("tests/pos-special/i3323b.scala", defaultOptions.and("-Xfatal-warnings")) +
compileFile("tests/pos-special/i3589-b.scala", defaultOptions.and("-Xfatal-warnings")) +
compileFile("tests/pos-special/i4166.scala", defaultOptions.and("-Xfatal-warnings")) +
compileFile("tests/pos-special/completeFromSource/Test.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) +
compileFile("tests/pos-special/completeFromSource/Test2.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) +
compileFile("tests/pos-special/completeFromSource/Test3.scala", defaultOptions.and("-sourcepath", "tests/pos-special", "-scansource")) +
Expand Down
4 changes: 4 additions & 0 deletions tests/neg-custom-args/fatal-warnings/i2673b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package Foos

class Bar // error
object bar
6 changes: 6 additions & 0 deletions tests/neg-custom-args/fatal-warnings/i2673c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package Foos

object Outer {
class X // error
object x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolasstucki Why is this not allowed? It is only an issue when class X and object x are top level, right? Scalac does not complain

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those classes will emit Outer$X.class and Outer$x.class which may conflict.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. I think Outer$x$.class will be emitted. So there is no conflict. I think it is only an issue for top level objects

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the object will generate Outer$x$.class but is the class needs a companion object it will generate Outer$X$.class which causes the conflict.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would happen with

object Outer {
  case class X()
  object x
}

or any other class that generates the module class for it.

}
7 changes: 7 additions & 0 deletions tests/pos-special/i4166.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package foo {
class Hello
}

package bar {
class Hello
}
4 changes: 2 additions & 2 deletions tests/pos/test4a.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class O[X]() {
val j:I[X] = null;
}

object o extends O[C]() {
object p extends O[C]() {
def c: C = c;
def main = {
o.j.foo(c);
p.j.foo(c);
}
}

12 changes: 6 additions & 6 deletions tests/pos/test4refine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ object test {

import test._;

trait S extends o.I {
trait S extends p.I {
type Y = D;
def bar: E = foo(c,d);
}
Expand All @@ -25,15 +25,15 @@ abstract class O() {
val j:I { type Y = X } = null;
}

object o extends O() {
object p extends O() {
type X = C;

def main = {
val s: S = null;
import s._;
foo(c,d);
o.i.foo(c,e);
o.j.foo(c,c);
p.i.foo(c,e);
p.j.foo(c,c);
bar
}
}
Expand All @@ -42,8 +42,8 @@ class Main() {
val s: S = null;
import s._;
foo(c,d);
o.i.foo(c,e);
o.j.foo(c,c);
p.i.foo(c,e);
p.j.foo(c,c);
bar;
}