Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala compilation error: not found: type _$1

I am researching about existential types in Scala 2.12.x. For that I'm testing the following code:

trait Parent
class ChildA extends Parent
class ChildB extends Parent

def whatIsInside(opt: Option[_ <: Parent]): String = {
  opt match {
    case _: Option[_ <: ChildA] => "ChildA"
    case _: Option[_ <: ChildB] => "ChildB"
    case _                      => throw new IllegalArgumentException("unknown type")
  }
}


whatIsInside(Some(new ChildA))

I don't expect this to work at runtime because of type erasure, but nevertheless this does not even compile. I am getting the following error:

[error] ExistentialTypes.scala:12:24: not found: type _$2
[error]         case _: Option[_ <: ChildA] => "ChildA"
[error]                        ^
[error] ExistentialTypes.scala:13:24: not found: type _$3
[error]         case _: Option[_ <: ChildB] => "ChildB"
[error]                        ^

Can someone explain these errors?

like image 297
Nicolas Schejtman Avatar asked May 22 '21 16:05

Nicolas Schejtman


1 Answers

(Not a full answer, but a few notes and links; Maybe it can serve as a starting point for someone else)

In 2.12.13, the compiler seems to be able to prove that F[_ <: X] and F[X] are the same type if X occurs in covariant position:

println(implicitly[Option[_ <: ChildA] =:= Option[ChildA]])

This compiles (with warnings, but it compiles):

trait Parent
class ChildA extends Parent
class ChildB extends Parent

def whatIsInside(opt: Option[_ <: Parent]): String = {
  opt match {
    case _: Option[ChildA] => "ChildA"
    case _: Option[ChildB] => "ChildB"
    case None            => "None"
    case _ => throw new Error("meh")
  }
}

This does not compile:

trait Parent
class ChildA extends Parent
class ChildB extends Parent

def whatIsInside(opt: Option[_ <: Parent]): String = {
  opt match {
    case _: Option[_ <: ChildA] => "ChildA"
    case _: Option[_ <: ChildB] => "ChildB"
    case None            => "None"
    case _ => throw new Error("meh")
  }
}

So, it seems that it must have something to do with the bounds inference for the synthetic _$2 type-variable.

Also, this compiles:

def testConforms[A >: Nothing <: ChildA](ca: Option[A]): Option[_ <: Parent] = ca

so, unless I'm misinterpreting the spec:

If there exists a substitution σ over the type variables a_i,…,a_n such that σT conforms to pt, one determines the weakest subtype constraints C1 over the type variables a1,…,an such that C0 ∧ C1 implies that T conforms to [the expected type] pt.

, the pt would be Option[_ <: Parent], then a1,...,an would be the single synthetic type _$2, and the constraints _$2 >: Nothing <: ChildA should make the type Option[_$2] conform to Option[_ <: Parent]. So, it seems that it should work, but doesn't.


Bonus

If you just wanted to make it work, then just skip all those wildcards, they aren't needed:

trait Parent
class ChildA extends Parent
class ChildB extends Parent

def whatIsInside(opt: Option[Parent]): String = {
  opt match {
    case Some(_: ChildA) => "ChildA"
    case Some(_: ChildB) => "ChildB"
    case None            => "None"
    case _ => throw new Error("meh")
  }
}


whatIsInside(Some(new ChildA))
whatIsInside(Some(new ChildB))
whatIsInside(None)
like image 157
2 revs Avatar answered Oct 20 '22 18:10

2 revs