From 0b44bbeea35752435d9b35d551e490301da036f6 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 29 Jan 2024 14:37:16 +0100 Subject: [PATCH] Move dropExpr upstream to glb and lub Avoids follow-up failures in Ycheck for the test case. [Cherry-picked 278beb8926488f35c969d2bd18aa4647ac18eaf2] --- .../dotty/tools/dotc/core/TypeComparer.scala | 71 +++++++++---------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 448163588768..7f7c167c865a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2230,40 +2230,35 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling else if !tp2.exists || (tp2 eq WildcardType) then tp1 else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp2 else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp1 - else tp2 match - case tp2: LazyRef => - glb(tp1, tp2.ref) - case _ => - tp1 match - case tp1: LazyRef => - glb(tp1.ref, tp2) - case _ => - val tp1a = dropIfSuper(tp1, tp2) - if tp1a ne tp1 then glb(tp1a, tp2) - else - val tp2a = dropIfSuper(tp2, tp1) - if tp2a ne tp2 then glb(tp1, tp2a) - else tp2 match // normalize to disjunctive normal form if possible. - case tp2 @ OrType(tp21, tp22) => - lub(tp1 & tp21, tp1 & tp22, isSoft = tp2.isSoft) - case _ => - tp1 match - case tp1 @ OrType(tp11, tp12) => - lub(tp11 & tp2, tp12 & tp2, isSoft = tp1.isSoft) - case tp1: ConstantType => - tp2 match - case tp2: ConstantType => - // Make use of the fact that the intersection of two constant types - // types which are not subtypes of each other is known to be empty. - // Note: The same does not apply to singleton types in general. - // E.g. we could have a pattern match against `x.type & y.type` - // which might succeed if `x` and `y` happen to be the same ref - // at run time. It would not work to replace that with `Nothing`. - // However, maybe we can still apply the replacement to - // types which are not explicitly written. - NothingType - case _ => andType(tp1, tp2) + else + def mergedGlb(tp1: Type, tp2: Type): Type = + val tp1a = dropIfSuper(tp1, tp2) + if tp1a ne tp1 then glb(tp1a, tp2) + else + val tp2a = dropIfSuper(tp2, tp1) + if tp2a ne tp2 then glb(tp1, tp2a) + else tp2 match // normalize to disjunctive normal form if possible. + case tp2 @ OrType(tp21, tp22) => + lub(tp1 & tp21, tp1 & tp22, isSoft = tp2.isSoft) + case _ => + tp1 match + case tp1 @ OrType(tp11, tp12) => + lub(tp11 & tp2, tp12 & tp2, isSoft = tp1.isSoft) + case tp1: ConstantType => + tp2 match + case tp2: ConstantType => + // Make use of the fact that the intersection of two constant types + // types which are not subtypes of each other is known to be empty. + // Note: The same does not apply to singleton types in general. + // E.g. we could have a pattern match against `x.type & y.type` + // which might succeed if `x` and `y` happen to be the same ref + // at run time. It would not work to replace that with `Nothing`. + // However, maybe we can still apply the replacement to + // types which are not explicitly written. + NothingType case _ => andType(tp1, tp2) + case _ => andType(tp1, tp2) + mergedGlb(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef)) } def widenInUnions(using Context): Boolean = @@ -2303,7 +2298,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft) else orType(tp1w, tp2w, isSoft = isSoft) // no need to check subtypes again } - mergedLub(tp1.stripLazyRef, tp2.stripLazyRef) + mergedLub(dropExpr(tp1.stripLazyRef), dropExpr(tp2.stripLazyRef)) } /** Try to produce joint arguments for a lub `A[T_1, ..., T_n] | A[T_1', ..., T_n']` using @@ -2424,12 +2419,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling /** 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 here. As explained in + * used as operands of glb or lub. We fix this on the fly here. As explained in * ElimByName, we can't fix it beforehand by mapping all occurrences of `=> T` to * `() ?=> T` since that could lead to cycles. */ private def dropExpr(tp: Type): Type = tp match - case ExprType(rt) if Phases.elimByNamePhase <= ctx.phase && !ctx.erasedTypes => + case ExprType(rt) if (Phases.elimByNamePhase <= ctx.phase) && !ctx.erasedTypes => defn.ByNameFunction(rt) case _ => tp @@ -2442,7 +2437,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling val t2 = distributeAnd(tp2, tp1) if (t2.exists) t2 else if (isErased) erasedGlb(tp1, tp2) - else liftIfHK(dropExpr(tp1), dropExpr(tp2), op, original, _ | _) + else liftIfHK(tp1, tp2, op, original, _ | _) // The ` | ` on variances is needed since variances are associated with bounds // not lambdas. Example: // @@ -2486,7 +2481,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling val t2 = distributeOr(tp2, tp1, isSoft) if (t2.exists) t2 else if (isErased) erasedLub(tp1, tp2) - else liftIfHK(dropExpr(tp1), dropExpr(tp2), OrType.balanced(_, _, soft = isSoft), _ | _, _ & _) + else liftIfHK(tp1, tp2, OrType.balanced(_, _, soft = isSoft), _ | _, _ & _) } }