Skip to content

Commit

Permalink
Improve ConstraintHandling of SkolemTypes (#20175)
Browse files Browse the repository at this point in the history
By retaining instantiated type vars in ApproximatingTypeMap when possible.
  • Loading branch information
smarter authored Apr 13, 2024
2 parents acfc621 + 6e5f540 commit 1ec4374
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 2 deletions.
17 changes: 15 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6180,6 +6180,10 @@ object Types extends TypeUtils {
variance = saved
derivedLambdaType(tp)(ptypes1, this(restpe))

protected def mapOverTypeVar(tp: TypeVar) =
val inst = tp.instanceOpt
if (inst.exists) apply(inst) else tp

def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]

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

case tp: TypeVar =>
val inst = tp.instanceOpt
if (inst.exists) apply(inst) else tp
mapOverTypeVar(tp)

case tp: ExprType =>
derivedExprType(tp, this(tp.resultType))
Expand Down Expand Up @@ -6632,6 +6635,16 @@ object Types extends TypeUtils {
tp.derivedLambdaType(tp.paramNames, formals, restpe)
}

override protected def mapOverTypeVar(tp: TypeVar) =
val inst = tp.instanceOpt
if !inst.exists then tp
else
// We can keep the original type var if its instance is not transformed
// by the ApproximatingTypeMap. This allows for simpler bounds and for
// derivedSkolemType to retain more skolems, by keeping the info unchanged.
val res = apply(inst)
if res eq inst then tp else res

protected def reapply(tp: Type): Type = apply(tp)
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/test/dotc/pos-test-pickling.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,7 @@ i7445b.scala

# more aggresive reduce projection makes a difference
i15525.scala
i19955a.scala
i19955b.scala
i20053b.scala

27 changes: 27 additions & 0 deletions tests/pos/i19955a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

trait Summon[R, T <: R]:
type Out
object Summon:
given [R, T <: R]: Summon[R, T] with
type Out = R

trait DFTypeAny
trait DFBits[W <: Int] extends DFTypeAny
class DFVal[+T <: DFTypeAny]
type DFValAny = DFVal[DFTypeAny]
type DFValOf[+T <: DFTypeAny] = DFVal[T]
trait Candidate[R]:
type OutW <: Int
object Candidate:
type Aux[R, O <: Int] = Candidate[R] { type OutW = O }
given [W <: Int, R <: DFValOf[DFBits[W]]]: Candidate[R] with
type OutW = W

extension [L](lhs: L) def foo(using es: Summon[L, lhs.type]): Unit = ???
extension [L <: DFValAny](lhs: L)(using icL: Candidate[L]) def baz: DFValOf[DFBits[icL.OutW]] = ???
extension [L <: DFValAny, W <: Int](lhs: L)(using icL: Candidate.Aux[L, W])
def bazAux: DFValOf[DFBits[W]] = ???

val x = new DFVal[DFBits[4]]
val works = x.bazAux.foo
val fails = x.baz.foo
17 changes: 17 additions & 0 deletions tests/pos/i19955b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

trait Wrap[W]

trait IsWrapOfInt[R]:
type Out <: Int
given [W <: Int, R <: Wrap[W]]: IsWrapOfInt[R] with
type Out = Int

trait IsInt[U <: Int]
given [U <: Int]: IsInt[U] = ???

extension [L](lhs: L) def get(using ev: IsWrapOfInt[L]): ev.Out = ???
extension (lhs: Int) def isInt(using IsInt[lhs.type]): Unit = ???

val x: Wrap[Int] = ???
val works = (x.get: Int).isInt
val fails = x.get.isInt
22 changes: 22 additions & 0 deletions tests/pos/i20053b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

trait Sub[R, T >: R]
given [R, T >: R]: Sub[R, T] with {}

trait Candidate[-R]:
type OutP
given [P]: Candidate[Option[P]] with
type OutP = P

extension [L](lhs: L)
def ^^^[P](rhs: Option[P])
(using es: Sub[lhs.type, Any])
(using c: Candidate[L])
(using check: c.type <:< Any): Option[c.OutP] = ???

val x: Option[Boolean] = ???

val z1 = x ^^^ x // Ok
val z2 = z1 ^^^ x // Ok
val zz = ^^^[Option[Boolean]](x ^^^ x)(x) // Ok

val zzz = x ^^^ x ^^^ x // Error before changes

0 comments on commit 1ec4374

Please sign in to comment.