Skip to content

Commit 5c9ff47

Browse files
committed
Detect double toplevel definitions in separate files
Flag as error if two separate files contain toplevel definitions with the same name.
1 parent e5b3023 commit 5c9ff47

File tree

8 files changed

+38
-10
lines changed

8 files changed

+38
-10
lines changed

Diff for: compiler/src/dotty/tools/dotc/typer/Namer.scala

+19-9
Original file line numberDiff line numberDiff line change
@@ -302,21 +302,31 @@ class Namer { typer: Typer =>
302302

303303
typr.println(i"creating symbol for $tree in ${ctx.mode}")
304304

305-
def checkNoConflict(name: Name): Name = {
305+
def checkNoConflict(name: Name): Name =
306306
def errorName(msg: => String) = {
307307
ctx.error(msg, tree.sourcePos)
308308
name.freshened
309309
}
310+
def conflict(conflicting: Symbol) =
311+
val f = conflicting.associatedFile
312+
val where = if f == null then "" else i" in $f"
313+
errorName(i"$name is already defined as $conflicting$where")
314+
310315
def preExisting = ctx.effectiveScope.lookup(name)
311-
if (ctx.owner.is(PackageClass))
312-
if (preExisting.isDefinedInCurrentRun)
313-
errorName(s"${preExisting.showLocated} has already been compiled once during this run")
314-
else name
315-
else
316-
if ((!ctx.owner.isClass || name.isTypeName) && preExisting.exists)
317-
errorName(i"$name is already defined as $preExisting")
316+
if ctx.owner.is(PackageClass) then
317+
if preExisting.isDefinedInCurrentRun then conflict(preExisting)
318318
else name
319-
}
319+
else if ctx.owner.isPackageObject && name != nme.CONSTRUCTOR then
320+
def conflicts(sym: Symbol) =
321+
sym.is(Package)
322+
|| sym.isDefinedInCurrentRun && sym.associatedFile != ctx.compilationUnit.source.file
323+
ctx.owner.skipWeakOwner.info.member(name).altsWith(conflicts) match
324+
case conflicting :: _ => conflict(conflicting.symbol)
325+
case _ => name
326+
else if (!ctx.owner.isClass || name.isTypeName) && preExisting.exists then
327+
errorName(i"$name is already defined as $preExisting")
328+
else name
329+
end checkNoConflict
320330

321331
/** Create new symbol or redefine existing symbol under lateCompile. */
322332
def createOrRefine[S <: Symbol](

Diff for: tests/neg/toplevel-doubledef/defs_1.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def hello(x: String): Unit = // error: has already been compiled
2+
println(s"hello: $x")

Diff for: tests/neg/toplevel-doubledef/moredefs_1.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def hello(x: String): Unit =
2+
println(s"hi, $x")

Diff for: tests/neg/toplevel-overload/defs_1.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait A
2+
3+
def f(x: A) = s"A" // error: has already been compiled

Diff for: tests/neg/toplevel-overload/moredefs_1.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait B
2+
3+
def f(x: B) = s"B"

Diff for: tests/neg/toplevel-package/defs_1.scala

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package foo
2+
package bar
3+
class C
4+
def hello(x: String): Unit =
5+
println(s"hello: $x")
6+

Diff for: tests/neg/toplevel-package/moredefs_2.scala

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package foo
2+
def bar = 2 // error: bar is a package

Diff for: tests/run/toplevel-mixed/B_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ object X2 {
99
def bar = "hi"
1010
}
1111

12-
class X3
12+
class X4
1313

0 commit comments

Comments
 (0)