diff options
-rw-r--r-- | src/dotty/tools/dotc/config/Config.scala | 14 | ||||
-rw-r--r-- | tests/pos/IterableSelfRec.scala | 52 |
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] = ??? +} + |