Skip to content

Commit 71cbbe1

Browse files
oderskyWojciechMazur
authored andcommitted
Heal occurrences of => T between ElimByName and Erasure
There's a window of vulnerability between ElimByName and Erasure where some ExprTypes `=> T` that appear as parameters of function types are not yet converted to by-name functions `() ?=> T`. These would cause an assertion violation when used as operands of & or |. We fix this on the fly when forming these types in TypeComparer. As explained in ElimByName, we can't fix it beforehand by mapping all occurrences of `=> T` to `() ?=> T` since that could lead to cycles. Fixes #19548 [Cherry-picked 1ea4c86]
1 parent 5af5c71 commit 71cbbe1

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,6 +2421,19 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24212421
NoType
24222422
}
24232423

2424+
/** There's a window of vulnerability between ElimByName and Erasure where some
2425+
* ExprTypes `=> T` that appear as parameters of function types are not yet converted
2426+
* to by-name functions `() ?=> T`. These would cause an assertion violation when
2427+
* used as operands of & or |. We fix this on the fly here. As explained in
2428+
* ElimByName, we can't fix it beforehand by mapping all occurrences of `=> T` to
2429+
* `() ?=> T` since that could lead to cycles.
2430+
*/
2431+
private def dropExpr(tp: Type): Type = tp match
2432+
case ExprType(rt) if Phases.elimByNamePhase <= ctx.phase && !ctx.erasedTypes =>
2433+
defn.ByNameFunction(rt)
2434+
case _ =>
2435+
tp
2436+
24242437
private def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
24252438
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"andTypeGen(${tp1.show}, ${tp2.show})", subtyping, show = true) {
24262439
val t1 = distributeAnd(tp1, tp2)
@@ -2429,7 +2442,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24292442
val t2 = distributeAnd(tp2, tp1)
24302443
if (t2.exists) t2
24312444
else if (isErased) erasedGlb(tp1, tp2)
2432-
else liftIfHK(tp1, tp2, op, original, _ | _)
2445+
else liftIfHK(dropExpr(tp1), dropExpr(tp2), op, original, _ | _)
24332446
// The ` | ` on variances is needed since variances are associated with bounds
24342447
// not lambdas. Example:
24352448
//
@@ -2473,7 +2486,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24732486
val t2 = distributeOr(tp2, tp1, isSoft)
24742487
if (t2.exists) t2
24752488
else if (isErased) erasedLub(tp1, tp2)
2476-
else liftIfHK(tp1, tp2, OrType.balanced(_, _, soft = isSoft), _ | _, _ & _)
2489+
else liftIfHK(dropExpr(tp1), dropExpr(tp2), OrType.balanced(_, _, soft = isSoft), _ | _, _ & _)
24772490
}
24782491
}
24792492

tests/pos/i19548.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def byName[T](p: => T): T = p
2+
val test = (if ??? then byName else (??? : ((=> Int) => Int))) (42)

0 commit comments

Comments
 (0)