Dotty: Can't overload `copy` method of generic case class

Created on 29 Feb 2020  路  3Comments  路  Source: lampepfl/dotty

minimized code

case class Foo[S](s: S) {
  def copy(s: S = s): Foo[S] = Foo(s) // error
}
case class Foo0(s: String) {
  def copy(s: String = s): Foo0 = Foo0(s) // ok
}

Compilation output

[error] -- Error: /dotty-example/src/main/scala/Main.scala:1:0 
[error] 1 |case class Foo[S](s: S) {
[error]   |^
[error]   |two or more overloaded variants of method copy have default arguments
[error] one error found

expectation

Compile successfully as in scala 2.

Notes

  • dotty version: 0.22.0-RC1
  • If I remove default argument (remove = s in def copy) then error:
[error] -- [E120] Duplicate Symbol Error: /dotty-example/src/main/scala/Main.scala:2:6 
[error] 2 |  def copy(s: S): Foo[S] = Foo(s) // error
[error]   |      ^
[error]   |      Double definition:
[error]   |      def copy(s: Object): Foo in class Foo at line 1 and
[error]   |      def copy(s: Object): Foo in class Foo at line 2
[error]   |      have the same type after erasure.

-

  • scala 2.13.1 compile successfully both Foo and Foo0.
  • dotty: Foo - error, Foo0 - success
  • Side notes: I found this error when try compiling akka. Error in FSM / State[S,D]
scala2 bug

All 3 comments

case class Foo[S](s: S) {
  def copy(s: S = s): Foo[S] = Foo(s) // error
}

This creates an overload of the copy method instead of replacing the copy method generated for the case class, because the generated one has a type parameter [S]. If State#copy was declared with two type parameters like the class itself, it would compile (and this could be changed without breaking binary-compatibility). Is there a good reason to not do so ? Otherwise, is it worth trying to imitate scalac exactly here ?

We know we differ in the way copy methods get generated. We treat copy like apply: I.e. a method is synthesized unless there is one which is already given which has the same signature as the original copy method. scalac does something coarser. I am not quite sure, but I think a copy method does not get generated if there is _any_ other method called copy in scope. I believe the way it is done now is better.

Ah. Thank you.
But I think the error messages is not clear:

[error] -- [E120] Duplicate Symbol Error: /dotty-example/src/main/scala/Main.scala:2:6 
[error] 2 |  def copy(s: S): Foo[S] = Foo(s) // error
[error]   |      ^
[error]   |      Double definition:
[error]   |      def copy(s: Object): Foo in class Foo at line 1 and
[error]   |      def copy(s: Object): Foo in class Foo at line 2
[error]   |      have the same type after erasure.

As a normal scala developer (not compiler developer), I should be provided an error message like this:

...
[error]   |      def copy[S](s: S): Foo in class Foo at line 2
...

Similar for the error message two or more overloaded variants...

Was this page helpful?
0 / 5 - 0 ratings