@@ -3679,14 +3679,26 @@ object Types {
36793679
36803680 // ----- TypeMaps --------------------------------------------------------------------
36813681
3682- abstract class TypeMap (implicit protected val ctx : Context ) extends (Type => Type ) { thisMap =>
3682+ /** Common base class of TypeMap and TypeAccumulator */
3683+ abstract class VariantTraversal {
3684+ protected [core] var variance = 1
3685+
3686+ @ inline protected def atVariance [T ](v : Int )(op : => T ): T = {
3687+ val saved = variance
3688+ variance = v
3689+ val res = op
3690+ variance = saved
3691+ res
3692+ }
3693+ }
3694+
3695+ abstract class TypeMap (implicit protected val ctx : Context )
3696+ extends VariantTraversal with (Type => Type ) { thisMap =>
36833697
36843698 protected def stopAtStatic = true
36853699
36863700 def apply (tp : Type ): Type
36873701
3688- protected [core] var variance = 1
3689-
36903702 protected def derivedSelect (tp : NamedType , pre : Type ): Type =
36913703 tp.derivedSelect(pre)
36923704 protected def derivedRefinedType (tp : RefinedType , parent : Type , info : Type ): Type =
@@ -3724,16 +3736,13 @@ object Types {
37243736 case tp : NamedType =>
37253737 if (stopAtStatic && tp.symbol.isStatic) tp
37263738 else {
3727- val saved = variance
3728- variance = variance max 0
3739+ val prefix1 = atVariance(variance max 0 )(this (tp.prefix))
37293740 // A prefix is never contravariant. Even if say `p.A` is used in a contravariant
37303741 // context, we cannot assume contravariance for `p` because `p`'s lower
37313742 // bound might not have a binding for `A` (e.g. the lower bound could be `Nothing`).
37323743 // By contrast, covariance does translate to the prefix, since we have that
37333744 // if `p <: q` then `p.A <: q.A`, and well-formedness requires that `A` is a member
37343745 // of `p`'s upper bound.
3735- val prefix1 = this (tp.prefix)
3736- variance = saved
37373746 derivedSelect(tp, prefix1)
37383747 }
37393748 case _ : ThisType
@@ -3744,11 +3753,7 @@ object Types {
37443753 derivedRefinedType(tp, this (tp.parent), this (tp.refinedInfo))
37453754
37463755 case tp : TypeAlias =>
3747- val saved = variance
3748- variance *= tp.variance
3749- val alias1 = this (tp.alias)
3750- variance = saved
3751- derivedTypeAlias(tp, alias1)
3756+ derivedTypeAlias(tp, atVariance(variance * tp.variance)(this (tp.alias)))
37523757
37533758 case tp : TypeBounds =>
37543759 variance = - variance
@@ -3764,12 +3769,8 @@ object Types {
37643769 if (inst.exists) apply(inst) else tp
37653770
37663771 case tp : HKApply =>
3767- def mapArg (arg : Type , tparam : ParamInfo ): Type = {
3768- val saved = variance
3769- variance *= tparam.paramVariance
3770- try this (arg)
3771- finally variance = saved
3772- }
3772+ def mapArg (arg : Type , tparam : ParamInfo ): Type =
3773+ atVariance(variance * tparam.paramVariance)(this (arg))
37733774 derivedAppliedType(tp, this (tp.tycon),
37743775 tp.args.zipWithConserve(tp.typeParams)(mapArg))
37753776
@@ -3894,20 +3895,14 @@ object Types {
38943895 case _ => tp
38953896 }
38963897
3897- protected def atVariance [T ](v : Int )(op : => T ): T = {
3898- val saved = variance
3899- variance = v
3900- try op finally variance = saved
3901- }
3902-
3903- /** Derived selection.
3904- * @pre the (upper bound of) prefix `pre` has a member named `tp.name`.
3898+ /** Try to widen a named type to its info relative to given prefix `pre`, where possible.
3899+ * The possible cases are listed inline in the code. Return `default` if no widening is
3900+ * possible.
39053901 */
3906- override protected def derivedSelect (tp : NamedType , pre : Type ) =
3907- if (pre eq tp.prefix) tp
3908- else pre match {
3909- case Range (preLo, preHi) =>
3910- preHi.member(tp.name).info.widenExpr match {
3902+ def tryWiden (tp : NamedType , pre : Type )(default : => Type ): Type =
3903+ pre.member(tp.name) match {
3904+ case d : SingleDenotation =>
3905+ d.info match {
39113906 case TypeAlias (alias) =>
39123907 // if H#T = U, then for any x in L..H, x.T =:= U,
39133908 // hence we can replace with U under all variances
@@ -3921,9 +3916,21 @@ object Types {
39213916 // hence we can replace with y.type under all variances
39223917 reapply(info)
39233918 case _ =>
3924- range(tp.derivedSelect(preLo), tp.derivedSelect(preHi))
3919+ default
39253920 }
3926- case _ => tp.derivedSelect(pre)
3921+ case _ => default
3922+ }
3923+
3924+ /** Derived selection.
3925+ * @pre the (upper bound of) prefix `pre` has a member named `tp.name`.
3926+ */
3927+ override protected def derivedSelect (tp : NamedType , pre : Type ) =
3928+ if (pre eq tp.prefix) tp
3929+ else pre match {
3930+ case Range (preLo, preHi) =>
3931+ tryWiden(tp, preHi)(range(tp.derivedSelect(preLo), tp.derivedSelect(preHi)))
3932+ case _ =>
3933+ tp.derivedSelect(pre)
39273934 }
39283935
39293936 override protected def derivedRefinedType (tp : RefinedType , parent : Type , info : Type ) =
@@ -3932,20 +3939,30 @@ object Types {
39323939 case Range (parentLo, parentHi) =>
39333940 range(derivedRefinedType(tp, parentLo, info), derivedRefinedType(tp, parentHi, info))
39343941 case _ =>
3942+ def propagate (lo : Type , hi : Type ) =
3943+ range(derivedRefinedType(tp, parent, lo), derivedRefinedType(tp, parent, hi))
39353944 if (parent.isBottomType) parent
39363945 else info match {
3946+ case Range (infoLo : TypeBounds , infoHi : TypeBounds ) =>
3947+ assert(variance == 0 )
3948+ val v1 = infoLo.variance
3949+ val v2 = infoHi.variance
3950+ // There's some weirdness coming from the way aliases can have variance
3951+ // If infoLo and infoHi are both aliases with the same non-zero variance
3952+ // we can propagate to a range of the refined types. If they are both
3953+ // non-alias ranges we know that infoLo <:< infoHi and therefore we can
3954+ // propagate to refined types with infoLo and infoHi as bounds.
3955+ // In all other cases, Nothing..Any is the only interval that contains
3956+ // the range. i966.scala is a test case.
3957+ if (v1 > 0 && v2 > 0 ) propagate(infoLo, infoHi)
3958+ else if (v1 < 0 && v2 < 0 ) propagate(infoHi, infoLo)
3959+ else if (! infoLo.isAlias && ! infoHi.isAlias) propagate(infoLo, infoHi)
3960+ else range(tp.bottomType, tp.topType)
3961+ // Using `parent` instead of `tp.topType` would be better for normal refinements,
3962+ // but it would also turn *-types into hk-types, which is not what we want.
3963+ // We should revisit this point in case we represent applied types not as refinements anymore.
39373964 case Range (infoLo, infoHi) =>
3938- def propagate (lo : Type , hi : Type ) =
3939- range(derivedRefinedType(tp, parent, lo), derivedRefinedType(tp, parent, hi))
3940- tp.refinedInfo match {
3941- case rinfo : TypeBounds =>
3942- val v = if (rinfo.isAlias) rinfo.variance * variance else variance
3943- if (v > 0 ) tp.derivedRefinedType(parent, tp.refinedName, rangeToBounds(info))
3944- else if (v < 0 ) propagate(infoHi, infoLo)
3945- else range(tp.bottomType, tp.topType)
3946- case _ =>
3947- propagate(infoLo, infoHi)
3948- }
3965+ propagate(infoLo, infoHi)
39493966 case _ =>
39503967 tp.derivedRefinedType(parent, tp.refinedName, info)
39513968 }
@@ -3987,6 +4004,13 @@ object Types {
39874004 if (variance > 0 ) tp.derivedAppliedType(tycon, args.map(rangeToBounds))
39884005 else {
39894006 val loBuf, hiBuf = new mutable.ListBuffer [Type ]
4007+ // Given `C[A1, ..., An]` where sone A's are ranges, try to find
4008+ // non-range arguments L1, ..., Ln and H1, ..., Hn such that
4009+ // C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of
4010+ // ranges that appear in as co- or contravariant arguments.
4011+ // Fail for non-variant argument ranges.
4012+ // If successful, the L-arguments are in loBut, the H-arguments in hiBuf.
4013+ // @return operation succeeded for all arguments.
39904014 def distributeArgs (args : List [Type ], tparams : List [ParamInfo ]): Boolean = args match {
39914015 case Range (lo, hi) :: args1 =>
39924016 val v = tparams.head.paramVariance
@@ -4006,13 +4030,14 @@ object Types {
40064030 range(tp.derivedAppliedType(tycon, loBuf.toList),
40074031 tp.derivedAppliedType(tycon, hiBuf.toList))
40084032 else range(tp.bottomType, tp.topType)
4033+ // TODO: can we give a better bound than `topType`?
40094034 }
40104035 }
40114036 else tp.derivedAppliedType(tycon, args)
40124037 }
40134038
40144039 override protected def derivedAndOrType (tp : AndOrType , tp1 : Type , tp2 : Type ) =
4015- if (tp1. isInstanceOf [ Range ] || tp2. isInstanceOf [ Range ] )
4040+ if (isRange( tp1) || isRange( tp2) )
40164041 if (tp.isAnd) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2))
40174042 else range(lower(tp1) | lower(tp2), upper(tp1) | upper(tp2))
40184043 else tp.derivedAndOrType(tp1, tp2)
@@ -4030,7 +4055,9 @@ object Types {
40304055 }
40314056
40324057 override protected def derivedClassInfo (tp : ClassInfo , pre : Type ): Type = {
4033- assert(! pre.isInstanceOf [Range ])
4058+ assert(! isRange(pre))
4059+ // we don't know what to do here; this case has to be handled in subclasses
4060+ // (typically by handling ClassInfo's specially, in case they can be encountered).
40344061 tp.derivedClassInfo(pre)
40354062 }
40364063
@@ -4058,23 +4085,17 @@ object Types {
40584085
40594086 // ----- TypeAccumulators ----------------------------------------------------
40604087
4061- abstract class TypeAccumulator [T ](implicit protected val ctx : Context ) extends ((T , Type ) => T ) {
4088+ abstract class TypeAccumulator [T ](implicit protected val ctx : Context )
4089+ extends VariantTraversal with ((T , Type ) => T ) {
40624090
40634091 protected def stopAtStatic = true
40644092
40654093 def apply (x : T , tp : Type ): T
40664094
40674095 protected def applyToAnnot (x : T , annot : Annotation ): T = x // don't go into annotations
40684096
4069- protected var variance = 1
4070-
4071- protected final def applyToPrefix (x : T , tp : NamedType ) = {
4072- val saved = variance
4073- variance = variance max 0 // see remark on NamedType case in TypeMap
4074- val result = this (x, tp.prefix)
4075- variance = saved
4076- result
4077- }
4097+ protected final def applyToPrefix (x : T , tp : NamedType ) =
4098+ atVariance(variance max 0 )(this (x, tp.prefix)) // see remark on NamedType case in TypeMap
40784099
40794100 def foldOver (x : T , tp : Type ): T = tp match {
40804101 case tp : TypeRef =>
@@ -4095,13 +4116,7 @@ object Types {
40954116 this (this (x, tp.parent), tp.refinedInfo)
40964117
40974118 case bounds @ TypeBounds (lo, hi) =>
4098- if (lo eq hi) {
4099- val saved = variance
4100- variance = variance * bounds.variance
4101- val result = this (x, lo)
4102- variance = saved
4103- result
4104- }
4119+ if (lo eq hi) atVariance(variance * bounds.variance)(this (x, lo))
41054120 else {
41064121 variance = - variance
41074122 val y = this (x, lo)
0 commit comments