2

Sometimes I get inconsistent result when I check if a class extends a trait. I'm using scala 2.12.8.

My project uses ru.Type to dynamically build a chain of operations. The output of an operation must conform to the input of the next one.

Before linking two operations, I check if type are compatible using:

def checkFrom(t: ru.Type): Boolean = t <:< ru.typeOf[ExpectedTrait[_, _, _]]

But sometimes (rarely in fact), <:< returns false instead true (I didn't identify the cause). I've added debug message:

def checkFrom(t: ru.Type): Boolean = {
  val expectedType = ru.typeOf[ExpectedTrait[_, _, _]]
  val r = t <:< expectedType
  if (!r) println(s"$t is not a $expectedType (${t <:< expectedType})")
  r
}

I can see message like: MyClass is not a ExpectedTrait (true). The first evaluation of <:< returns false and the second returns true !

t is an Types$ClassNoArtgsTypeRef and expectedType is a Types$ExistentialType

--edit-1--

All ru.Type come from ru.typeOf[X]. In this case, I don't use rm.classSymbol(x.getClass).toType.

This issue is probably related to inconsistency-with-scala-reflection-library

Does it exist a workaround ?

--edit-2--

I can reproduce the error with the following code:

import scala.reflect.runtime.{universe => ru}

abstract class BaseClass[A, This <: BaseClass[A, This]](a: A) {
  def newInstance(a: A): This
}

abstract class ExtClass[A, This <: ExtClass[A, This]](a: A) extends BaseClass[A, This](a)

class MyClass(n: Int) extends ExtClass[Int, MyClass](n) {
  override def newInstance(a: Int): MyClass = new MyClass(a)
}

object ReflectionTest extends App {
  def test[T: ru.TypeTag](tpe: ru.Type): Boolean = {
    val r = tpe <:< ru.typeOf[T]
    if (!r) println(s"test fails: ${tpe <:< ru.typeOf[T]}")
    r
  }
  println((0 until 1000).par.forall(_ => test[BaseClass[_, _]](ru.typeOf[MyClass])))
}

I think the key point is the parallel execution. Here an example of output:

test fails: true
test fails: true
false
To-om
  • 75
  • 6

0 Answers0