Skip to content

Commit 74a653d

Browse files
authored
Merge pull request #10928 from dotty-staging/fix-#9472
Properly report clashes between classes and objects
2 parents 64a34af + 714eb74 commit 74a653d

File tree

12 files changed

+59
-8
lines changed

12 files changed

+59
-8
lines changed

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
168168
CannotExtendJavaEnumID,
169169
InvalidReferenceInImplicitNotFoundAnnotationID,
170170
TraitMayNotDefineNativeMethodID,
171-
JavaEnumParentArgsID
171+
JavaEnumParentArgsID,
172+
AlreadyDefinedID
172173

173174
def errorNumber = ordinal - 2
174175
}

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,19 @@ import transform.SymUtils._
18471847
def explain = ""
18481848
}
18491849

1850+
class AlreadyDefined(name: Name, owner: Symbol, conflicting: Symbol)(using Context) extends NamingMsg(AlreadyDefinedID):
1851+
private def where: String =
1852+
if conflicting.effectiveOwner.is(Package) && conflicting.associatedFile != null then
1853+
i" in ${conflicting.associatedFile}"
1854+
else if conflicting.owner == owner then ""
1855+
else i" in ${conflicting.owner}"
1856+
def msg =
1857+
if conflicting.isTerm != name.isTermName then
1858+
em"$name clashes with $conflicting$where; the two must be defined together"
1859+
else
1860+
em"$name is already defined as $conflicting$where"
1861+
def explain = ""
1862+
18501863
class PackageNameAlreadyDefined(pkg: Symbol)(using Context) extends NamingMsg(PackageNameAlreadyDefinedID) {
18511864
lazy val (where, or) =
18521865
if pkg.associatedFile == null then ("", "")

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,17 @@ trait Checking {
746746
em"Implementation restriction: ${path.tpe.classSymbol} is not a valid prefix " +
747747
"for a wildcard export, as it is a package.", path.srcPos)
748748

749+
/** Check that module `sym` does not clash with a class of the same name
750+
* that is concurrently compiled in another source file.
751+
*/
752+
def checkNoModuleClash(sym: Symbol)(using Context): Unit =
753+
if sym.effectiveOwner.is(Package)
754+
&& sym.owner.info.member(sym.name.moduleClassName).symbol.isAbsent()
755+
then
756+
val conflicting = sym.owner.info.member(sym.name.toTypeName).symbol
757+
if conflicting.exists then
758+
report.error(AlreadyDefined(sym.name, sym.owner, conflicting), sym.srcPos)
759+
749760
/** Check that `tp` is a class type.
750761
* Also, if `traitReq` is true, check that `tp` is a trait.
751762
* Also, if `stablePrefixReq` is true and phase is not after RefChecks,
@@ -1266,6 +1277,7 @@ trait ReChecking extends Checking {
12661277
override def checkEnumCaseRefsLegal(cdef: TypeDef, enumCtx: Context)(using Context): Unit = ()
12671278
override def checkAnnotApplicable(annot: Tree, sym: Symbol)(using Context): Boolean = true
12681279
override def checkMatchable(tp: Type, pos: SrcPos, pattern: Boolean)(using Context): Unit = ()
1280+
override def checkNoModuleClash(sym: Symbol)(using Context) = ()
12691281
}
12701282

12711283
trait NoChecking extends ReChecking {

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,10 @@ class Namer { typer: Typer =>
136136
var conflictsDetected = false
137137

138138
def conflict(conflicting: Symbol) =
139-
val where: String =
140-
if conflicting.owner == owner then ""
141-
else if conflicting.owner.isPackageObject then i" in ${conflicting.associatedFile}"
142-
else i" in ${conflicting.owner}"
143-
report.error(i"$name is already defined as $conflicting$where", ctx.source.atSpan(span))
139+
val other =
140+
if conflicting.is(ConstructorProxy) then conflicting.companionClass
141+
else conflicting
142+
report.error(AlreadyDefined(name, owner, other), ctx.source.atSpan(span))
144143
conflictsDetected = true
145144

146145
def checkNoConflictIn(owner: Symbol) =

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,7 @@ class Typer extends Namer
19821982
val ValDef(name, tpt, _) = vdef
19831983
completeAnnotations(vdef, sym)
19841984
if (sym.isOneOf(GivenOrImplicit)) checkImplicitConversionDefOK(sym)
1985+
if sym.is(Module) then checkNoModuleClash(sym)
19851986
val tpt1 = checkSimpleKinded(typedType(tpt))
19861987
val rhs1 = vdef.rhs match {
19871988
case rhs @ Ident(nme.WILDCARD) => rhs withType tpt1.tpe

tests/neg/i9472a.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E161] Naming Error: tests/neg/i9472a/B.scala:3:0 -------------------------------------------------------------------
2+
3 |object Reproduction // error
3+
|^
4+
|Reproduction clashes with class Reproduction in tests/neg/i9472a/A.scala; the two must be defined together

tests/neg/i9472a/A.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package example.reproduction
2+
3+
class Reproduction
4+

tests/neg/i9472a/B.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package example.reproduction
2+
3+
object Reproduction // error
4+
5+

tests/neg/i9472b.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E161] Naming Error: tests/neg/i9472b/A.scala:3:0 -------------------------------------------------------------------
2+
3 |object Reproduction // error
3+
|^
4+
|Reproduction clashes with class Reproduction in tests/neg/i9472b/B.scala; the two must be defined together

tests/neg/i9472b/A.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package example.reproduction
2+
3+
object Reproduction // error
4+

tests/neg/i9472b/B.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package example.reproduction
2+
3+
class Reproduction
4+

tests/neg/trailingCommas.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ trait ArgumentExprs2 { validMethod(23, "bar")(Ev0, Ev1, ) } // error // error
77
trait ArgumentExprs3 { new ValidClass(23, "bar", )(Ev0, Ev1) } // error // error
88
trait ArgumentExprs4 { new ValidClass(23, "bar")(Ev0, Ev1, ) } // error // error
99

10-
trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } // error // error // error
10+
trait Params1 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } // error // error
1111

12-
trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } // error // error // error
12+
trait Params2 { def f(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1, ) = 1 } // error // error
1313

1414
trait ClassParams1 { final class C(foo: Int, bar: String, )(implicit ev0: Ev0, ev1: Ev1) } // error
1515
trait ClassParams2 { final class C(foo: Int, bar: String)(implicit ev0: Ev0, ev1: Ev1, ) } // error

0 commit comments

Comments
 (0)