8000 Compilation failure due to `knownDirectSubclasses` and lexicographical ordering of files. · Issue #10454 · scala/bug · GitHub
[go: up one dir, main page]

Skip to content
Compilation failure due to knownDirectSubclasses and lexicographical ordering of files. #10454
@isomarcte

Description

@isomarcte

Overview

Consider a type T with at least one sub-type and a reference to that type in another file which invokes a macro (defined in another project) that invokes knownDirectSubclasses against T. If the reference to the type T occurs in a file whose filename has a lexicographical ordering which occurs before the filename of the file in which the type T is defined, a globalError is raised due to T being observed before all sub-types have been registered with the compiler.

This is related to SI-7046 which was generally thought to have been fixed in PR 5284. While that PR does list a few exceptional cases where this bug can still occur, it does not appear (to me) to list the cases documented here.

  • Scala Versions
    • The error is raised on all Scala versions in the range [2.11.9, 2.13.0-M2]. Although it appears to still be present before 2.11.9, but is silently ignored as the code which emits the globalError was only added in 2.11.9.
  • JVM Versions
    • I have tested this on OpenJDK 1.8.0_144-b01

Details

This bug is a bit tricky to describe well in prose, so I have created an example project here (https://github.com/isomarcte/scala-compiler-knownSubclasses-bug) which may be more directly helpful. The below is taken from the README.md for that project.

Here is what is happening.

Consider some sealed type T that defines all sub-classes in the companion object for the type.

sealed trait T

object T {

  final case class TImpl() extends T
}

Consider some type-class F[_] which can derive instances for certain types, assuming certain requirements for T are met. The validation of these requirements and the derivation code is done using a macro. This macro invokes knownDirectSubclasses at some point.

trait F[T]

object F {

  def instanceImpl[T : c.WeakTypeTag](
    c: Context
  ): c.Expr[F[T]] = {
    import c.universe._
    val wtt: c.WeakTypeTag[T] = implicitly[c.WeakTypeTag[T]]

    wtt.tpe.typeSymbol.asClass.knownDirectSubclasses.toString

    reify(new F[T]{})
  }

  implicit def instance[T]: F[T] = macro instanceImpl[T]
}

Finally, consider a function foo which uses T and requires that T have an instances of F.

object Foo {

    def foo[T : F]: Unit = ()

    foo[T]
}

If the T is defined in a file whose filename has a lexicographical ordering which places it after the file in which foo is defined and T highest ranking implicit instance for F is the macro derived instance, then the following will occur.

  • The call to knownDirectSubclasses in the macro will fail to see any sub-classes of T
  • When the compiler type-checks T it will raise N globalError invocations, where N is the exactly equal to the number of sub-classes for T.

If the file in which T is defined has a lexicographical ordering which places it before the file in which foo is defined, everything works great.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0