Skip to content

Commit b945e61

Browse files
committed
Fix #4032: Fix direction of instantiation.
This is an altogether unsatisfying scenario. In #4032 there's an unconstrained type variable that should be interpolated and it's a coin flip whether we instantiate it to the lower or upper bound. A completely unrelated change in #3981 meant that we instantiated the variable to the upper instead of the lower bound which caused the program to fail. We now fix it by adding another condition which is also more or less arbitrary: if neither lower bound nor upper bound is defined, we now prefer again the lower bound. But all of this is quite arbitrary. The fact is that we do cut off some parts of the search space in arbitrary ways and programs have come on rely on the specific arbitrary way in which we do it.
1 parent 7655503 commit b945e61

File tree

4 files changed

+25
-2
lines changed

4 files changed

+25
-2
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3400,6 +3400,10 @@ object Types {
34003400
def hasLowerBound(implicit ctx: Context) =
34013401
!ctx.typerState.constraint.entry(origin).loBound.isBottomType
34023402

3403+
/** For uninstantiated type variables: Is the lower bound different from Nothing? */
3404+
def hasUpperBound(implicit ctx: Context) =
3405+
!ctx.typerState.constraint.entry(origin).hiBound.isTopType
3406+
34033407
/** Unwrap to instance (if instantiated) or origin (if not), until result
34043408
* is no longer a TypeVar
34053409
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ trait Inferencing { this: Typer =>
389389
if (!(vs contains tvar) && qualifies(tvar)) {
390390
typr.println(s"instantiating non-occurring ${tvar.show} in ${tp.show} / $tp")
391391
ensureConstrained()
392-
tvar.instantiate(fromBelow = tvar.hasLowerBound)
392+
tvar.instantiate(fromBelow = tvar.hasLowerBound || !tvar.hasUpperBound)
393393
}
394394
}
395395
if (constraint.uninstVars exists qualifies) interpolate()

tests/neg-tailcall/tailrec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Failures {
5656
}
5757

5858
// unsafe
59-
@tailrec final def fail3[T](x: Int): Int = fail3(x - 1) // error // error: recursive application has different type arguments
59+
@tailrec final def fail3[T](x: Int): Int = fail3(x - 1)
6060

6161
// unsafe
6262
class Tom[T](x: Int) {

tests/pos/i4032.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import scala.concurrent.Future
2+
3+
class Gen[+T] {
4+
def map[U](f: T => U): Gen[U] = ???
5+
}
6+
7+
object Gen {
8+
def oneOf[T](t0: T, t1: T): Gen[T] = ??? // Compile with this line commented
9+
def oneOf[T](g0: Gen[T], g1: Gen[T]): Gen[T] = ???
10+
}
11+
12+
class Arbitrary[T]
13+
14+
object Arbitrary {
15+
def arbitrary[T]: Gen[T] = ???
16+
17+
def arbFuture[X]: Gen[Future[X]] =
18+
Gen.oneOf(arbitrary[Future[X]], arbitrary[Throwable].map(Future.failed))
19+
}

0 commit comments

Comments
 (0)