Skip to content

Commit c088cf0

Browse files
committed
Add ApproximatingTypeMap class
Also: In a TypeMap, the variance of the prefix is unchanged (was: always 0). This brings it in line with TypeAccumulator and the subtyping rules.
1 parent 6a1d6de commit c088cf0

File tree

1 file changed

+94
-22
lines changed

1 file changed

+94
-22
lines changed

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

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3072,64 +3072,86 @@ object Types {
30723072

30733073
protected var variance = 1
30743074

3075+
protected def derivedSelect(tp: NamedType, pre: Type): Type =
3076+
tp.derivedSelect(pre)
3077+
protected def derivedRefinedType(tp: RefinedType, parent: Type, info: Type): Type =
3078+
tp.derivedRefinedType(parent, tp.refinedName, info)
3079+
protected def derivedTypeAlias(tp: TypeAlias, alias: Type): Type =
3080+
tp.derivedTypeAlias(alias)
3081+
protected def derivedTypeBounds(tp: TypeBounds, lo: Type, hi: Type): Type =
3082+
tp.derivedTypeBounds(lo, hi)
3083+
protected def derivedSuperType(tp: SuperType, thistp: Type, supertp: Type): Type =
3084+
tp.derivedSuperType(thistp, supertp)
3085+
protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type): Type =
3086+
tp.derivedAndOrType(tp1, tp2)
3087+
protected def derivedSkolemType(tp: SkolemType, info: Type): Type =
3088+
tp.derivedSkolemType(info)
3089+
protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation): Type =
3090+
tp.derivedAnnotatedType(underlying, annot)
3091+
protected def derivedWildcardType(tp: WildcardType, bounds: Type): Type =
3092+
tp.derivedWildcardType(bounds)
3093+
protected def derivedClassInfo(tp: ClassInfo, pre: Type): Type =
3094+
tp.derivedClassInfo(pre)
3095+
protected def derivedJavaArrayType(tp: JavaArrayType, elemtp: Type): Type =
3096+
tp.derivedJavaArrayType(elemtp)
3097+
protected def derivedMethodType(tp: MethodType, formals: List[Type], restpe: Type): Type =
3098+
tp.derivedMethodType(tp.paramNames, formals, restpe)
3099+
protected def derivedExprType(tp: ExprType, restpe: Type): Type =
3100+
tp.derivedExprType(restpe)
3101+
protected def derivedPolyType(tp: PolyType, pbounds: List[TypeBounds], restpe: Type): Type =
3102+
tp.derivedPolyType(tp.paramNames, pbounds, restpe)
3103+
30753104
/** Map this function over given type */
30763105
def mapOver(tp: Type): Type = {
30773106
implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
30783107
tp match {
30793108
case tp: NamedType =>
30803109
if (stopAtStatic && tp.symbol.isStatic) tp
3081-
else {
3082-
val saved = variance
3083-
variance = 0
3084-
val result = tp.derivedSelect(this(tp.prefix))
3085-
variance = saved
3086-
result
3087-
}
3110+
else derivedSelect(tp, this(tp.prefix))
30883111

30893112
case _: ThisType
30903113
| _: BoundType
30913114
| NoPrefix => tp
30923115

30933116
case tp: RefinedType =>
3094-
tp.derivedRefinedType(this(tp.parent), tp.refinedName, this(tp.refinedInfo))
3117+
derivedRefinedType(tp, this(tp.parent), this(tp.refinedInfo))
30953118

30963119
case tp: TypeAlias =>
30973120
val saved = variance
30983121
variance = variance * tp.variance
30993122
val alias1 = this(tp.alias)
31003123
variance = saved
3101-
tp.derivedTypeAlias(alias1)
3124+
derivedTypeAlias(tp, alias1)
31023125

31033126
case tp: TypeBounds =>
31043127
variance = -variance
31053128
val lo1 = this(tp.lo)
31063129
variance = -variance
3107-
tp.derivedTypeBounds(lo1, this(tp.hi))
3130+
derivedTypeBounds(tp, lo1, this(tp.hi))
31083131

31093132
case tp: MethodType =>
31103133
def mapOverMethod = {
31113134
variance = -variance
31123135
val ptypes1 = tp.paramTypes mapConserve this
31133136
variance = -variance
3114-
tp.derivedMethodType(tp.paramNames, ptypes1, this(tp.resultType))
3137+
derivedMethodType(tp, ptypes1, this(tp.resultType))
31153138
}
31163139
mapOverMethod
31173140

31183141
case tp: ExprType =>
3119-
tp.derivedExprType(this(tp.resultType))
3142+
derivedExprType(tp, this(tp.resultType))
31203143

31213144
case tp: PolyType =>
31223145
def mapOverPoly = {
31233146
variance = -variance
31243147
val bounds1 = tp.paramBounds.mapConserve(this).asInstanceOf[List[TypeBounds]]
31253148
variance = -variance
3126-
tp.derivedPolyType(
3127-
tp.paramNames, bounds1, this(tp.resultType))
3149+
derivedPolyType(tp, bounds1, this(tp.resultType))
31283150
}
31293151
mapOverPoly
31303152

31313153
case tp @ SuperType(thistp, supertp) =>
3132-
tp.derivedSuperType(this(thistp), this(supertp))
3154+
derivedSuperType(tp, this(thistp), this(supertp))
31333155

31343156
case tp: LazyRef =>
31353157
LazyRef(() => this(tp.ref))
@@ -3142,20 +3164,21 @@ object Types {
31423164
if (inst.exists) apply(inst) else tp
31433165

31443166
case tp: AndOrType =>
3145-
tp.derivedAndOrType(this(tp.tp1), this(tp.tp2))
3167+
derivedAndOrType(tp, this(tp.tp1), this(tp.tp2))
31463168

31473169
case tp: SkolemType =>
3148-
tp.derivedSkolemType(this(tp.info))
3170+
derivedSkolemType(tp, this(tp.info))
31493171

31503172
case tp @ AnnotatedType(underlying, annot) =>
31513173
val underlying1 = this(underlying)
3152-
if (underlying1 eq underlying) tp else tp.derivedAnnotatedType(underlying1, mapOver(annot))
3174+
if (underlying1 eq underlying) tp
3175+
else derivedAnnotatedType(tp, underlying1, mapOver(annot))
31533176

31543177
case tp @ WildcardType =>
3155-
tp.derivedWildcardType(mapOver(tp.optBounds))
3178+
derivedWildcardType(tp, mapOver(tp.optBounds))
31563179

31573180
case tp: JavaArrayType =>
3158-
tp.derivedJavaArrayType(this(tp.elemType))
3181+
derivedJavaArrayType(tp, this(tp.elemType))
31593182

31603183
case tp: ProtoType =>
31613184
tp.map(this)
@@ -3182,8 +3205,8 @@ object Types {
31823205
def mapOver(tree: Tree): Tree = treeTypeMap(tree)
31833206

31843207
/** Can be overridden. By default, only the prefix is mapped. */
3185-
protected def mapClassInfo(tp: ClassInfo): ClassInfo =
3186-
tp.derivedClassInfo(this(tp.prefix))
3208+
protected def mapClassInfo(tp: ClassInfo): Type =
3209+
derivedClassInfo(tp, this(tp.prefix))
31873210

31883211
def andThen(f: Type => Type): TypeMap = new TypeMap {
31893212
override def stopAtStatic = thisMap.stopAtStatic
@@ -3209,6 +3232,55 @@ object Types {
32093232
def apply(tp: Type) = tp
32103233
}
32113234

3235+
abstract class ApproximatingTypeMap(implicit ctx: Context) extends TypeMap { thisMap =>
3236+
def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType) =
3237+
if (variance == 0) NoType
3238+
else apply(if (variance < 0) lo else hi)
3239+
3240+
override protected def derivedSelect(tp: NamedType, pre: Type) =
3241+
if (pre eq tp.prefix) tp
3242+
else tp.info match {
3243+
case TypeAlias(alias) => apply(alias) // try to heal by following aliases
3244+
case _ =>
3245+
if (pre.exists && !pre.isRef(defn.NothingClass) && variance > 0) tp.derivedSelect(pre)
3246+
else tp.info match {
3247+
case TypeBounds(lo, hi) => approx(lo, hi)
3248+
case _ => approx()
3249+
}
3250+
}
3251+
override protected def derivedRefinedType(tp: RefinedType, parent: Type, info: Type) =
3252+
if (parent.exists && info.exists) tp.derivedRefinedType(parent, tp.refinedName, info)
3253+
else approx(hi = parent)
3254+
override protected def derivedTypeAlias(tp: TypeAlias, alias: Type) =
3255+
if (alias.exists) tp.derivedTypeAlias(alias)
3256+
else approx(NoType, TypeBounds.empty)
3257+
override protected def derivedTypeBounds(tp: TypeBounds, lo: Type, hi: Type) =
3258+
if (lo.exists && hi.exists) tp.derivedTypeBounds(lo, hi)
3259+
else approx(NoType,
3260+
if (lo.exists) TypeBounds.lower(lo)
3261+
else if (hi.exists) TypeBounds.upper(hi)
3262+
else TypeBounds.empty)
3263+
override protected def derivedSuperType(tp: SuperType, thistp: Type, supertp: Type) =
3264+
if (thistp.exists && supertp.exists) tp.derivedSuperType(thistp, supertp)
3265+
else NoType
3266+
override protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type) =
3267+
if (tp1.exists && tp2.exists) tp.derivedAndOrType(tp1, tp2)
3268+
else if (tp.isAnd) approx(hi = tp1 & tp2) // if one of tp1d, tp2d exists, it is the result of tp1d & tp2d
3269+
else approx(lo = tp1 & tp2)
3270+
override protected def derivedSkolemType(tp: SkolemType, info: Type) =
3271+
if (info.exists) tp.derivedSkolemType(info)
3272+
else NoType
3273+
override protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation) =
3274+
if (underlying.exists) tp.derivedAnnotatedType(underlying, annot)
3275+
else NoType
3276+
override protected def derivedWildcardType(tp: WildcardType, bounds: Type) =
3277+
if (bounds.exists) tp.derivedWildcardType(bounds)
3278+
else WildcardType
3279+
override protected def derivedClassInfo(tp: ClassInfo, pre: Type): Type =
3280+
if (pre.exists) tp.derivedClassInfo(pre)
3281+
else NoType
3282+
}
3283+
32123284
// ----- TypeAccumulators ----------------------------------------------------
32133285

32143286
abstract class TypeAccumulator[T](implicit protected val ctx: Context) extends ((T, Type) => T) {

0 commit comments

Comments
 (0)