@@ -2594,53 +2594,73 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2594
2594
/** Try to distribute `&` inside type, detect and handle conflicts
2595
2595
* @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
2596
2596
*/
2597
- private def distributeAnd (tp1 : Type , tp2 : Type ): Type = tp1 match {
2598
- case tp1 @ AppliedType (tycon1, args1) =>
2599
- tp2 match {
2600
- case AppliedType (tycon2, args2)
2601
- if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2602
- val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2603
- if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2604
- else NoType
2605
- case _ =>
2606
- NoType
2607
- }
2608
- case tp1 : RefinedType =>
2609
- // opportunistically merge same-named refinements
2610
- // this does not change anything semantically (i.e. merging or not merging
2611
- // gives =:= types), but it keeps the type smaller.
2612
- tp2 match {
2613
- case tp2 : RefinedType if tp1.refinedName == tp2.refinedName =>
2614
- val jointInfo = Denotations .infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false )
2615
- if jointInfo.exists then
2616
- tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2617
- else
2597
+ private def distributeAnd (tp1 : Type , tp2 : Type ): Type = {
2598
+ var ft1 = false
2599
+ var ft2 = false
2600
+ def recur (tp1 : Type , tp2 : Type ): Type = tp1 match {
2601
+ case tp1 @ FlexibleType (tp) =>
2602
+ // Hack -- doesn't generalise to other intersection/union types
2603
+ // but covers a common special case for pattern matching
2604
+ ft1 = true
2605
+ recur(tp, tp2)
2606
+ case tp1 @ AppliedType (tycon1, args1) =>
2607
+ tp2 match {
2608
+ case AppliedType (tycon2, args2)
2609
+ if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2610
+ val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2611
+ if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2612
+ else {
2613
+ NoType
2614
+ }
2615
+ case FlexibleType (tp) =>
2616
+ // Hack from above
2617
+ ft2 = true
2618
+ recur(tp1, tp)
2619
+ case _ =>
2618
2620
NoType
2619
- case _ =>
2620
- NoType
2621
- }
2622
- case tp1 : RecType =>
2623
- tp1.rebind(distributeAnd(tp1.parent, tp2))
2624
- case ExprType (rt1) =>
2625
- tp2 match {
2626
- case ExprType (rt2) =>
2627
- ExprType (rt1 & rt2)
2628
- case _ =>
2629
- NoType
2630
- }
2631
- case tp1 : TypeVar if tp1.isInstantiated =>
2632
- tp1.underlying & tp2
2633
- case CapturingType (parent1, refs1) =>
2634
- if subCaptures(tp2.captureSet, refs1, frozen = true ).isOK
2635
- && tp1.isBoxedCapturing == tp2.isBoxedCapturing
2636
- then
2637
- parent1 & tp2
2638
- else
2639
- tp1.derivedCapturingType(parent1 & tp2, refs1)
2640
- case tp1 : AnnotatedType if ! tp1.isRefining =>
2641
- tp1.underlying & tp2
2642
- case _ =>
2643
- NoType
2621
+ }
2622
+
2623
+ // if result exists and is not notype, maybe wrap result in flex based on whether seen flex on both sides
2624
+ case tp1 : RefinedType =>
2625
+ // opportunistically merge same-named refinements
2626
+ // this does not change anything semantically (i.e. merging or not merging
2627
+ // gives =:= types), but it keeps the type smaller.
2628
+ tp2 match {
2629
+ case tp2 : RefinedType if tp1.refinedName == tp2.refinedName =>
2630
+ val jointInfo = Denotations .infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false )
2631
+ if jointInfo.exists then
2632
+ tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2633
+ else
2634
+ NoType
2635
+ case _ =>
2636
+ NoType
2637
+ }
2638
+ case tp1 : RecType =>
2639
+ tp1.rebind(recur(tp1.parent, tp2))
2640
+ case ExprType (rt1) =>
2641
+ tp2 match {
2642
+ case ExprType (rt2) =>
2643
+ ExprType (rt1 & rt2)
2644
+ case _ =>
2645
+ NoType
2646
+ }
2647
+ case tp1 : TypeVar if tp1.isInstantiated =>
2648
+ tp1.underlying & tp2
2649
+ case CapturingType (parent1, refs1) =>
2650
+ if subCaptures(tp2.captureSet, refs1, frozen = true ).isOK
2651
+ && tp1.isBoxedCapturing == tp2.isBoxedCapturing
2652
+ then
2653
+ parent1 & tp2
2654
+ else
2655
+ tp1.derivedCapturingType(parent1 & tp2, refs1)
2656
+ case tp1 : AnnotatedType if ! tp1.isRefining =>
2657
+ tp1.underlying & tp2
2658
+ case _ =>
2659
+ NoType
2660
+ }
2661
+ // if flex on both sides, return flex type
2662
+ val ret = recur(tp1, tp2)
2663
+ if (ft1 && ft2) then FlexibleType (ret) else ret
2644
2664
}
2645
2665
2646
2666
/** Try to distribute `|` inside type, detect and handle conflicts
0 commit comments