Skip to content

Commit

Permalink
Force LazyRef in AvoidWildcardsMap
Browse files Browse the repository at this point in the history
This is to avoid unneeded new LazyRef's.  LazyRefs, which are created
for recursive types, aren't cacheable, so if you TypeMap an AppliedType
with one, it will create a brand new instance.  OrderingConstraint#init
runs AvoidWildcardsMap on param bounds.  So when instDirection compares
the constraint bounds and the original param bounds (to calculate the
instantiate direction), because they are new instances they won't
shortcircuit, leading to a recursion overflow.  By forcing, it will eq
check and return true.

In particular, with i5877, which is a neg test of recursive overflows,
the new implementation of interpolateTypeVars does more type comparisons
(to calculate the instDirection).  If the LazyRefs are kept eq, then the
AppliedTypes in the bounds are also eq, and so the subtyping check
shortcircuits true, rather than overflowing.
  • Loading branch information
dwijnand committed Aug 17, 2024
1 parent 1d56a51 commit 53ba3c8
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 5 deletions.
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6631,6 +6631,9 @@ object Types extends TypeUtils {
range(atVariance(-variance)(apply(bounds.lo)), apply(bounds.hi))
def apply(t: Type): Type = t match
case t: WildcardType => mapWild(t)
case tp: LazyRef => mapOver(tp) match
case tp1: LazyRef if tp.ref eq tp1.ref => tp
case tp1 => tp1
case _ => mapOver(t)

// ----- TypeAccumulators ----------------------------------------------------
Expand Down
10 changes: 5 additions & 5 deletions tests/neg-deep-subtype/i5877.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
object Main { // error // error
object Main {
def main(a: Array[String]): Unit = {
println("you may not run `testHasThisType` - just check that it compiles")
// comment lines after "// this line of code makes" comments to make it compilable again
Expand All @@ -18,25 +18,25 @@ object Main { // error // error

// ---- ---- ---- ----

def testHasThisType(): Unit = { // error // error
def testHasThisType(): Unit = {
def testSelf[PThis <: HasThisType[_ <: PThis]](that: HasThisType[PThis]): Unit = {
val thatSelf = that.self()
// that.self().type <: that.This
assert(implicitly[thatSelf.type <:< that.This] != null)
}
val that: HasThisType[_] = Foo() // null.asInstanceOf
testSelf(that) // error: recursion limit exceeded // error
testSelf(that) // error: recursion limit exceeded
}


def testHasThisType2(): Unit = { // error // error
def testHasThisType2(): Unit = {
def testSelf[PThis <: HasThisType[_ <: PThis]](that: PThis with HasThisType[PThis]): Unit = {
// that.type <: that.This
assert(implicitly[that.type <:< that.This] != null)
}
val that: HasThisType[_] = Foo() // null.asInstanceOf
// this line of code makes Dotty compiler infinite recursion (stopped only by overflow) - comment it to make it compilable again
testSelf(that) // error: recursion limit exceeded // error
testSelf(that) // error: recursion limit exceeded
}

// ---- ---- ---- ----
Expand Down

0 comments on commit 53ba3c8

Please sign in to comment.