Open
Description
(Discovered while pulling on the thread exposed by https://issues.scala-lang.org/browse/SI-9899)
Consider
class C {
val p: (A, A => Unit) forSome {type A} = (1, println(_: Int))
// def unpack[T](p: (T, T => Unit)): Unit = p._2(p._1)
// unpack(p)
//
// p match { case (a, f) => f(a) }
p._2(p._1) // we get an error, but it could be clearer:
// p._1 has type A&0 (obtained by skolemizing p's type and calling _1)
// p._2 has type A&1 => Unit (obtained by skolemizing p's type *again* and calling _2)
}
2.12.0-M5's error message reveals that we are not skolemizing p's existential type:
found : C.this.p._1.type (with underlying type A)
required: A
p._2(p._1)
^
The type checker does not skolemize p's type because it is the singleton type p.type
.
The fix:
diff --git i/src/compiler/scala/tools/nsc/typechecker/Typers.scala w/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9d273ce..a67ac2a 100644
--- i/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ w/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1168,8 +1168,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
adapt(tree setType restpe, mode, pt, original)
case TypeRef(_, ByNameParamClass, arg :: Nil) if mode.inExprMode => // (2)
adapt(tree setType arg, mode, pt, original)
- case tp if mode.typingExprNotLhs && isExistentialType(tp) && !isSyntheticAccessor(context.owner) =>
- adapt(tree setType tp.dealias.skolemizeExistential(context.owner, tree), mode, pt, original)
+ case tp if mode.typingExprNotLhs && isExistentialType(tp.dealiasWiden) && !isSyntheticAccessor(context.owner) =>
+ adapt(tree setType tp.dealiasWiden.skolemizeExistential(context.owner, tree), mode, pt, original)
case PolyType(tparams, restpe) if mode.inNone(TAPPmode | PATTERNmode) && !context.inTypeConstructorAllowed => // (3)
// assert((mode & HKmode) == 0) //@M a PolyType in HKmode represents an anonymous type function,
// we're in HKmode since a higher-kinded type is expected --> hence, don't implicitly apply it to type params!
We now get a more accurate, but more confusing error:
/Users/adriaan/Library/Preferences/IdeaIC2016.2/scratches/scratch_12.scala:9: error: type mismatch;
found : ((some other)A(in value <local C>), (some other)A(in value <local C>) => Unit)#_1.type (with underlying type (some other)A(in value <local C>)) where type (some other)A(in value <local C>)
required: A(in value <local C>) where type A(in value <local C>)
p._2(p._1)
^
It would read a lot better if:
/Users/adriaan/Library/Preferences/IdeaIC2016.2/scratches/scratch_12.scala:9: error: type mismatch;
found : (A&0, A&0 => Unit)#_1.type (with underlying type A&0)
required: A&1
(Note that A&0 and A&1 arose from skolemizing p's existential type in the expressions p._2 and p._1)
p._2(p._1)
^