Skip to content

Commit 39657ec

Browse files
committed
Switch to structural variances for type lambdas
1 parent 91e167b commit 39657ec

File tree

3 files changed

+31
-34
lines changed

3 files changed

+31
-34
lines changed

compiler/src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,6 @@ class TypeApplications(val self: Type) extends AnyVal {
139139
/** The type parameters of this type are:
140140
* For a ClassInfo type, the type parameters of its class.
141141
* For a typeref referring to a class, the type parameters of the class.
142-
* For a typeref referring to a Lambda class, the type parameters of
143-
* its right hand side or upper bound.
144142
* For a refinement type, the type parameters of its parent, dropping
145143
* any type parameter that is-rebound by the refinement.
146144
*/

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Decorators._
1818
import Denotations._
1919
import Periods._
2020
import CheckRealizable._
21-
import Variances.{Variance, varianceFromInt, varianceToInt}
21+
import Variances.{Variance, varianceFromInt, varianceToInt, setStructuralVariances, Invariant}
2222
import util.Stats._
2323
import util.SimpleIdentitySet
2424
import reporting.diagnostic.Message
@@ -3409,12 +3409,8 @@ object Types {
34093409

34103410
def newParamRef(n: Int): TypeParamRef = new TypeParamRefImpl(this, n)
34113411

3412-
protected var myTypeParams: List[LambdaParam] = null
3413-
3414-
def typeParams: List[LambdaParam] =
3415-
if myTypeParams == null then
3416-
myTypeParams = paramNames.indices.toList.map(new LambdaParam(this, _))
3417-
myTypeParams
3412+
@threadUnsafe lazy val typeParams: List[LambdaParam] =
3413+
paramNames.indices.toList.map(new LambdaParam(this, _))
34183414

34193415
def derivedLambdaAbstraction(paramNames: List[TypeName], paramInfos: List[TypeBounds], resType: Type)(implicit ctx: Context): Type =
34203416
resType match {
@@ -3632,6 +3628,11 @@ object Types {
36323628
def paramRef(implicit ctx: Context): Type = tl.paramRefs(n)
36333629

36343630
private var myVariance: FlagSet = UndefinedFlags
3631+
def storedVariance_= (v: Variance): Unit =
3632+
myVariance = v
3633+
def storedVariance: Variance =
3634+
myVariance
3635+
36353636
def givenVariance_=(v: Variance): Unit =
36363637
assert(myVariance == UndefinedFlags)
36373638
myVariance = v
@@ -3641,7 +3642,11 @@ object Types {
36413642

36423643
def paramVariance(implicit ctx: Context): Variance =
36433644
if myVariance == UndefinedFlags then
3644-
myVariance = varianceFromInt(tl.paramNames(n).variance)
3645+
tl match
3646+
case tl: HKTypeLambda =>
3647+
setStructuralVariances(tl)
3648+
case _ =>
3649+
myVariance = Invariant
36453650
myVariance
36463651
}
36473652

compiler/src/dotty/tools/dotc/core/Variances.scala

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package core
33

44
import Types._, Contexts._, Flags._, Symbols._, Annotations._
55
import TypeApplications.TypeParamInfo
6+
import Decorators._
67

78
object Variances {
89

@@ -108,24 +109,19 @@ object Variances {
108109
Bivariant
109110
}
110111

111-
/** A map from the index of a lambda parameter to its variance in -1 .. 1 */
112-
type ParamVarianceMap = Map[Int, Int]
113-
114-
def lambdaVariances(lam: HKTypeLambda)(implicit ctx: Context): ParamVarianceMap =
115-
object accu extends TypeAccumulator[ParamVarianceMap] {
116-
def apply(vmap: ParamVarianceMap, t: Type): ParamVarianceMap = t match {
112+
def setStructuralVariances(lam: HKTypeLambda)(implicit ctx: Context): Unit =
113+
assert(!lam.isVariant)
114+
for param <- lam.typeParams do param.storedVariance = Bivariant
115+
object traverse extends TypeAccumulator[Unit] {
116+
def apply(x: Unit, t: Type): Unit = t match
117117
case t: TypeParamRef if t.binder eq lam =>
118-
val idx = t.paramNum
119-
vmap.get(idx) match
120-
case None =>
121-
vmap.updated(idx, variance)
122-
case Some(v) =>
123-
if v == variance || v == 0 then vmap else vmap.updated(idx, 0)
118+
lam.typeParams(t.paramNum).storedVariance &= varianceFromInt(variance)
119+
case _: LazyRef =>
120+
x
124121
case _ =>
125-
foldOver(vmap, t)
126-
}
122+
foldOver(x, t)
127123
}
128-
accu(Map(), lam.resType)
124+
traverse((), lam.resType)
129125

130126
/** Does variance `v1` conform to variance `v2`?
131127
* This is the case if the variances are the same or `sym` is nonvariant.
@@ -136,21 +132,19 @@ object Variances {
136132
/** Does the variance of type parameter `tparam1` conform to the variance of type parameter `tparam2`?
137133
*/
138134
def varianceConforms(tparam1: TypeParamInfo, tparam2: TypeParamInfo)(implicit ctx: Context): Boolean =
139-
varianceConforms(tparam1.paramVarianceSign, tparam2.paramVarianceSign)
135+
tparam1.paramVariance.isAllOf(tparam2.paramVariance)
140136

141137
/** Do the variances of type parameters `tparams1` conform to the variances
142138
* of corresponding type parameters `tparams2`?
143139
* This is only the case of `tparams1` and `tparams2` have the same length.
144140
*/
145141
def variancesConform(tparams1: List[TypeParamInfo], tparams2: List[TypeParamInfo])(implicit ctx: Context): Boolean =
146-
tparams1.corresponds(tparams2)(varianceConforms)
147-
148-
def variancesConform(vs1: List[Variance], vs2: List[Variance]): Boolean = vs2 match
149-
case v2 :: rest2 =>
150-
vs1 match
151-
case v1 :: rest1 => v1.isAllOf(v2) && variancesConform(rest1, rest2)
152-
case nil => v2.isEmpty && variancesConform(vs1, rest2)
153-
case nil => true
142+
val needsDetailedCheck = tparams2 match
143+
case (_: Symbol) :: _ => true
144+
case LambdaParam(tl: HKTypeLambda, _) :: _ => tl.isVariant
145+
case _ => false
146+
if needsDetailedCheck then tparams1.corresponds(tparams2)(varianceConforms)
147+
else tparams1.hasSameLengthAs(tparams2)
154148

155149
def varianceString(sym: Symbol)(implicit ctx: Context): String =
156150
varianceString(sym.variance)

0 commit comments

Comments
 (0)