@@ -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
*/
@@ -2481,15 +2482,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2481
2482
NoType
2482
2483
}
2483
2484
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, _ | _)
2493
2497
// The ` | ` on variances is needed since variances are associated with bounds
2494
2498
// not lambdas. Example:
2495
2499
//
@@ -2499,7 +2503,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2499
2503
//
2500
2504
// Here, `F` is treated as bivariant in `O`. That is, only bivariant implementation
2501
2505
// of `F` are allowed. See neg/hk-variance2s.scala test.
2506
+ }
2502
2507
}
2508
+ if (tp1orig.isInstanceOf [FlexibleType ] && tp2orig.isInstanceOf [FlexibleType ]) FlexibleType (ret) else ret
2503
2509
}
2504
2510
2505
2511
/** Form a normalized conjunction of two types.
@@ -2571,73 +2577,53 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2571
2577
/** Try to distribute `&` inside type, detect and handle conflicts
2572
2578
* @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
2573
2579
*/
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
2622
2601
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
2641
2627
}
2642
2628
2643
2629
/** Try to distribute `|` inside type, detect and handle conflicts
0 commit comments