@@ -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
*/
@@ -2462,15 +2463,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2462
2463
NoType
2463
2464
}
2464
2465
2465
- private def andTypeGen (tp1 : Type , tp2 : Type , op : (Type , Type ) => Type ,
2466
- original : (Type , Type ) => Type = _ & _, isErased : Boolean = ctx.erasedTypes): Type = trace(s " andTypeGen( ${tp1.show}, ${tp2.show}) " , subtyping, show = true ) {
2467
- val t1 = distributeAnd(tp1, tp2)
2468
- if (t1.exists) t1
2469
- else {
2470
- val t2 = distributeAnd(tp2, tp1)
2471
- if (t2.exists) t2
2472
- else if (isErased) erasedGlb(tp1, tp2)
2473
- else liftIfHK(tp1, tp2, op, original, _ | _)
2466
+ private def andTypeGen (tp1orig : Type , tp2orig : Type , op : (Type , Type ) => Type ,
2467
+ original : (Type , Type ) => Type = _ & _, isErased : Boolean = ctx.erasedTypes): Type = trace(s " andTypeGen( ${tp1orig.show}, ${tp2orig.show}) " , subtyping, show = true ) {
2468
+ val tp1 = tp1orig.stripFlexible
2469
+ val tp2 = tp2orig.stripFlexible
2470
+ val ret = {
2471
+ val t1 = distributeAnd(tp1, tp2)
2472
+ if (t1.exists) t1
2473
+ else {
2474
+ val t2 = distributeAnd(tp2, tp1)
2475
+ if (t2.exists) t2
2476
+ else if (isErased) erasedGlb(tp1, tp2)
2477
+ else liftIfHK(tp1, tp2, op, original, _ | _)
2474
2478
// The ` | ` on variances is needed since variances are associated with bounds
2475
2479
// not lambdas. Example:
2476
2480
//
@@ -2480,7 +2484,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2480
2484
//
2481
2485
// Here, `F` is treated as bivariant in `O`. That is, only bivariant implementation
2482
2486
// of `F` are allowed. See neg/hk-variance2s.scala test.
2487
+ }
2483
2488
}
2489
+ if (tp1orig.isInstanceOf [FlexibleType ] && tp2orig.isInstanceOf [FlexibleType ]) FlexibleType (ret) else ret
2484
2490
}
2485
2491
2486
2492
/** Form a normalized conjunction of two types.
@@ -2552,73 +2558,53 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2552
2558
/** Try to distribute `&` inside type, detect and handle conflicts
2553
2559
* @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
2554
2560
*/
2555
- private def distributeAnd (tp1 : Type , tp2 : Type ): Type = {
2556
- var ft1 = false
2557
- var ft2 = false
2558
- def recur (tp1 : Type , tp2 : Type ): Type = tp1 match {
2559
- case tp1 @ FlexibleType (tp) =>
2560
- // Hack -- doesn't generalise to other intersection/union types
2561
- // but covers a common special case for pattern matching
2562
- ft1 = true
2563
- recur(tp, tp2)
2564
- case tp1 @ AppliedType (tycon1, args1) =>
2565
- tp2 match {
2566
- case AppliedType (tycon2, args2)
2567
- if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2568
- val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2569
- if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2570
- else {
2571
- NoType
2572
- }
2573
- case FlexibleType (tp) =>
2574
- // Hack from above
2575
- ft2 = true
2576
- recur(tp1, tp)
2577
- case _ =>
2578
- NoType
2579
- }
2580
-
2581
- // if result exists and is not notype, maybe wrap result in flex based on whether seen flex on both sides
2582
- case tp1 : RefinedType =>
2583
- // opportunistically merge same-named refinements
2584
- // this does not change anything semantically (i.e. merging or not merging
2585
- // gives =:= types), but it keeps the type smaller.
2586
- tp2 match {
2587
- case tp2 : RefinedType if tp1.refinedName == tp2.refinedName =>
2588
- val jointInfo = Denotations .infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false )
2589
- if jointInfo.exists then
2590
- tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2591
- else
2592
- NoType
2593
- case _ =>
2594
- NoType
2595
- }
2596
- case tp1 : RecType =>
2597
- tp1.rebind(recur(tp1.parent, tp2))
2598
- case ExprType (rt1) =>
2599
- tp2 match {
2600
- case ExprType (rt2) =>
2601
- ExprType (rt1 & rt2)
2602
- case _ =>
2561
+ private def distributeAnd (tp1 : Type , tp2 : Type ): Type = tp1 match {
2562
+ case tp1 @ AppliedType (tycon1, args1) =>
2563
+ tp2 match {
2564
+ case AppliedType (tycon2, args2)
2565
+ if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
2566
+ val jointArgs = glbArgs(args1, args2, tycon1.typeParams)
2567
+ if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs)
2568
+ else NoType
2569
+ case _ =>
2570
+ NoType
2571
+ }
2572
+ case tp1 : RefinedType =>
2573
+ // opportunistically merge same-named refinements
2574
+ // this does not change anything semantically (i.e. merging or not merging
2575
+ // gives =:= types), but it keeps the type smaller.
2576
+ tp2 match {
2577
+ case tp2 : RefinedType if tp1.refinedName == tp2.refinedName =>
2578
+ val jointInfo = Denotations .infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false )
2579
+ if jointInfo.exists then
2580
+ tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2581
+ else
2603
2582
NoType
2604
- }
2605
- case tp1 : TypeVar if tp1.isInstantiated =>
2606
- tp1.underlying & tp2
2607
- case CapturingType (parent1, refs1) =>
2608
- if subCaptures(tp2.captureSet, refs1, frozen = true ).isOK
2609
- && tp1.isBoxedCapturing == tp2.isBoxedCapturing
2610
- then
2611
- parent1 & tp2
2612
- else
2613
- tp1.derivedCapturingType(parent1 & tp2, refs1)
2614
- case tp1 : AnnotatedType if ! tp1.isRefining =>
2615
- tp1.underlying & tp2
2616
- case _ =>
2617
- NoType
2618
- }
2619
- // if flex on both sides, return flex type
2620
- val ret = recur(tp1, tp2)
2621
- if (ft1 && ft2) then FlexibleType (ret) else ret
2583
+ case _ =>
2584
+ NoType
2585
+ }
2586
+ case tp1 : RecType =>
2587
+ tp1.rebind(distributeAnd(tp1.parent, tp2))
2588
+ case ExprType (rt1) =>
2589
+ tp2 match {
2590
+ case ExprType (rt2) =>
2591
+ ExprType (rt1 & rt2)
2592
+ case _ =>
2593
+ NoType
2594
+ }
2595
+ case tp1 : TypeVar if tp1.isInstantiated =>
2596
+ tp1.underlying & tp2
2597
+ case CapturingType (parent1, refs1) =>
2598
+ if subCaptures(tp2.captureSet, refs1, frozen = true ).isOK
2599
+ && tp1.isBoxedCapturing == tp2.isBoxedCapturing
2600
+ then
2601
+ parent1 & tp2
2602
+ else
2603
+ tp1.derivedCapturingType(parent1 & tp2, refs1)
2604
+ case tp1 : AnnotatedType if ! tp1.isRefining =>
2605
+ tp1.underlying & tp2
2606
+ case _ =>
2607
+ NoType
2622
2608
}
2623
2609
2624
2610
/** Try to distribute `|` inside type, detect and handle conflicts
0 commit comments