E098: Failure To Eliminate Existential

E098: Failure To Eliminate Existential (실존 타입 제거 실패)

컴파일 타임이라기보다는, Scala 2 클래스파일에서 온 복잡한 실존 타입(Existential type)을 Scala 3에 맞게 정확히 매핑하지 못할 때 나오는 경고예요.

출처: Scala 3 Reference

본문

실존 타입의 온전한 일반 형태는 Scala 3에서 더 이상 지원되지 않아요. Scala 2 클래스파일을 읽을 때 Scala 3는 그 실존 타입을 근사(approximation)하려고 시도하죠. List[T] forSome { type T }처럼 단순한 실존 타입은 깔끔하게 처리되지만, 바운드 변수를 끝까지 제거할 수 없는 복잡한 실존 타입에서는 이 경고가 뜰 수 있어요.

대부분의 사용자는 평생 마주치지 못할 흔치 않은 호환성 경고예요.

예시

이 경고는 Scala 2로 컴파일된 클래스를 로드할 때만 발생해요. 특히 바운드된 타입 변수가 깔끔하게 제거되지 못하는 위치에 등장하는 복잡한 실존 타입을 쓴 경우에요.

// Scala 2 library code (compiled with Scala 2)
// Complex existential where T appears in multiple positions
class Container {
  def get: (T, List[T]) forSome { type T } = ???
}
// Scala 3 code trying to use the Scala 2 library
val container = new Container()
val items = container.get  // Warning E098 may be emitted when loading Container.class

에러 메시지

-- [E098] Compatibility Warning: -----------------------------------------------
  |An existential type that came from a Scala-2 classfile for Container
  |cannot be mapped accurately to a Scala-3 equivalent.
  |original type    : List[T] forSome { type T }
  |reduces to       : List[?]
  |type used instead: List[Any]
  |This choice can cause follow-on type errors or hide type errors.
  |Proceed at own risk.

해결 방법

라이브러리를 직접 관리할 수 있다면 Scala 3로 다시 컴파일해요. 실존 타입 대신 와일드카드나 타입 파라미터를 쓰는 거예요. 라이브러리를 바꿀 수 없다면 타입 불일치 가능성이 있다는 점을 인지하고, 필요한 곳에 명시적인 타입 어노테이션을 붙이는 게 좋아요.

// Instead of: List[T] forSome { type T } use wildcards or add type parameter
def get[T]: List[T] = ???
def getAny: List[?] = ???