@@ -30,6 +30,9 @@ trait TypeComparers {
30
30
private [this ] val _pendingSubTypes = new mutable.HashSet [SubTypePair ]
31
31
def pendingSubTypes = _pendingSubTypes
32
32
33
+ private [this ] val _knownFalseSubTypes = new mutable.HashMap [Type , Type ]
34
+ def knownFalseSubTypes = _knownFalseSubTypes
35
+
33
36
final case class SubTypePair (tp1 : Type , tp2 : Type ) {
34
37
// scala/bug#8146 we used to implement equality here in terms of pairwise =:=.
35
38
// But, this was inconsistent with hashCode, which was based on the
@@ -84,9 +87,10 @@ trait TypeComparers {
84
87
}
85
88
} finally {
86
89
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
+ }
90
94
}
91
95
92
96
def isDifferentTypeConstructor (tp1 : Type , tp2 : Type ) = ! isSameTypeConstructor(tp1, tp2)
@@ -121,9 +125,10 @@ trait TypeComparers {
121
125
}
122
126
finally {
123
127
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
+ }
127
132
}
128
133
129
134
// @pre: at least one argument has annotations
@@ -291,16 +296,20 @@ trait TypeComparers {
291
296
292
297
try result = { // if subtype test fails, it should not affect constraints on typevars
293
298
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
296
302
false // see neg/t8146-no-finitary*
297
- else
303
+ } else
298
304
try {
299
305
pendingSubTypes += p
300
306
isSubType1(tp1, tp2, depth)
301
307
} finally {
302
308
pendingSubTypes -= p
303
309
}
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
304
313
} else {
305
314
isSubType1(tp1, tp2, depth)
306
315
}
@@ -309,9 +318,10 @@ trait TypeComparers {
309
318
result
310
319
} finally {
311
320
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
+ }
315
325
}
316
326
317
327
/** Check whether the subtype or type equivalence relationship
0 commit comments