@@ -25,6 +25,7 @@ import reporting.trace
25
25
import annotation .constructorOnly
26
26
import cc .{CapturingType , derivedCapturingType , CaptureSet , stripCapturing , isBoxedCapturing , boxed , boxedUnlessFun , boxedIfTypeParam , isAlwaysPure }
27
27
import NameKinds .WildcardParamName
28
+ import NullOpsDecorator .stripFlexible
28
29
29
30
/** Provides methods to compare types.
30
31
*/
@@ -2497,15 +2498,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2497
2498
NoType
2498
2499
}
2499
2500
2500
- private def andTypeGen (tp1 : Type , tp2 : Type , op : (Type , Type ) => Type ,
2501
- original : (Type , Type ) => Type = _ & _, isErased : Boolean = ctx.erasedTypes): Type = trace(s " andTypeGen( ${tp1.show}, ${tp2.show}) " , subtyping, show = true ) {
2502
- val t1 = distributeAnd(tp1, tp2)
2503
- if (t1.exists) t1
2504
- else {
2505
- val t2 = distributeAnd(tp2, tp1)
2506
- if (t2.exists) t2
2507
- else if (isErased) erasedGlb(tp1, tp2)
2508
- else liftIfHK(tp1, tp2, op, original, _ | _)
2501
+ private def andTypeGen (tp1orig : Type , tp2orig : Type , op : (Type , Type ) => Type ,
2502
+ original : (Type , Type ) => Type = _ & _, isErased : Boolean = ctx.erasedTypes): Type = trace(s " andTypeGen( ${tp1orig.show}, ${tp2orig.show}) " , subtyping, show = true ) {
2503
+ val tp1 = tp1orig.stripFlexible
2504
+ val tp2 = tp2orig.stripFlexible
2505
+ val ret = {
2506
+ val t1 = distributeAnd(tp1, tp2)
2507
+ if (t1.exists) t1
2508
+ else {
2509
+ val t2 = distributeAnd(tp2, tp1)
2510
+ if (t2.exists) t2
2511
+ else if (isErased) erasedGlb(tp1, tp2)
2512
+ else liftIfHK(tp1, tp2, op, original, _ | _)
2509
2513
// The ` | ` on variances is needed since variances are associated with bounds
2510
2514
// not lambdas. Example:
2511
2515
//
@@ -2515,7 +2519,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2515
2519
//
2516
2520
// Here, `F` is treated as bivariant in `O`. That is, only bivariant implementation
2517
2521
// of `F` are allowed. See neg/hk-variance2s.scala test.
2522
+ }
2518
2523
}
2524
+ if (tp1orig.isInstanceOf [FlexibleType ] && tp2orig.isInstanceOf [FlexibleType ]) FlexibleType (ret) else ret
2519
2525
}
2520
2526
2521
2527
/** Form a normalized conjunction of two types.
@@ -2588,73 +2594,53 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2588
2594
/** Try to distribute `&` inside type, detect and handle conflicts
2589
2595
* @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
2590
2596
*/
2591
- private def distributeAnd (tp1 : Type , tp2 : Type ): Type = {
2592
- var ft1 = false
2593
- var ft2 = false
2594
- def recur (tp1 : Type , tp2 : Type ): Type = tp1 match {
2595
- case tp1 @ FlexibleType (tp) =>
2596
- // Hack -- doesn't generalise to other intersection/union types
2597
- // but covers a common special case for pattern matching
2598
- ft1 = true
2599
- recur(tp, tp2)
2600
- case tp1 @ AppliedType (tycon1, args1) =>
2601
- tp2 match {
2602
- case AppliedType (tycon2, args2)
2603
- if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2604
- val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2605
- if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2606
- else {
2607
- NoType
2608
- }
2609
- case FlexibleType (tp) =>
2610
- // Hack from above
2611
- ft2 = true
2612
- recur(tp1, tp)
2613
- case _ =>
2614
- NoType
2615
- }
2616
-
2617
- // if result exists and is not notype, maybe wrap result in flex based on whether seen flex on both sides
2618
- case tp1 : RefinedType =>
2619
- // opportunistically merge same-named refinements
2620
- // this does not change anything semantically (i.e. merging or not merging
2621
- // gives =:= types), but it keeps the type smaller.
2622
- tp2 match {
2623
- case tp2 : RefinedType if tp1.refinedName == tp2.refinedName =>
2624
- val jointInfo = Denotations .infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false )
2625
- if jointInfo.exists then
2626
- tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2627
- else
2628
- NoType
2629
- case _ =>
2630
- NoType
2631
- }
2632
- case tp1 : RecType =>
2633
- tp1.rebind(recur(tp1.parent, tp2))
2634
- case ExprType (rt1) =>
2635
- tp2 match {
2636
- case ExprType (rt2) =>
2637
- ExprType (rt1 & rt2)
2638
- case _ =>
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
2639
2618
NoType
2640
- }
2641
- case tp1 : TypeVar if tp1.isInstantiated =>
2642
- tp1.underlying & tp2
2643
- case CapturingType (parent1, refs1) =>
2644
- if subCaptures(tp2.captureSet, refs1, frozen = true ).isOK
2645
- && tp1.isBoxedCapturing == tp2.isBoxedCapturing
2646
- then
2647
- parent1 & tp2
2648
- else
2649
- tp1.derivedCapturingType(parent1 & tp2, refs1)
2650
- case tp1 : AnnotatedType if ! tp1.isRefining =>
2651
- tp1.underlying & tp2
2652
- case _ =>
2653
- NoType
2654
- }
2655
- // if flex on both sides, return flex type
2656
- val ret = recur(tp1, tp2)
2657
- if (ft1 && ft2) then FlexibleType (ret) else ret
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
2658
2644
}
2659
2645
2660
2646
/** Try to distribute `|` inside type, detect and handle conflicts
0 commit comments