Feuermurmel
Feuermurmel

Reputation: 9952

Type parameter bound not considered when generic type is used with unbounded wildcard

In my project, I have a constellation like this:

trait F

trait X[A <: F]

def test(x: X[_]): X[_ <: F] = x

Trait X has a type parameter with an upper bound of F. From my understanding, the types X[_] and X[_ <: F] should be equivalent. But scalac 2.12.5 complains that one is not assignable to the other.

$ scalac -Xscript test test.scala 
test.scala:5: error: type mismatch;
 found   : this.X[_$1] where type _$1
 required: this.X[_ <: this.F]
def test(x: X[_]): X[_ <: F] = x
                               ^

I cannot think of a situation where this assignment is making a sound program unsound. What are the reasons that this assignment is rejected? Is there a way that allowing such an assignment (maybe in a more complex example) is problematic?

Upvotes: 3

Views: 346

Answers (2)

Serhii Shynkarenko
Serhii Shynkarenko

Reputation: 726

i might be wrong, but it's enough to look at the definition of the function itself:

def test(x: X[_]): X[_ <: F] = x

the only information existential type gives is that there exists something. and with this signature you try to "narrow" the function result

put it in a practical way with an example. let's say you have smth like this:

def test(x: Option[_]): Option[_ <: String]

and then you call it passing inside Option[Int]. would you expect this assignment to be correct?

val result: Option[_ <: String] = test(Some(1): Option[_])

Upvotes: 0

Andrey Tyukin
Andrey Tyukin

Reputation: 44992

This assignment isn't really problematic, and the compiler even kind-of knows this, because the following implementation compiles without problems:

trait F
trait X[A <: F]
def test(x: X[_]): X[_ <: F] = x match { case q: X[t] => q }

If you give the type checker some slack by allowing it to infer more precise bounds for the type variable t, it will eventually figure out that t must be subtype of F, and then allow you to return the value q (which is the same as x) without complaining. It doesn't do this by default for some counter-intuitive reasons that probably have something to do with Java-wildcard interoperability.

(Undeleted again; My original guess didn't seem too far off, and given Dmytro Mitin's link, it doesn't even seem all that vague by comparison.)

Upvotes: 2

Related Questions