Skip to content

Commit df0e3f7

Browse files
committed
simplify changes to distributeAnd
1 parent 0827f5e commit df0e3f7

File tree

1 file changed

+61
-75
lines changed

1 file changed

+61
-75
lines changed

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

Lines changed: 61 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import reporting.trace
2525
import annotation.constructorOnly
2626
import cc.{CapturingType, derivedCapturingType, CaptureSet, stripCapturing, isBoxedCapturing, boxed, boxedUnlessFun, boxedIfTypeParam, isAlwaysPure}
2727
import NameKinds.WildcardParamName
28+
import NullOpsDecorator.stripFlexible
2829

2930
/** Provides methods to compare types.
3031
*/
@@ -2481,15 +2482,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24812482
NoType
24822483
}
24832484

2484-
private def andTypeGen(tp1: Type, tp2: Type, op: (Type, Type) => Type,
2485-
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"andTypeGen(${tp1.show}, ${tp2.show})", subtyping, show = true) {
2486-
val t1 = distributeAnd(tp1, tp2)
2487-
if (t1.exists) t1
2488-
else {
2489-
val t2 = distributeAnd(tp2, tp1)
2490-
if (t2.exists) t2
2491-
else if (isErased) erasedGlb(tp1, tp2)
2492-
else liftIfHK(tp1, tp2, op, original, _ | _)
2485+
private def andTypeGen(tp1orig: Type, tp2orig: Type, op: (Type, Type) => Type,
2486+
original: (Type, Type) => Type = _ & _, isErased: Boolean = ctx.erasedTypes): Type = trace(s"andTypeGen(${tp1orig.show}, ${tp2orig.show})", subtyping, show = true) {
2487+
val tp1 = tp1orig.stripFlexible
2488+
val tp2 = tp2orig.stripFlexible
2489+
val ret = {
2490+
val t1 = distributeAnd(tp1, tp2)
2491+
if (t1.exists) t1
2492+
else {
2493+
val t2 = distributeAnd(tp2, tp1)
2494+
if (t2.exists) t2
2495+
else if (isErased) erasedGlb(tp1, tp2)
2496+
else liftIfHK(tp1, tp2, op, original, _ | _)
24932497
// The ` | ` on variances is needed since variances are associated with bounds
24942498
// not lambdas. Example:
24952499
//
@@ -2499,7 +2503,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24992503
//
25002504
// Here, `F` is treated as bivariant in `O`. That is, only bivariant implementation
25012505
// of `F` are allowed. See neg/hk-variance2s.scala test.
2506+
}
25022507
}
2508+
if(tp1orig.isInstanceOf[FlexibleType] && tp2orig.isInstanceOf[FlexibleType]) FlexibleType(ret) else ret
25032509
}
25042510

25052511
/** Form a normalized conjunction of two types.
@@ -2571,73 +2577,53 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25712577
/** Try to distribute `&` inside type, detect and handle conflicts
25722578
* @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
25732579
*/
2574-
private def distributeAnd(tp1: Type, tp2: Type): Type = {
2575-
var ft1 = false
2576-
var ft2 = false
2577-
def recur(tp1: Type, tp2: Type): Type = tp1 match {
2578-
case tp1 @ FlexibleType(tp) =>
2579-
// Hack -- doesn't generalise to other intersection/union types
2580-
// but covers a common special case for pattern matching
2581-
ft1 = true
2582-
recur(tp, tp2)
2583-
case tp1 @ AppliedType(tycon1, args1) =>
2584-
tp2 match {
2585-
case AppliedType(tycon2, args2)
2586-
if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2587-
val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2588-
if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2589-
else {
2590-
NoType
2591-
}
2592-
case FlexibleType(tp) =>
2593-
// Hack from above
2594-
ft2 = true
2595-
recur(tp1, tp)
2596-
case _ =>
2597-
NoType
2598-
}
2599-
2600-
// if result exists and is not notype, maybe wrap result in flex based on whether seen flex on both sides
2601-
case tp1: RefinedType =>
2602-
// opportunistically merge same-named refinements
2603-
// this does not change anything semantically (i.e. merging or not merging
2604-
// gives =:= types), but it keeps the type smaller.
2605-
tp2 match {
2606-
case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
2607-
val jointInfo = Denotations.infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false)
2608-
if jointInfo.exists then
2609-
tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2610-
else
2611-
NoType
2612-
case _ =>
2613-
NoType
2614-
}
2615-
case tp1: RecType =>
2616-
tp1.rebind(recur(tp1.parent, tp2))
2617-
case ExprType(rt1) =>
2618-
tp2 match {
2619-
case ExprType(rt2) =>
2620-
ExprType(rt1 & rt2)
2621-
case _ =>
2580+
private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match {
2581+
case tp1 @ AppliedType(tycon1, args1) =>
2582+
tp2 match {
2583+
case AppliedType(tycon2, args2)
2584+
if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2585+
val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2586+
if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2587+
else NoType
2588+
case _ =>
2589+
NoType
2590+
}
2591+
case tp1: RefinedType =>
2592+
// opportunistically merge same-named refinements
2593+
// this does not change anything semantically (i.e. merging or not merging
2594+
// gives =:= types), but it keeps the type smaller.
2595+
tp2 match {
2596+
case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
2597+
val jointInfo = Denotations.infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false)
2598+
if jointInfo.exists then
2599+
tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2600+
else
26222601
NoType
2623-
}
2624-
case tp1: TypeVar if tp1.isInstantiated =>
2625-
tp1.underlying & tp2
2626-
case CapturingType(parent1, refs1) =>
2627-
if subCaptures(tp2.captureSet, refs1, frozen = true).isOK
2628-
&& tp1.isBoxedCapturing == tp2.isBoxedCapturing
2629-
then
2630-
parent1 & tp2
2631-
else
2632-
tp1.derivedCapturingType(parent1 & tp2, refs1)
2633-
case tp1: AnnotatedType if !tp1.isRefining =>
2634-
tp1.underlying & tp2
2635-
case _ =>
2636-
NoType
2637-
}
2638-
// if flex on both sides, return flex type
2639-
val ret = recur(tp1, tp2)
2640-
if (ft1 && ft2) then FlexibleType(ret) else ret
2602+
case _ =>
2603+
NoType
2604+
}
2605+
case tp1: RecType =>
2606+
tp1.rebind(distributeAnd(tp1.parent, tp2))
2607+
case ExprType(rt1) =>
2608+
tp2 match {
2609+
case ExprType(rt2) =>
2610+
ExprType(rt1 & rt2)
2611+
case _ =>
2612+
NoType
2613+
}
2614+
case tp1: TypeVar if tp1.isInstantiated =>
2615+
tp1.underlying & tp2
2616+
case CapturingType(parent1, refs1) =>
2617+
if subCaptures(tp2.captureSet, refs1, frozen = true).isOK
2618+
&& tp1.isBoxedCapturing == tp2.isBoxedCapturing
2619+
then
2620+
parent1 & tp2
2621+
else
2622+
tp1.derivedCapturingType(parent1 & tp2, refs1)
2623+
case tp1: AnnotatedType if !tp1.isRefining =>
2624+
tp1.underlying & tp2
2625+
case _ =>
2626+
NoType
26412627
}
26422628

26432629
/** Try to distribute `|` inside type, detect and handle conflicts

0 commit comments

Comments
 (0)