Open
Description
The typer substitutes bounded wildcard types for the quantifiers of existential expected types (in non-pattern mode.)
Currently, dropExistential
is implemented in terms of SubstWildcardMap
.
However, as we see below, this seems too shallow, and does not descend into the info the the quantifiers themselves.
scala> class X { def foo = { class C; new { def c: C = ??? } } }
warning: there was one feature warning; re-run with -feature for details
defined class X
scala> val et @ ExistentialType(qs, ul) = typeOf[X].decls.last.info.finalResultType
et: $r.intp.global.ExistentialType = $anon forSome { type $anon <: AnyRef{def c: C}; type C <: AnyRef }
qs: List[$r.intp.global.Symbol] = List(type $anon, type C)
ul: $r.intp.global.Type = $anon
scala> new SubstWildcardMap(qs).apply(et)
res11: $r.intp.global.Type = ? <: AnyRef{def c: C} forSome { type $anon <: AnyRef{def c: C}; type C <: AnyRef }
I believe something like this is needed:
def dropExistential(tp: Type): Type = tp match {
case ExistentialType(tparams, tpe) =>
val tparams1 = cloneSymbols(tparams)
val subst1 = new SubstWildcardMap(tparams1)
tparams1 foreach (_.modifyInfo(subst1.apply))
val result = ExistentialType(tparams1, subst1.apply(tpe.substituteSymbols(tparams, tparams1)))
result
case TypeRef(_, sym, _) if sym.isAliasType =>
val tp0 = tp.dealias
if (tp eq tp0) {
devWarning(s"dropExistential did not progress dealiasing $tp, see SI-7126")
tp
} else {
val tp1 = dropExistential(tp0)
if (tp1 eq tp0) tp else tp1
}
case _ => tp
}
I believe this will be the correct fix for pos/existentials-harmful.scala
, rather than the workaround in scala/scala@7a6fa80.
Here's a current manifestation of the bug in the REPL:
scala> { class C; new { def c: C = ??? } }
warning: there was one feature warning; re-run with -feature for details
<console>:5: error: type mismatch;
found : $anon(in lazy value $result) where type $anon(in lazy value $result) <: AnyRef{def c: C}
required: (some other)$anon(in lazy value $result) forSome { type (some other)$anon(in lazy value $result) <: AnyRef{def c: C}; type C <: AnyRef }
lazy val $result = res0
^
<console>:5: error: type mismatch;
found : $anon(in value $result) where type $anon(in value $result) <: AnyRef{def c: C}
required: $anon(in lazy value $result) forSome { type $anon(in lazy value $result) <: AnyRef{def c: C}; type C <: AnyRef }
lazy val $result = res0
^