From ad675afe873b64ce178ba82d254d64254330a90f Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 11 Feb 2023 19:30:13 +0100 Subject: [PATCH 1/2] Generate toString only for synthetic companions of case classes Don't generate a toString method if the companion is explicitly given. This matches Scala 2's behavior. Fixes #16879 --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 6 +++++- tests/run/i16879.scala | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/run/i16879.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 6f85efb0fc8a..cab5dc273f4b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -541,7 +541,11 @@ class Namer { typer: Typer => res = cpy.TypeDef(modCls)( rhs = cpy.Template(modTempl)( derived = if (fromTempl.derived.nonEmpty) fromTempl.derived else modTempl.derived, - body = fromTempl.body ++ modTempl.body)) + body = fromTempl.body.filter { + case stat: DefDef => stat.name != nme.toString_ + // toString should only be generated if explicit companion is missing + case _ => true + } ++ modTempl.body)) if (fromTempl.derived.nonEmpty) { if (modTempl.derived.nonEmpty) report.error(em"a class and its companion cannot both have `derives` clauses", mdef.srcPos) diff --git a/tests/run/i16879.scala b/tests/run/i16879.scala new file mode 100644 index 000000000000..c01b8cb1ed89 --- /dev/null +++ b/tests/run/i16879.scala @@ -0,0 +1,16 @@ +trait Companion: + final override def toString: String = "Companion" + +case class Example(value: Int) +object Example extends Companion + +case class C() +object C: + override def toString = "CC" + +case class D() + +@main def Test = + assert(Example.toString == "Companion") + assert(C.toString == "CC") + assert(D.toString == "D") From afd499bfe1c5cf279a4635a72b98b5ddae2d65fd Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 11 Feb 2023 20:48:30 +0100 Subject: [PATCH 2/2] Update semanticdb expect file --- tests/semanticdb/metac.expect | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 32e19e1f9c46..c78d30e00863 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -467,7 +467,7 @@ Schema => SemanticDB v4 Uri => Classes.scala Text => empty Language => Scala -Symbols => 109 entries +Symbols => 108 entries Occurrences => 114 entries Synthetics => 2 entries @@ -504,10 +504,9 @@ classes/C4#copy$default$1(). => method copy$default$1 => Int @uncheckedVariance classes/C4#copy(). => method copy (param x: Int): C4 classes/C4#copy().(x) => param x: Int classes/C4#x. => val method x Int -classes/C4. => final object C4 extends Object { self: C4.type => +4 decls } +classes/C4. => final object C4 extends Object { self: C4.type => +3 decls } classes/C4.apply(). => method apply (param x: Int): C4 classes/C4.apply().(x) => param x: Int -classes/C4.toString(). => method toString => String <: scala/Any#toString(). classes/C4.unapply(). => method unapply (param x$1: C4): C4 classes/C4.unapply().(x$1) => param x$1: C4 classes/C6# => case class C6 extends Object with Product with Serializable { self: C6 => +5 decls } @@ -4559,7 +4558,7 @@ Schema => SemanticDB v4 Uri => semanticdb-Types.scala Text => empty Language => Scala -Symbols => 144 entries +Symbols => 143 entries Occurrences => 228 entries Synthetics => 1 entries @@ -4585,10 +4584,9 @@ types/Foo#copy$default$1(). => method copy$default$1 => "abc" @uncheckedVariance types/Foo#copy(). => method copy (param s: "abc"): Foo types/Foo#copy().(s) => param s: "abc" types/Foo#s. => val method s "abc" -types/Foo. => final object Foo extends Object { self: Foo.type => +6 decls } +types/Foo. => final object Foo extends Object { self: Foo.type => +5 decls } types/Foo.apply(). => method apply (param s: "abc"): Foo types/Foo.apply().(s) => param s: "abc" -types/Foo.toString(). => method toString => String <: scala/Any#toString(). types/Foo.unapply(). => method unapply (param x$1: Foo): Foo types/Foo.unapply().(x$1) => param x$1: Foo types/Foo.x. => val method x "abc" @deprecated