Skip to content

Commit 1ea4c86

Browse files
committed
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
1 parent 1716bcd commit 1ea4c86

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
@@ -2508,6 +2508,19 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25082508
NoType
25092509
}
25102510

2511+
/** There's a window of vulnerability between ElimByName and Erasure where some
2512+
* ExprTypes `=> T` that appear as parameters of function types are not yet converted
2513+
* to by-name functions `() ?=> T`. These would cause an assertion violation when
2514+
* used as operands of & or |. We fix this on the fly here. As explained in
2515+
* ElimByName, we can't fix it beforehand by mapping all occurrences of `=> T` to
2516+
* `() ?=> T` since that could lead to cycles.
2517+
*/
2518+
private def dropExpr(tp: Type): Type = tp match
2519+
case ExprType(rt) if Phases.elimByNamePhase <= ctx.phase && !ctx.erasedTypes =>
2520+
defn.ByNameFunction(rt)
2521+
case _ =>
2522+
tp
2523+
25112524
private def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
25122525
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"andTypeGen(${tp1.show}, ${tp2.show})", subtyping, show = true) {
25132526
val t1 = distributeAnd(tp1, tp2)
@@ -2516,7 +2529,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25162529
val t2 = distributeAnd(tp2, tp1)
25172530
if (t2.exists) t2
25182531
else if (isErased) erasedGlb(tp1, tp2)
2519-
else liftIfHK(tp1, tp2, op, original, _ | _)
2532+
else liftIfHK(dropExpr(tp1), dropExpr(tp2), op, original, _ | _)
25202533
// The ` | ` on variances is needed since variances are associated with bounds
25212534
// not lambdas. Example:
25222535
//
@@ -2561,7 +2574,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25612574
val t2 = distributeOr(tp2, tp1, isSoft)
25622575
if (t2.exists) t2
25632576
else if (isErased) erasedLub(tp1, tp2)
2564-
else liftIfHK(tp1, tp2, OrType.balanced(_, _, soft = isSoft), _ | _, _ & _)
2577+
else liftIfHK(dropExpr(tp1), dropExpr(tp2), OrType.balanced(_, _, soft = isSoft), _ | _, _ & _)
25652578
}
25662579
}
25672580

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)