Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 64ace6a

Browse files
committed
When detecting subtyping loops remember problematic cases on the way out
The test causes a subtyping test that loops, which is caught by existing infrastructure (LogPendingSubTypesThreshold). However, before reaching the threshold the subtyping check branches off into two equal cases at every iteration. For details, see the bug report. To avoid having to reach the threshold on every one of these branches, remember the problematic subtyping tests on teh way back.
1 parent 241446d commit 64ace6a

File tree

4 files changed

+37
-12
lines changed

4 files changed

+37
-12
lines changed

project/MimaFilters.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ object MimaFilters extends AutoPlugin {
7575
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.mutable.StringBuilder.getChars"),
7676
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.ArrayCharSequence.getChars"),
7777
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.SeqCharSequence.getChars"),
78+
79+
// scala/scala#11124
80+
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse.knownFalseSubTypes"),
7881
)
7982

8083
override val buildSettings = Seq(

src/reflect/scala/reflect/internal/tpe/TypeComparers.scala

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ trait TypeComparers {
3030
private[this] val _pendingSubTypes = new mutable.HashSet[SubTypePair]
3131
def pendingSubTypes = _pendingSubTypes
3232

33+
private[this] val _knownFalseSubTypes = new mutable.HashMap[Type, Type]
34+
def knownFalseSubTypes = _knownFalseSubTypes
35+
3336
final case class SubTypePair(tp1: Type, tp2: Type) {
3437
// scala/bug#8146 we used to implement equality here in terms of pairwise =:=.
3538
// But, this was inconsistent with hashCode, which was based on the
@@ -84,9 +87,10 @@ trait TypeComparers {
8487
}
8588
} finally {
8689
subsametypeRecursions -= 1
87-
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
88-
// it doesn't help to keep separate recursion counts for the three methods that now share it
89-
// if (subsametypeRecursions == 0) undoLog.clear()
90+
if (subsametypeRecursions == 0) {
91+
knownFalseSubTypes.clear()
92+
// undoLog.clear() // too eager, breaks #3281, #3866
93+
}
9094
}
9195

9296
def isDifferentTypeConstructor(tp1: Type, tp2: Type) = !isSameTypeConstructor(tp1, tp2)
@@ -121,9 +125,10 @@ trait TypeComparers {
121125
}
122126
finally {
123127
subsametypeRecursions -= 1
124-
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
125-
// it doesn't help to keep separate recursion counts for the three methods that now share it
126-
// if (subsametypeRecursions == 0) undoLog.clear()
128+
if (subsametypeRecursions == 0) {
129+
knownFalseSubTypes.clear()
130+
// undoLog.clear() // too eager, breaks #3281, #3866
131+
}
127132
}
128133

129134
// @pre: at least one argument has annotations
@@ -291,16 +296,20 @@ trait TypeComparers {
291296

292297
try result = { // if subtype test fails, it should not affect constraints on typevars
293298
if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
294-
val p = new SubTypePair(tp1, tp2)
295-
if (pendingSubTypes(p))
299+
val p = SubTypePair(tp1, tp2)
300+
if (pendingSubTypes(p)) {
301+
knownFalseSubTypes(tp1) = tp2 // see scala/bug#13119
296302
false // see neg/t8146-no-finitary*
297-
else
303+
} else
298304
try {
299305
pendingSubTypes += p
300306
isSubType1(tp1, tp2, depth)
301307
} finally {
302308
pendingSubTypes -= p
303309
}
310+
} else if (!knownFalseSubTypes.isEmpty && knownFalseSubTypes.get(tp1).contains(tp2)) {
311+
// redundant `isEmtpy` check is probably premature optimization, but isSubType is perf sensitive
312+
false
304313
} else {
305314
isSubType1(tp1, tp2, depth)
306315
}
@@ -309,9 +318,10 @@ trait TypeComparers {
309318
result
310319
} finally {
311320
subsametypeRecursions -= 1
312-
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
313-
// it doesn't help to keep separate recursion counts for the three methods that now share it
314-
// if (subsametypeRecursions == 0) undoLog.clear()
321+
if (subsametypeRecursions == 0) {
322+
knownFalseSubTypes.clear()
323+
// undoLog.clear() // too eager, breaks #3281, #3866
324+
}
315325
}
316326

317327
/** Check whether the subtype or type equivalence relationship

src/reflect/scala/reflect/runtime/SynchronizedTypes.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
6969
private lazy val _pendingSubTypes = mkThreadLocalStorage(new mutable.HashSet[SubTypePair])
7070
override def pendingSubTypes = _pendingSubTypes.get
7171

72+
private lazy val _knownFalseSubTypes = mkThreadLocalStorage(new mutable.HashMap[Type, Type])
73+
override def knownFalseSubTypes = _knownFalseSubTypes.get
74+
7275
private lazy val _basetypeRecursions = mkThreadLocalStorage(0)
7376
override def basetypeRecursions = _basetypeRecursions.get
7477
override def basetypeRecursions_=(value: Int) = _basetypeRecursions.set(value)

test/files/pos/t13119.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait A[T]
2+
final class C[T, E] extends A[T with E]
3+
4+
object T {
5+
def f(x: A[?]): Int = x match {
6+
case b: C[?, ?] => 0
7+
case _ => 1
8+
}
9+
}

0 commit comments

Comments
 (0)