From 01d038c43dbe47c792823776fea0b906d1c33692 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 6 Dec 2025 23:52:48 -0800 Subject: [PATCH] Overcome Name comparison hurdles --- compiler/src/dotty/tools/dotc/core/NameOps.scala | 12 ++++++++++-- compiler/src/dotty/tools/dotc/typer/Checking.scala | 7 ++++--- tests/neg/i19274.scala | 13 +++++++++++++ tests/pos/i19274.scala | 13 +++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 tests/neg/i19274.scala create mode 100644 tests/pos/i19274.scala diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index f157da843f41..87f6371f552f 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -188,9 +188,17 @@ object NameOps { } } - /** Do two target names match? An empty target name matchws any other name. */ + /** Do two target names match? An empty target name matches any other name. + * Target names match if their simple names compare equal, + * if they belong to the same term or type namespace, + * and it's not the case that only one is a field name. + */ def matchesTargetName(other: Name) = - name == other || name.isEmpty || other.isEmpty + name.isEmpty + || other.isEmpty + || name.isTermName == other.isTermName + && name.is(NameKinds.FieldName) == other.is(NameKinds.FieldName) + && name.toSimpleName == other.toSimpleName private def functionSuffixStart: Int = val first = name.firstPart diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index d975e2341111..bf1a070f6106 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -1350,11 +1350,12 @@ trait Checking { /** Check that class does not declare same symbol twice */ def checkNoDoubleDeclaration(cls: Symbol)(using Context): Unit = - val seen = new mutable.HashMap[Name, List[Symbol]].withDefaultValue(Nil) + val seen = new mutable.HashMap[String, List[Symbol]].withDefaultValue(Nil) typr.println(i"check no double declarations $cls") def checkDecl(decl: Symbol): Unit = - for other <- seen(decl.name) if decl.name != nme.ERROR && !decl.isAbsent() && !other.isAbsent() do + val key = decl.name.toString + for other <- seen(key) if decl.name != nme.ERROR && !decl.isAbsent() && !other.isAbsent() do typr.println(i"conflict? $decl $other") def javaFieldMethodPair = decl.is(JavaDefined) && other.is(JavaDefined) && @@ -1371,7 +1372,7 @@ trait Checking { report.error(em"two or more overloaded variants of $decl have default arguments", decl.srcPos) decl.resetFlag(HasDefaultParams) if !excludeFromDoubleDeclCheck(decl) then - seen(decl.name) = decl :: seen(decl.name) + seen(key) ::= decl cls.info.decls.foreach(checkDecl) cls.info match diff --git a/tests/neg/i19274.scala b/tests/neg/i19274.scala new file mode 100644 index 000000000000..5cc745c62375 --- /dev/null +++ b/tests/neg/i19274.scala @@ -0,0 +1,13 @@ +import annotation.* + +case class StaticBinding(v: String) { + private def copy$default$1(): String = ??? // error +} + +case class DynamicBinding(v: String): + @targetName("copy$default$1") + private def dynamo(): String = ??? // TODO + +@main def Demo = + val b = StaticBinding("test") + println(b) diff --git a/tests/pos/i19274.scala b/tests/pos/i19274.scala new file mode 100644 index 000000000000..6b3fe27dfd5d --- /dev/null +++ b/tests/pos/i19274.scala @@ -0,0 +1,13 @@ +//> using options -Ycheck:mixin + +object Diagnostic: + trait OriginWarning(val origin: String): + self: Warning => + object OriginWarning: + val NoOrigin = "..." + + class LintWarning(msg: String, origin: String = OriginWarning.NoOrigin) + extends Warning(msg), OriginWarning(origin) + + class Warning(msg: String) extends Diagnostic(msg) +class Diagnostic(val msg: String)