scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

A generic class property used as a default argument to a 'copy' method is typed as if it belonged to the copied type #12832

Open noresttherein opened 11 months ago

noresttherein commented 11 months ago

Reproduction steps

Scala version: 2.13.11

import castingUtil.safeCasting

class Squirrel[Nut](val nuts :Array[Nut]) {
    def copy[N](nuts :Array[N] = nuts) :Squirrel[N] = //compiles, but should not
        new Squirrel(nuts)
}
class Hamster[Seed](val seeds :Array[Seed]) { //does not compile, but should
    def copy[S](seeds :Array[S] = seeds.cast[Array[Seed], Array[S]]) :Hamster[S] = 
        new Hamster(seeds)
}
object castingUtil {
    implicit class safeCasting[T](private val self :T) {
        def cast[From >: T, To] :To = self.asInstanceOf[To]
    }
}

Problem

type arguments [Array[Seed],Array[S]] do not conform to method cast's type parameter bounds [From >: Array[S],To]
    def copy[S >: Seed](seeds :Array[S] = seeds.cast[Array[Seed], Array[S]]) :Hamster[S] =

I can't even put it into words, but apparently nuts/seeds have their type parameters mistyped in this context to the method type parameter, rather than owning class's type parameter.

Also, removing val keywords and leaving the properties as pure fields still work, that is are legal for use as default parameters. I don't report it, because it probably is a feature.

som-snytt commented 11 months ago

scalac -Vprint shows how the default args are elaborated:

    <synthetic> def copy$default$1[N]: Array[Nut] = Squirrel.this.nuts
    <synthetic> def copy$default$1[S]: Array[S] = castingUtil.safeCasting[Array[Seed]](Hamster.this.seeds).cast[Array[Seed], Array[S]]

The RHS is what you wrote, and the result type is inferred from that (as usual) and not the type of the parameter for which it is a default.

Also

scala> implicitly[Array[String] <:< Array[AnyRef]]
                 ^
       error: Cannot prove that Array[String] <:< Array[AnyRef].

Your error here is for a tweaked version of the posted source.

Separately, there are issues with default args and how they are type checked. I think Scala 3 intends to explore different implementations eventually.

SethTisue commented 11 months ago

I think Scala 3 intends to explore different implementations eventually

reference: https://contributors.scala-lang.org/t/better-default-arguments/6034