E137: Illegal Super Accessor

This error occurs when a class cannot be defined due to a conflict between its parent traits when implementing a super-accessor.

When a trait calls super.method without explicitly naming a parent (like super[Parent].method), Scala generates a super-accessor in the extending class based on the linearization order. If the resolved super-call has an incompatible return type with what the trait expects, this error is raised.

This typically happens when:

  1. A trait contains a super.method call
  2. Another trait in the hierarchy overrides the same method with a different return type
  3. Due to linearization order, the super-accessor would bind to the wrong implementation

Example

class X
class Y extends X

trait A[+T]:
  def foo: T = null.asInstanceOf[T]

trait B extends A[X]:
  override def foo: X = new X

trait C extends A[Y]:
  override def foo: Y = new Y
  def superFoo: Y = super.foo

class Fail extends B with C

Error

-- [E137] Declaration Error: example.scala:14:6 --------------------------------
14 |class Fail extends B with C
   |      ^
   |class Fail cannot be defined due to a conflict between its parents when
   |implementing a super-accessor for foo in trait C:
   |
   |1. One of its parent (C) contains a call super.foo 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 B comes before C in the linearization
   |   order of Fail, and because B overrides foo,
   |   the super-accessor in Fail is implemented as a call to
   |   super[B].foo.
   |3. However,
   |   X (the type of super[B].foo in Fail)
   |   is not a subtype of
   |   Y (the type of foo in trait C).
   |   Hence, the super-accessor that needs to be generated in Fail
   |   is illegal.
   |
   |Here are two possible ways to resolve this:
   |
   |1. Change the linearization order of Fail such that
   |   C comes before B.
   |2. Alternatively, replace super.foo in the body of trait C by a
   |   super-call to a specific parent, e.g. super[A].foo

Solution

// Use explicit super-call in the trait
class X
class Y extends X

trait A[+T]:
  def foo: T = null.asInstanceOf[T]

trait B extends A[X]:
  override def foo: X = new X

trait C extends A[Y]:
  override def foo: Y = new Y
  def superFoo: Y = super[A].foo

class Fixed extends B with C