Closed japgolly closed 3 years ago
This has to do with the fact that c.asInstanceOf[C]
is an expression, not a value.
C[?]
is not compatible with any C[A]
. If the argument is a singleton value c
, an exception is made and we treat
C[?]
as "the unknown type instance of C
that is the type of c
". This alone makes me cringe but we have to do it
since Java also does this sort of "capture conversion". But for expressions as arguments this is unsound in general.
C[?]
is not compatible with anyC[A]
.
I don't quite understand this, as I would expect it to be compatible if A := ?
, i.e. that unnamed type that the type alias C
is using. I think I would have a better chance at understanding the unsoundness you mention if you (or someone) could mock up an example. I don't see how the 3rd example shouldn't work any different than the 2nd, for instance.
Btw, in Scala 2 the 4th example is an error while the 3rd works... 😄
This is a bug in the compiler, as the following works:
object O {
class CA[A](var x: A)
type C = CA[_]
val c: CA[_] = CA(5)
def f[A](r: CA[A]): A = r.x
def g(): CA[_] = CA("hello")
f(g())
f(c.asInstanceOf[CA[_]])
}
We have two places where capture conversion kicks in. One is in typer that handles top-level wildcards. One is in TypeComparer which only works for a stable path.
The reason why the first mechanism does not work for f(c.asInstanceOf[C])
is that we forget to dealias in captureWildcards
:
With the following change, the original code compiles:
--- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -503,7 +503,7 @@ object Inferencing {
* $i is a skolem of type `scala.internal.TypeBox`, and `CAP` is its
* type member. See the documentation of `TypeBox` for a rationale why we do this.
*/
- def captureWildcards(tp: Type)(using Context): Type = tp match {
+ def captureWildcards(tp: Type)(using Context): Type = tp.dealias match {
case tp @ AppliedType(tycon, args) if tp.hasWildcardArg =>
Is this related or a different issue? https://github.com/lampepfl/dotty/issues/12796
Probably unrelated since its isInstanceOf
Note that this isn't asInstanceOf
specific, compilation also fails with e.g. def c(): C = ???; f(c())
. Presumably the key difference is whether it's a stable path or not.
we have to do it since Java also does this sort of "capture conversion"
(For background on this remark Martin made, see https://docs.oracle.com/javase/specs/jls/se16/html/jls-5.html#jls-5.1.10 — it begins with formal language, but then following that is a nice informal motivation section, in the purple box.)
Compiler version
3.0.0
Minimized code
Output
Expectation
No error.