Skip to content

Commit f6867c8

Browse files
committed
Calibrate findMember logging thresholds and test case
Adds IterableSelfRec.scala which caused lockup of the compiler. After a lot of work the problem was determined to be polyomial or exponential behavior of the compiler when executing findMember on refined types that contain several bindings where the resutling & causes a recursive invokation of findMember with the same name. We do have a stop for this now, but if the stop comes too late the runtime will grow very fast. Problem addressed by kiccking in earlier with the stopping logic.
1 parent 650bec9 commit f6867c8

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

src/dotty/tools/dotc/config/Config.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,17 @@ object Config {
8585
/** How many recursive calls to isSubType are performed before logging starts. */
8686
final val LogPendingSubTypesThreshold = 50
8787

88-
/** How many recursive calls to findMember are performed before logging names starts */
89-
final val LogPendingFindMemberThreshold = 20
88+
/** How many recursive calls to findMember are performed before logging names starts
89+
* Note: this threshold has to be chosen carefully. Too large, and programs
90+
* like tests/pos/IterableSelfRec go into polynomial (or even exponential?)
91+
* compile time slowdown. Too small and normal programs will cause the compiler to
92+
* do inefficient operations on findMember. The current value is determined
93+
* so that (1) IterableSelfRec still compiles in reasonable time (< 10sec) (2) Compiling
94+
* dotty itself only causes small pending names lists to be generated (we measured
95+
* at max 6 elements) and these lists are never searched with contains.
96+
*/
97+
final val LogPendingFindMemberThreshold = 10
9098

9199
/** Maximal number of outstanding recursive calls to findMember */
92-
final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 2
100+
final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4
93101
}

tests/pos/IterableSelfRec.scala

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package dotty.collection
2+
package immutable
3+
4+
import annotation.unchecked.uncheckedVariance
5+
6+
trait Collection[T] { self =>
7+
type This <: Collection { type This <: self.This }
8+
def companion: CollectionCompanion[This]
9+
}
10+
11+
trait Iterable[T] extends Collection[T] { self =>
12+
type This <: Iterable { type This <: self.This }
13+
override def companion: IterableCompanion[This] = Iterable.asInstanceOf
14+
15+
def iterator: Iterator[T]
16+
}
17+
18+
trait Seq[T] extends Iterable[T] { self =>
19+
type This <: Seq { type This <: self.This }
20+
override def companion: IterableCompanion[This] = Seq.asInstanceOf
21+
22+
def apply(x: Int): T
23+
}
24+
25+
abstract class CollectionCompanion[+CC <: Collection { type This <: CC }]
26+
27+
abstract class IterableCompanion[+CC <: Iterable { type This <: CC }] extends CollectionCompanion[CC] {
28+
def fromIterator[T](it: Iterator[T]): CC[T]
29+
def map[T, U](xs: Iterable[T], f: T => U): CC[U] =
30+
fromIterator(xs.iterator.map(f))
31+
def filter[T](xs: Iterable[T], p: T => Boolean): CC[T] =
32+
fromIterator(xs.iterator.filter(p))
33+
def flatMap[T, U](xs: Iterable[T], f: T => TraversableOnce[U]): CC[U] =
34+
fromIterator(xs.iterator.flatMap(f))
35+
36+
implicit def transformOps[T](xs: CC[T] @uncheckedVariance): TransformOps[CC, T] = ??? // new TransformOps[CC, T](xs)
37+
}
38+
39+
class TransformOps[+CC <: Iterable { type This <: CC }, T] (val xs: CC[T]) extends AnyVal {
40+
def companion[T](xs: CC[T] @uncheckedVariance): IterableCompanion[CC] = xs.companion
41+
def map[U](f: T => U): CC[U] = companion(xs).map(xs, f)
42+
def filter(p: T => Boolean): CC[T] = companion(xs).filter(xs, p)
43+
def flatMap[U](f: T => TraversableOnce[U]): CC[U] = companion(xs).flatMap(xs, f)
44+
}
45+
46+
object Iterable extends IterableCompanion[Iterable] {
47+
def fromIterator[T](it: Iterator[T]): Iterable[T] = ???
48+
}
49+
object Seq extends IterableCompanion[Seq] {
50+
def fromIterator[T](it: Iterator[T]): Seq[T] = ???
51+
}
52+

0 commit comments

Comments
 (0)