typelevel / scala

Typelevel Scala, a fork of Scala
http://typelevel.org/scala/
372 stars 21 forks source link

any.type does not convert to `_ <: any.type` when `-Yliteral-types` is on #139

Closed Atry closed 6 years ago

Atry commented 7 years ago
scalaOrganization in ThisBuild := "org.typelevel"

scalacOptions in ThisBuild += "-Yliteral-types"
  import scala.collection.mutable

  // Compiles, as expected
  def pass(a: AnyRef): mutable.Buffer[_ <: a.type] = {
    mutable.Buffer.empty[a.type]
  }

  // Expect compile, got error
  def error(a: Any): mutable.Buffer[_ <: a.type] = {
    mutable.Buffer.empty[a.type]
  }
CoAny.scala:15: type mismatch;
 found   : scala.collection.mutable.Buffer[a.type]
 required: scala.collection.mutable.Buffer[_]
    mutable.Buffer.empty[a.type]
                        ^

The Scala version is TLS 2.12.1

Atry commented 7 years ago

A workaround

  def workaround(a: Any): mutable.Buffer[_ <: a.type] = {
    def aux[A](buffer: mutable.Buffer[A]): mutable.Buffer[_ <: A] = buffer
    aux[a.type](mutable.Buffer.empty[a.type])
  }
milessabin commented 7 years ago

That does look like a bug.

But isn't the existential redundant here? Given that a.type is a singleton type, surely _ <: a.type =:= a.type? In which case a simpler equivalent signature would be,

def workaround(a: Any): mutable.Buffer[a.type] = ...
Atry commented 7 years ago

That's the point. (_ <: a.type) =:= a.type is correct. However, scalac does not realise that. At least scalac did not know mutable.Buffer[a.type] <:< mutable.Buffer[_ <: a.type] if a is Any.

milessabin commented 6 years ago

Confirming that this compiles as expected in Dotty.

milessabin commented 6 years ago

Fixed in: https://github.com/milessabin/scala/commit/e4f55f663b83e1b434ece7bbd7429c271a65b916.

milessabin commented 6 years ago

PR against Lightbend Scala is here: https://github.com/scala/scala/pull/6155.