Skip to content

Failure to implement super-accessor to toString #6089

@bjornregnell

Description

@bjornregnell

Is this difference in behavior in Scala 2 vs dotty intentional or a bug?

// Scala 2.12.8
scala> trait X { override def toString = super.toString + " X" }
defined trait X

scala> trait Y { override def toString = super.toString + " Y" }
defined trait Y

scala> class Z extends X with Y { override def toString = super.toString + " Z" }
defined class Z

scala> new Z
res1: Z = Z@20a24edf X Y Z

In dotty

// dotty 0.14.0-bin-20190312-3c9935f-NIGHTLY 
scala> trait X { override def toString = super.toString + " X" }                                                                
     | trait Y { override def toString = super.toString + " Y" }
     | class Z extends X with Y { override def toString = super.toString + " Z" }
     | 
3 |class Z extends X with Y { override def toString = super.toString + " Z" }
  |      ^
  | class Z cannot be defined due to a conflict between its parents when
  | implementing a super-accessor for toString in trait Y:
  | 
  | 1. One of its parent (Y) contains a call super.toString in its body,
  |    and when a super-call in a trait is written without an explicit parent
  |    listed in brackets, it is implemented by a generated super-accessor in
  |    the class that extends this trait based on the linearization order of
  |    the class.
  | 2. Because X comes before Y in the linearization
  |    order of Z, and because X overrides toString,
  |    the super-accessor in Z is implemented as a call to
  |    super[X].toString.
  | 3. However,
  |    String (the type of super[X].toString in Z)
  |    is not a subtype of
  |    (): String (the type of toString in trait Y).
  |    Hence, the super-accessor that needs to be generated in Z
  |    is illegal.
  | 
  | Here are two possible ways to resolve this:
  | 
  | 1. Change the linearization order of Z such that
  |    Y comes before X.
  | 2. Alternatively, replace super.toString in the body of trait Y by a
  |    super-call to a specific parent, e.g. super[Object].toString

I wonder why 3 talks about the subtype of (): String.
And if I follow proposal 1 from this error message it is still an error and proposal 2 gives this:

scala> trait X { override def toString = super[Object].toString + " X" }                                                                                                                      
     | trait Y { override def toString = super[Object].toString + " Y" }
     | class Z extends X with Y { override def toString = super.toString + " Z" }
     | 
// defined trait X
// defined trait Y
// defined class Z

scala> new Z
val res0: Z = Z@30a3e9b Y Z

Compared to Scala 2 which also prints X ...
Shouldn't the behavior in Scala 2 and dotty be the same when not specifying parent super[Object] ?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions