Skip to content

Commit 2c46850

Browse files
committed
Make applications inside ranges respect variance
A Range, if it survives, will always lead to a situation where the upper bound appears in a covariant position in the result, and the lower bound appears in a contravariant position. Hence, when we apply a type map to the argument in a range we should take this into account. Fixes a previous failure in t2435.scala and dependent-extractors.scala.
1 parent 79c7a03 commit 2c46850

File tree

4 files changed

+29
-8
lines changed

4 files changed

+29
-8
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
132132

133133
/** Approximate a type `tp` with a type that does not contain skolem types. */
134134
object deskolemize extends ApproximatingTypeMap {
135-
def apply(tp: Type) = tp match {
136-
case tp: SkolemType => range(hi = apply(tp.info))
137-
case _ => mapOver(tp)
135+
def apply(tp: Type) = /*ctx.traceIndented(i"deskolemize($tp) at $variance", show = true)*/ {
136+
tp match {
137+
case tp: SkolemType => range(hi = atVariance(1)(apply(tp.info)))
138+
case _ => mapOver(tp)
139+
}
138140
}
139141
}
140142

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3890,6 +3890,9 @@ object Types {
38903890
case class Range(lo: Type, hi: Type) extends UncachedGroundType {
38913891
assert(!lo.isInstanceOf[Range])
38923892
assert(!hi.isInstanceOf[Range])
3893+
3894+
override def toText(printer: Printer): Text =
3895+
lo.toText(printer) ~ ".." ~ hi.toText(printer)
38933896
}
38943897

38953898
/** A type map that approximates TypeBounds types depending on
@@ -3924,14 +3927,23 @@ object Types {
39243927
case _ => tp
39253928
}
39263929

3930+
def atVariance[T](v: Int)(op: => T): T = {
3931+
val saved = variance
3932+
variance = v
3933+
try op finally variance = saved
3934+
}
3935+
39273936
override protected def derivedSelect(tp: NamedType, pre: Type) =
39283937
if (pre eq tp.prefix) tp
39293938
else pre match {
39303939
case Range(preLo, preHi) =>
39313940
tp.info match {
3932-
case TypeAlias(alias) => apply(alias)
3933-
case TypeBounds(lo, hi) => range(apply(lo), apply(hi))
3934-
case _ => range(tp.derivedSelect(preLo), tp.derivedSelect(preHi))
3941+
case TypeAlias(alias) =>
3942+
apply(alias)
3943+
case TypeBounds(lo, hi) =>
3944+
range(atVariance(-1)(apply(lo)), atVariance(1)(apply(hi)))
3945+
case _ =>
3946+
range(tp.derivedSelect(preLo), tp.derivedSelect(preHi))
39353947
}
39363948
case _ => tp.derivedSelect(pre)
39373949
}
@@ -3949,23 +3961,27 @@ object Types {
39493961
tp.derivedRefinedType(parent, tp.refinedName, rangeToBounds(info))
39503962
}
39513963
}
3964+
39523965
override protected def derivedRecType(tp: RecType, parent: Type) =
39533966
parent match {
39543967
case Range(lo, hi) => range(tp.rebind(lo), tp.rebind(hi))
39553968
case _ => tp.rebind(parent)
39563969
}
3970+
39573971
override protected def derivedTypeAlias(tp: TypeAlias, alias: Type) =
39583972
alias match {
39593973
case Range(lo, hi) =>
39603974
if (variance > 0) TypeBounds(lo, hi)
39613975
else range(TypeAlias(lo), TypeAlias(hi))
39623976
case _ => tp.derivedTypeAlias(alias)
39633977
}
3978+
39643979
override protected def derivedTypeBounds(tp: TypeBounds, lo: Type, hi: Type) =
39653980
if (isRange(lo) || isRange(hi))
39663981
if (variance > 0) TypeBounds(loBound(lo), hiBound(hi))
39673982
else range(TypeBounds(hiBound(lo), loBound(hi)), TypeBounds(loBound(lo), hiBound(hi)))
39683983
else tp.derivedTypeBounds(lo, hi)
3984+
39693985
override protected def derivedSuperType(tp: SuperType, thistp: Type, supertp: Type) =
39703986
if (isRange(thistp) || isRange(supertp)) range()
39713987
else tp.derivedSuperType(thistp, supertp)
@@ -4005,6 +4021,7 @@ object Types {
40054021
if (tp.isAnd) range(loBound(tp1) & loBound(tp2), hiBound(tp1) & hiBound(tp2))
40064022
else range(loBound(tp1) | loBound(tp2), hiBound(tp1) | hiBound(tp2))
40074023
else tp.derivedAndOrType(tp1, tp2)
4024+
40084025
override protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation) =
40094026
underlying match {
40104027
case Range(lo, hi) =>
@@ -4016,6 +4033,7 @@ object Types {
40164033
override protected def derivedWildcardType(tp: WildcardType, bounds: Type) = {
40174034
tp.derivedWildcardType(rangeToBounds(bounds))
40184035
}
4036+
40194037
override protected def derivedClassInfo(tp: ClassInfo, pre: Type): Type = {
40204038
assert(!pre.isInstanceOf[Range])
40214039
tp.derivedClassInfo(pre)

tests/pos/dependent-extractors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ object Test {
1010
val y1: Int = y
1111

1212
val z = (c: Any) match { case X(y) => y }
13-
// val z1: C#T = z // error: z has type Any TODO: find out why
13+
val z1: C#T = z // error: z has type Any TODO: find out why
1414
}

tests/pos/t2435.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ object Test {
2323
val a2 = a1.chain("a")
2424

2525
println("\nDoesn't compile:")
26-
val a = FNil.chain("a").chain("a").chain("a")
26+
val a3 = FNil.chain("a").chain("a").chain("a")
27+
val a4: FConstant[_ <: FConstant[_ <: FConstant[FNil.type]]] = a3
2728
}

0 commit comments

Comments
 (0)