@@ -3679,14 +3679,26 @@ object Types {
3679
3679
3680
3680
// ----- TypeMaps --------------------------------------------------------------------
3681
3681
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 =>
3683
3697
3684
3698
protected def stopAtStatic = true
3685
3699
3686
3700
def apply (tp : Type ): Type
3687
3701
3688
- protected [core] var variance = 1
3689
-
3690
3702
protected def derivedSelect (tp : NamedType , pre : Type ): Type =
3691
3703
tp.derivedSelect(pre)
3692
3704
protected def derivedRefinedType (tp : RefinedType , parent : Type , info : Type ): Type =
@@ -3724,16 +3736,13 @@ object Types {
3724
3736
case tp : NamedType =>
3725
3737
if (stopAtStatic && tp.symbol.isStatic) tp
3726
3738
else {
3727
- val saved = variance
3728
- variance = variance max 0
3739
+ val prefix1 = atVariance(variance max 0 )(this (tp.prefix))
3729
3740
// A prefix is never contravariant. Even if say `p.A` is used in a contravariant
3730
3741
// context, we cannot assume contravariance for `p` because `p`'s lower
3731
3742
// bound might not have a binding for `A` (e.g. the lower bound could be `Nothing`).
3732
3743
// By contrast, covariance does translate to the prefix, since we have that
3733
3744
// if `p <: q` then `p.A <: q.A`, and well-formedness requires that `A` is a member
3734
3745
// of `p`'s upper bound.
3735
- val prefix1 = this (tp.prefix)
3736
- variance = saved
3737
3746
derivedSelect(tp, prefix1)
3738
3747
}
3739
3748
case _ : ThisType
@@ -3744,11 +3753,7 @@ object Types {
3744
3753
derivedRefinedType(tp, this (tp.parent), this (tp.refinedInfo))
3745
3754
3746
3755
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)))
3752
3757
3753
3758
case tp : TypeBounds =>
3754
3759
variance = - variance
@@ -3764,12 +3769,8 @@ object Types {
3764
3769
if (inst.exists) apply(inst) else tp
3765
3770
3766
3771
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))
3773
3774
derivedAppliedType(tp, this (tp.tycon),
3774
3775
tp.args.zipWithConserve(tp.typeParams)(mapArg))
3775
3776
@@ -3894,20 +3895,14 @@ object Types {
3894
3895
case _ => tp
3895
3896
}
3896
3897
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.
3905
3901
*/
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 {
3911
3906
case TypeAlias (alias) =>
3912
3907
// if H#T = U, then for any x in L..H, x.T =:= U,
3913
3908
// hence we can replace with U under all variances
@@ -3921,9 +3916,21 @@ object Types {
3921
3916
// hence we can replace with y.type under all variances
3922
3917
reapply(info)
3923
3918
case _ =>
3924
- range(tp.derivedSelect(preLo), tp.derivedSelect(preHi))
3919
+ default
3925
3920
}
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)
3927
3934
}
3928
3935
3929
3936
override protected def derivedRefinedType (tp : RefinedType , parent : Type , info : Type ) =
@@ -3932,20 +3939,30 @@ object Types {
3932
3939
case Range (parentLo, parentHi) =>
3933
3940
range(derivedRefinedType(tp, parentLo, info), derivedRefinedType(tp, parentHi, info))
3934
3941
case _ =>
3942
+ def propagate (lo : Type , hi : Type ) =
3943
+ range(derivedRefinedType(tp, parent, lo), derivedRefinedType(tp, parent, hi))
3935
3944
if (parent.isBottomType) parent
3936
3945
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.
3937
3964
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)
3949
3966
case _ =>
3950
3967
tp.derivedRefinedType(parent, tp.refinedName, info)
3951
3968
}
@@ -3987,6 +4004,13 @@ object Types {
3987
4004
if (variance > 0 ) tp.derivedAppliedType(tycon, args.map(rangeToBounds))
3988
4005
else {
3989
4006
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.
3990
4014
def distributeArgs (args : List [Type ], tparams : List [ParamInfo ]): Boolean = args match {
3991
4015
case Range (lo, hi) :: args1 =>
3992
4016
val v = tparams.head.paramVariance
@@ -4006,13 +4030,14 @@ object Types {
4006
4030
range(tp.derivedAppliedType(tycon, loBuf.toList),
4007
4031
tp.derivedAppliedType(tycon, hiBuf.toList))
4008
4032
else range(tp.bottomType, tp.topType)
4033
+ // TODO: can we give a better bound than `topType`?
4009
4034
}
4010
4035
}
4011
4036
else tp.derivedAppliedType(tycon, args)
4012
4037
}
4013
4038
4014
4039
override protected def derivedAndOrType (tp : AndOrType , tp1 : Type , tp2 : Type ) =
4015
- if (tp1. isInstanceOf [ Range ] || tp2. isInstanceOf [ Range ] )
4040
+ if (isRange( tp1) || isRange( tp2) )
4016
4041
if (tp.isAnd) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2))
4017
4042
else range(lower(tp1) | lower(tp2), upper(tp1) | upper(tp2))
4018
4043
else tp.derivedAndOrType(tp1, tp2)
@@ -4030,7 +4055,9 @@ object Types {
4030
4055
}
4031
4056
4032
4057
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).
4034
4061
tp.derivedClassInfo(pre)
4035
4062
}
4036
4063
@@ -4058,23 +4085,17 @@ object Types {
4058
4085
4059
4086
// ----- TypeAccumulators ----------------------------------------------------
4060
4087
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 ) {
4062
4090
4063
4091
protected def stopAtStatic = true
4064
4092
4065
4093
def apply (x : T , tp : Type ): T
4066
4094
4067
4095
protected def applyToAnnot (x : T , annot : Annotation ): T = x // don't go into annotations
4068
4096
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
4078
4099
4079
4100
def foldOver (x : T , tp : Type ): T = tp match {
4080
4101
case tp : TypeRef =>
@@ -4095,13 +4116,7 @@ object Types {
4095
4116
this (this (x, tp.parent), tp.refinedInfo)
4096
4117
4097
4118
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))
4105
4120
else {
4106
4121
variance = - variance
4107
4122
val y = this (x, lo)
0 commit comments