Skip to content

Commit e7708c6

Browse files
Merge pull request #6294 from dotty-staging/fix-#6127
Fix #6127: Drop followAlias
2 parents 4b9c555 + d9df5ef commit e7708c6

File tree

3 files changed

+33
-42
lines changed

3 files changed

+33
-42
lines changed

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ object Inferencing {
7979
* constrained upper bound != given upper bound and
8080
* constrained lower bound == given lower bound).
8181
* If (1) and (2) do not apply:
82-
* 3. T is maximized if it appears only contravariantly in the given type.
83-
* 4. T is minimized in all other cases.
82+
* 3. T is minimized if forceDegree is minimizeAll.
83+
* 4. Otherwise, T is maximized if it appears only contravariantly in the given type,
84+
* or if forceDegree is `noBottom` and T's minimized value is a bottom type.
85+
* 5. Otherwise, T is minimized.
8486
*
8587
* The instantiation is done in two phases:
8688
* 1st Phase: Try to instantiate minimizable type variables to
@@ -89,32 +91,29 @@ object Inferencing {
8991
* to their upper bound.
9092
*/
9193
private class IsFullyDefinedAccumulator(force: ForceDegree.Value)(implicit ctx: Context) extends TypeAccumulator[Boolean] {
94+
9295
private def instantiate(tvar: TypeVar, fromBelow: Boolean): Type = {
9396
val inst = tvar.instantiate(fromBelow)
9497
typr.println(i"forced instantiation of ${tvar.origin} = $inst")
9598
inst
9699
}
100+
97101
private[this] var toMaximize: Boolean = false
102+
98103
def apply(x: Boolean, tp: Type): Boolean = tp.dealias match {
99104
case _: WildcardType | _: ProtoType =>
100105
false
101106
case tvar: TypeVar
102107
if !tvar.isInstantiated && ctx.typerState.constraint.contains(tvar) =>
103108
force.appliesTo(tvar) && {
104109
val direction = instDirection(tvar.origin)
105-
if (direction != 0) {
106-
//if (direction > 0) println(s"inst $tvar dir = up")
107-
instantiate(tvar, direction < 0)
108-
}
109-
else {
110-
val minimize =
111-
force.minimizeAll ||
112-
variance >= 0 && !(
113-
!force.allowBottom &&
114-
defn.isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
115-
if (minimize) instantiate(tvar, fromBelow = true)
116-
else toMaximize = true
117-
}
110+
def avoidBottom =
111+
!force.allowBottom &&
112+
defn.isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true))
113+
def preferMin = force.minimizeAll || variance >= 0 && !avoidBottom
114+
if (direction != 0) instantiate(tvar, direction < 0)
115+
else if (preferMin) instantiate(tvar, fromBelow = true)
116+
else toMaximize = true
118117
foldOver(x, tvar)
119118
}
120119
case tp =>

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

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,32 +2542,6 @@ class Typer extends Namer
25422542
}
25432543
}
25442544

2545-
/** If `tp` is a TypeVar which is fully constrained (i.e. its upper bound `hi` conforms
2546-
* to its lower bound `lo`), replace `tp` by `hi`. This is necessary to
2547-
* keep the right constraints for some implicit search problems. The paradigmatic case
2548-
* is `implicitNums.scala`. Without the healing done in `followAlias`, we cannot infer
2549-
* implicitly[_3], where _2 is the typelevel number 3. The problem here is that if a
2550-
* prototype is, say, Succ[Succ[Zero]], we can infer that it's argument type is Succ[Zero].
2551-
* But if the prototype is N? >: Succ[Succ[Zero]] <: Succ[Succ[Zero]], the same
2552-
* decomposition does not work - we'd get a N?#M where M is the element type name of Succ
2553-
* instead.
2554-
*/
2555-
def followAlias(tp: Type)(implicit ctx: Context): Type = {
2556-
val constraint = ctx.typerState.constraint
2557-
def inst(tp: Type): Type = tp match {
2558-
case TypeBounds(lo, hi)
2559-
if (lo eq hi) || ctx.test(implicit ctx => hi <:< lo) =>
2560-
inst(lo)
2561-
case tp: TypeParamRef =>
2562-
constraint.typeVarOfParam(tp).orElse(tp)
2563-
case _ => tp
2564-
}
2565-
tp match {
2566-
case tp: TypeVar if constraint.contains(tp) => inst(constraint.entry(tp.origin))
2567-
case _ => tp
2568-
}
2569-
}
2570-
25712545
/** Reveal ignored parts of prototype when synthesizing the receiver
25722546
* of an extension method. This is necessary for pos/i5773a.scala
25732547
*/
@@ -2816,7 +2790,7 @@ class Typer extends Namer
28162790
}
28172791

28182792
def resultMatches(wtp: Type, pt: Type) =
2819-
constrainResult(tree.symbol, wtp, revealProtoOfExtMethod(followAlias(pt)))
2793+
constrainResult(tree.symbol, wtp, revealProtoOfExtMethod(pt))
28202794

28212795
def adaptNoArgs(wtp: Type): Tree = {
28222796
val ptNorm = underlyingApplied(pt)

tests/pos/i6127.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import reflect.ClassTag
2+
class Co[+S]
3+
object Co {
4+
def empty[X: ClassTag]: Co[X] = ???
5+
}
6+
class Contra[-S]
7+
object Contra {
8+
def empty[X: ClassTag]: Contra[X] = ???
9+
}
10+
class Foo[+FT](x: FT) {
11+
def fooArray: Foo[Array[String]] = new Foo(Array.empty)
12+
val y1: Array[String] = Array.empty
13+
def fooCo: Foo[Co[String]] = new Foo(Co.empty)
14+
val y2: Co[String] = Co.empty
15+
def fooContra: Foo[Contra[String]] = new Foo(Contra.empty)
16+
val y3: Contra[String] = Contra.empty
17+
}
18+

0 commit comments

Comments
 (0)