Skip to content

Commit 1ec4374

Browse files
authored
Improve ConstraintHandling of SkolemTypes (#20175)
By retaining instantiated type vars in ApproximatingTypeMap when possible.
2 parents acfc621 + 6e5f540 commit 1ec4374

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6180,6 +6180,10 @@ object Types extends TypeUtils {
61806180
variance = saved
61816181
derivedLambdaType(tp)(ptypes1, this(restpe))
61826182

6183+
protected def mapOverTypeVar(tp: TypeVar) =
6184+
val inst = tp.instanceOpt
6185+
if (inst.exists) apply(inst) else tp
6186+
61836187
def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]
61846188

61856189
protected def mapCapturingType(tp: Type, parent: Type, refs: CaptureSet, v: Int): Type =
@@ -6217,8 +6221,7 @@ object Types extends TypeUtils {
62176221
derivedTypeBounds(tp, lo1, this(tp.hi))
62186222

62196223
case tp: TypeVar =>
6220-
val inst = tp.instanceOpt
6221-
if (inst.exists) apply(inst) else tp
6224+
mapOverTypeVar(tp)
62226225

62236226
case tp: ExprType =>
62246227
derivedExprType(tp, this(tp.resultType))
@@ -6632,6 +6635,16 @@ object Types extends TypeUtils {
66326635
tp.derivedLambdaType(tp.paramNames, formals, restpe)
66336636
}
66346637

6638+
override protected def mapOverTypeVar(tp: TypeVar) =
6639+
val inst = tp.instanceOpt
6640+
if !inst.exists then tp
6641+
else
6642+
// We can keep the original type var if its instance is not transformed
6643+
// by the ApproximatingTypeMap. This allows for simpler bounds and for
6644+
// derivedSkolemType to retain more skolems, by keeping the info unchanged.
6645+
val res = apply(inst)
6646+
if res eq inst then tp else res
6647+
66356648
protected def reapply(tp: Type): Type = apply(tp)
66366649
}
66376650

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,7 @@ i7445b.scala
119119

120120
# more aggresive reduce projection makes a difference
121121
i15525.scala
122+
i19955a.scala
123+
i19955b.scala
124+
i20053b.scala
122125

tests/pos/i19955a.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
trait Summon[R, T <: R]:
3+
type Out
4+
object Summon:
5+
given [R, T <: R]: Summon[R, T] with
6+
type Out = R
7+
8+
trait DFTypeAny
9+
trait DFBits[W <: Int] extends DFTypeAny
10+
class DFVal[+T <: DFTypeAny]
11+
type DFValAny = DFVal[DFTypeAny]
12+
type DFValOf[+T <: DFTypeAny] = DFVal[T]
13+
trait Candidate[R]:
14+
type OutW <: Int
15+
object Candidate:
16+
type Aux[R, O <: Int] = Candidate[R] { type OutW = O }
17+
given [W <: Int, R <: DFValOf[DFBits[W]]]: Candidate[R] with
18+
type OutW = W
19+
20+
extension [L](lhs: L) def foo(using es: Summon[L, lhs.type]): Unit = ???
21+
extension [L <: DFValAny](lhs: L)(using icL: Candidate[L]) def baz: DFValOf[DFBits[icL.OutW]] = ???
22+
extension [L <: DFValAny, W <: Int](lhs: L)(using icL: Candidate.Aux[L, W])
23+
def bazAux: DFValOf[DFBits[W]] = ???
24+
25+
val x = new DFVal[DFBits[4]]
26+
val works = x.bazAux.foo
27+
val fails = x.baz.foo

tests/pos/i19955b.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
trait Wrap[W]
3+
4+
trait IsWrapOfInt[R]:
5+
type Out <: Int
6+
given [W <: Int, R <: Wrap[W]]: IsWrapOfInt[R] with
7+
type Out = Int
8+
9+
trait IsInt[U <: Int]
10+
given [U <: Int]: IsInt[U] = ???
11+
12+
extension [L](lhs: L) def get(using ev: IsWrapOfInt[L]): ev.Out = ???
13+
extension (lhs: Int) def isInt(using IsInt[lhs.type]): Unit = ???
14+
15+
val x: Wrap[Int] = ???
16+
val works = (x.get: Int).isInt
17+
val fails = x.get.isInt

tests/pos/i20053b.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
trait Sub[R, T >: R]
3+
given [R, T >: R]: Sub[R, T] with {}
4+
5+
trait Candidate[-R]:
6+
type OutP
7+
given [P]: Candidate[Option[P]] with
8+
type OutP = P
9+
10+
extension [L](lhs: L)
11+
def ^^^[P](rhs: Option[P])
12+
(using es: Sub[lhs.type, Any])
13+
(using c: Candidate[L])
14+
(using check: c.type <:< Any): Option[c.OutP] = ???
15+
16+
val x: Option[Boolean] = ???
17+
18+
val z1 = x ^^^ x // Ok
19+
val z2 = z1 ^^^ x // Ok
20+
val zz = ^^^[Option[Boolean]](x ^^^ x)(x) // Ok
21+
22+
val zzz = x ^^^ x ^^^ x // Error before changes

0 commit comments

Comments
 (0)