E137: Illegal Super Accessor — 잘못된 슈퍼 접근자

E137: Illegal Super Accessor — 잘못된 슈퍼 접근자

슈퍼 접근자(super-accessor)를 구현할 때 부모 트레이트들 사이에서 충돌이 생겨 클래스를 정의할 수 없을 때 발생하는 에러예요.

출처: Scala 3 Reference

본문

트레이트가 부모를 명시적으로 지정하지 않고(super[Parent].method처럼) super.method를 호출하면, Scala는 이 클래스를 상속하는 클래스 안에 선형화(linearization) 순서에 기반한 슈퍼 접근자를 생성해요. 그런데 해석된 슈퍼 호출의 반환 타입이 트레이트가 기대하는 타입과 호환되지 않으면 이 에러가 발생해요.

이 문제는 보통 다음 상황에서 일어나요.

예시

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

에러

-- [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

해결 방법

트레이트 안에서 명시적인 슈퍼 호출을 사용하면 돼요.

// 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