Skip to content

Commit a6dc3db

Browse files
committed
Improve CannotHaveSameNameAs msg when is defined in self
1 parent 9d9314b commit a6dc3db

File tree

5 files changed

+27
-10
lines changed

5 files changed

+27
-10
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,12 +1472,26 @@ object messages {
14721472
|"""
14731473
}
14741474

1475-
case class CannotHaveSameNameAs(sym: Symbol, cls: Symbol)(implicit ctx: Context)
1475+
case class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context)
14761476
extends Message(CannotHaveSameNameAsID) {
1477-
val msg = hl"""$sym cannot have the same name as ${cls.showLocated} -- class definitions cannot be overridden"""
1477+
import CannotHaveSameNameAs._
1478+
def resonMessage: String = reason match {
1479+
case CannotBeOverridden => "class definitions cannot be overridden"
1480+
case DefinedInSelf(self) =>
1481+
s"""cannot define ${sym.showKind} member with the same name as a ${cls.showKind} member in self reference ${self.name}.
1482+
|(Note: this can be resolved by using another name)
1483+
|""".stripMargin
1484+
}
1485+
1486+
val msg = hl"""$sym cannot have the same name as ${cls.showLocated} -- """ + resonMessage
14781487
val kind = "Syntax"
14791488
val explanation = ""
14801489
}
1490+
object CannotHaveSameNameAs {
1491+
sealed trait Reason
1492+
case object CannotBeOverridden extends Reason
1493+
case class DefinedInSelf(self: tpd.ValDef) extends Reason
1494+
}
14811495

14821496
case class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context)
14831497
extends Message(ValueClassesMayNotDefineInnerID) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ object Checking {
347347
checkNoConflict(Abstract, Override)
348348
if (sym.isType && !sym.is(Deferred))
349349
for (cls <- sym.allOverriddenSymbols.filter(_.isClass)) {
350-
fail(CannotHaveSameNameAs(sym, cls))
350+
fail(CannotHaveSameNameAs(sym, cls, CannotHaveSameNameAs.CannotBeOverridden))
351351
sym.setFlag(Private) // break the overriding relationship by making sym Private
352352
}
353353
}

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,15 +1317,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13171317
}
13181318

13191319
/** Checks if one of the decls is a type with the same name as class type member in selfType */
1320-
def classExistsOnSelf(decls: Scope, selfType: Type): Boolean = {
1320+
def classExistsOnSelf(decls: Scope, self: tpd.ValDef): Boolean = {
1321+
val selfType = self.tpt.tpe
13211322
if (!selfType.exists || (selfType.classSymbol eq cls)) false
13221323
else {
13231324
def memberInSelfButNotThis(decl: Symbol) =
13241325
selfType.member(decl.name).symbol.filter(other => other.isClass && other.owner != cls)
13251326
decls.iterator.filter(_.isType).foldLeft(false) { (foundRedef, decl) =>
13261327
val other = memberInSelfButNotThis(decl)
1327-
if (other.exists)
1328-
ctx.error(CannotHaveSameNameAs(decl, other), decl.pos)
1328+
if (other.exists) {
1329+
val msg = CannotHaveSameNameAs(decl, other, CannotHaveSameNameAs.DefinedInSelf(self))
1330+
ctx.error(msg, decl.pos)
1331+
}
13291332
foundRedef || other.exists
13301333
}
13311334
}
@@ -1336,7 +1339,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13361339
val parentsWithClass = ensureFirstIsClass(parents mapconserve typedParent, cdef.namePos)
13371340
val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx)
13381341
val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
1339-
if (self1.tpt.tpe.isError || classExistsOnSelf(cls.unforcedDecls, self1.tpt.tpe)) {
1342+
if (self1.tpt.tpe.isError || classExistsOnSelf(cls.unforcedDecls, self1)) {
13401343
// fail fast to avoid typing the body with an error type
13411344
cdef.withType(UnspecifiedErrorType)
13421345
} else {

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ class ErrorMessagesTests extends ErrorMessagesTest {
669669
.expect { (ictx, messages) =>
670670
implicit val ctx: Context = ictx
671671
assertMessageCount(1, messages)
672-
val CannotHaveSameNameAs(symbol, cls) :: Nil = messages
672+
val CannotHaveSameNameAs(symbol, cls, _) :: Nil = messages
673673
assertEquals("class A", symbol.show)
674674
assertEquals("class A", cls.show)
675675
}

tests/neg/i2473.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
trait Foo { trait Inner }
22
trait Bar { foo: Foo =>
3-
type Inner <: foo.Inner // error: type Inner cannot have the same name as trait Inner in trait Foo -- class definitions cannot be overridden
3+
type Inner <: foo.Inner // error
44
}
55
trait Baz { baz: Foo =>
6-
class Inner // error: class Inner cannot have the same name as trait Inner in trait Foo -- class definitions cannot be overridden
6+
class Inner // error
77
}

0 commit comments

Comments
 (0)