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