aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/config/Config.scala14
-rw-r--r--tests/pos/IterableSelfRec.scala52
2 files changed, 63 insertions, 3 deletions
diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala
index c00b06913..27d5effa5 100644
--- a/src/dotty/tools/dotc/config/Config.scala
+++ b/src/dotty/tools/dotc/config/Config.scala
@@ -85,9 +85,17 @@ object Config {
/** How many recursive calls to isSubType are performed before logging starts. */
final val LogPendingSubTypesThreshold = 50
- /** How many recursive calls to findMember are performed before logging names starts */
- final val LogPendingFindMemberThreshold = 20
+ /** How many recursive calls to findMember are performed before logging names starts
+ * Note: this threshold has to be chosen carefully. Too large, and programs
+ * like tests/pos/IterableSelfRec go into polynomial (or even exponential?)
+ * compile time slowdown. Too small and normal programs will cause the compiler to
+ * do inefficient operations on findMember. The current value is determined
+ * so that (1) IterableSelfRec still compiles in reasonable time (< 10sec) (2) Compiling
+ * dotty itself only causes small pending names lists to be generated (we measured
+ * at max 6 elements) and these lists are never searched with contains.
+ */
+ final val LogPendingFindMemberThreshold = 10
/** Maximal number of outstanding recursive calls to findMember */
- final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 2
+ final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4
}
diff --git a/tests/pos/IterableSelfRec.scala b/tests/pos/IterableSelfRec.scala
new file mode 100644
index 000000000..bba7a82d2
--- /dev/null
+++ b/tests/pos/IterableSelfRec.scala
@@ -0,0 +1,52 @@
+package dotty.collection
+package immutable
+
+import annotation.unchecked.uncheckedVariance
+
+trait Collection[T] { self =>
+ type This <: Collection { type This <: self.This }
+ def companion: CollectionCompanion[This]
+}
+
+trait Iterable[T] extends Collection[T] { self =>
+ type This <: Iterable { type This <: self.This }
+ override def companion: IterableCompanion[This] = Iterable.asInstanceOf
+
+ def iterator: Iterator[T]
+}
+
+trait Seq[T] extends Iterable[T] { self =>
+ type This <: Seq { type This <: self.This }
+ override def companion: IterableCompanion[This] = Seq.asInstanceOf
+
+ def apply(x: Int): T
+}
+
+abstract class CollectionCompanion[+CC <: Collection { type This <: CC }]
+
+abstract class IterableCompanion[+CC <: Iterable { type This <: CC }] extends CollectionCompanion[CC] {
+ def fromIterator[T](it: Iterator[T]): CC[T]
+ def map[T, U](xs: Iterable[T], f: T => U): CC[U] =
+ fromIterator(xs.iterator.map(f))
+ def filter[T](xs: Iterable[T], p: T => Boolean): CC[T] =
+ fromIterator(xs.iterator.filter(p))
+ def flatMap[T, U](xs: Iterable[T], f: T => TraversableOnce[U]): CC[U] =
+ fromIterator(xs.iterator.flatMap(f))
+
+ implicit def transformOps[T](xs: CC[T] @uncheckedVariance): TransformOps[CC, T] = ??? // new TransformOps[CC, T](xs)
+}
+
+class TransformOps[+CC <: Iterable { type This <: CC }, T] (val xs: CC[T]) extends AnyVal {
+ def companion[T](xs: CC[T] @uncheckedVariance): IterableCompanion[CC] = xs.companion
+ def map[U](f: T => U): CC[U] = companion(xs).map(xs, f)
+ def filter(p: T => Boolean): CC[T] = companion(xs).filter(xs, p)
+ def flatMap[U](f: T => TraversableOnce[U]): CC[U] = companion(xs).flatMap(xs, f)
+}
+
+object Iterable extends IterableCompanion[Iterable] {
+ def fromIterator[T](it: Iterator[T]): Iterable[T] = ???
+}
+object Seq extends IterableCompanion[Seq] {
+ def fromIterator[T](it: Iterator[T]): Seq[T] = ???
+}
+