@@ -25,6 +25,7 @@ import reporting.trace
2525import annotation .constructorOnly
2626import cc .{CapturingType , derivedCapturingType , CaptureSet , stripCapturing , isBoxedCapturing , boxed , boxedUnlessFun , boxedIfTypeParam , isAlwaysPure }
2727import NameKinds .WildcardParamName
28+ import NullOpsDecorator .stripFlexible
2829
2930/** Provides methods to compare types.
3031 */
@@ -2462,15 +2463,18 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24622463 NoType
24632464 }
24642465
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, _ | _)
24742478 // The ` | ` on variances is needed since variances are associated with bounds
24752479 // not lambdas. Example:
24762480 //
@@ -2480,7 +2484,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24802484 //
24812485 // Here, `F` is treated as bivariant in `O`. That is, only bivariant implementation
24822486 // of `F` are allowed. See neg/hk-variance2s.scala test.
2487+ }
24832488 }
2489+ if (tp1orig.isInstanceOf [FlexibleType ] && tp2orig.isInstanceOf [FlexibleType ]) FlexibleType (ret) else ret
24842490 }
24852491
24862492 /** Form a normalized conjunction of two types.
@@ -2552,73 +2558,53 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
25522558 /** Try to distribute `&` inside type, detect and handle conflicts
25532559 * @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before
25542560 */
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
26032582 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
26222608 }
26232609
26242610 /** Try to distribute `|` inside type, detect and handle conflicts
0 commit comments