Skip to content

Commit 4e22f0d

Browse files
committed
Fix #2300: Try to heal subtype failures by instantiating type variables
The idea is that if an adapt fails because an actual type A is not a subtype of an expected type B, we try to instantiate all type variables in A and, if that changes something, try again. This mitigates the discrepancy that dotc is more lazy in instantiating type variables than scalac. Fixes #2300.
1 parent 4f60767 commit 4e22f0d

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
383383
* prefix. If the result has another unsafe instantiation, raise an error.
384384
*/
385385
private def healNonvariant[T <: Tree](tree: T, pt: Type)(implicit ctx: Context): T =
386-
if (ctx.unsafeNonvariant == ctx.runId && tree.tpe.widen.hasUnsafeNonvariant)
386+
if (ctx.unsafeNonvariant == ctx.runId && tree.tpe.widen.hasUnsafeNonvariant) {
387+
println(i"HEAL $tree")
387388
tree match {
388389
case tree @ Select(qual, _) if !qual.tpe.isStable =>
389390
val alt = typedSelect(tree, pt, Typed(qual, TypeTree(SkolemType(qual.tpe.widen))))
@@ -392,7 +393,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
392393
case _ =>
393394
ctx.error(ex"unsafe instantiation of type ${tree.tpe}", tree.pos)
394395
tree
395-
}
396+
}}
396397
else tree
397398

398399
def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") {
@@ -2186,6 +2187,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
21862187
}
21872188
case _ =>
21882189
}
2190+
// try to fully instantiate type
2191+
{
2192+
val ictx = ctx.fresh.setNewTyperState
2193+
val constraint = ictx.typerState.constraint
2194+
if (isFullyDefined(wtp, force = ForceDegree.all)(ictx) &&
2195+
ictx.typerState.constraint.ne(constraint)) {
2196+
ictx.typerState.commit()
2197+
return adapt(tree, pt, original)
2198+
}
2199+
}
21892200
// try an implicit conversion
21902201
inferView(tree, pt) match {
21912202
case SearchSuccess(inferred, _, _, _) =>

tests/pos/i2300.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object hlists {
2+
sealed abstract class HList {
3+
type Merge[L <: HList] <: HList
4+
5+
def merge[L <: HList](l: L): Merge[L]
6+
}
7+
final case class HCons[H, T <: HList](head : H, tail : T) extends HList {
8+
type Merge[L <: HList] = HCons[H, tail.Merge[L]]
9+
10+
def merge[L <: HList](l: L): Merge[L] = HCons(head, tail.merge(l))
11+
}
12+
sealed trait HNil extends HList {
13+
type Merge[L <: HList] = L
14+
15+
def merge[L <: HList](l: L): Merge[L] = l
16+
}
17+
final val HNil: HNil = { case object HNil extends HNil; HNil }
18+
}
19+
20+
object Test {
21+
import hlists._
22+
23+
val merged: HCons[Int,HCons[String,HNil]] = {
24+
HCons(42, HNil) merge HCons("foo", HNil)
25+
}
26+
}

0 commit comments

Comments
 (0)