From 830b72432fc02b86e798da24b084264881cbc392 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Jun 2016 19:54:09 +0200 Subject: Change tests - compileMixed failed because there was a cycle between immutable.Seq (compiled) and parallel.ParSeq (loaded from classfile). Inspection of the completion log (turn completions Printer on) and the stack trace showed that there's nothing we can do here. The old hk scheme did not go into the cycle because it did not force an unrelated type. I believe with enough tweaking we would also hva egotten a cycle in the old hk scheme. The test is "fixed" by adding parallel.ParSeq to the files to compile. - Disable named parameter tests Those tests do not work yet with the revised hk scheme. Before trying to fix this, we should first decide what parts of named parameters should be kept. --- test/dotc/tests.scala | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index bac443735..f98b8114c 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -149,6 +149,7 @@ class tests extends CompilerTest { @Test def compileMixed = compileLine( """tests/pos/B.scala |./scala-scala/src/library/scala/collection/immutable/Seq.scala + |./scala-scala/src/library/scala/collection/parallel/ParSeq.scala |./scala-scala/src/library/scala/package.scala |./scala-scala/src/library/scala/collection/GenSeqLike.scala |./scala-scala/src/library/scala/collection/SeqLike.scala -- cgit v1.2.3 From fd62c7b6dc6882f658ba2d614cb95a7141842929 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 7 Jul 2016 15:14:37 +0200 Subject: Disallow higher-kinded types that simulate general existential types We cannot handle such types in general. So we now check that a hk application C[args] where some of the arguments are wildcards does not have as a supertype a hk application ([X] -> B)[args] --- src/dotty/tools/dotc/core/Mode.scala | 5 + src/dotty/tools/dotc/core/TypeApplications.scala | 41 +++- src/dotty/tools/dotc/typer/Checking.scala | 22 ++ test/dotc/tests.scala | 1 - tests/neg/existentials.scala | 61 ++++++ tests/pos-scala2/GenTraversableFactory.scala | 252 +++++++++++++++++++++++ tests/pos-scala2/t6014.scala | 13 ++ tests/pos/GenTraversableFactory.scala | 252 ----------------------- tests/pos/t6014.scala | 13 -- 9 files changed, 389 insertions(+), 271 deletions(-) create mode 100644 tests/neg/existentials.scala create mode 100644 tests/pos-scala2/GenTraversableFactory.scala create mode 100644 tests/pos-scala2/t6014.scala delete mode 100644 tests/pos/GenTraversableFactory.scala delete mode 100644 tests/pos/t6014.scala (limited to 'test') diff --git a/src/dotty/tools/dotc/core/Mode.scala b/src/dotty/tools/dotc/core/Mode.scala index 0e188ace2..3e9b7effe 100644 --- a/src/dotty/tools/dotc/core/Mode.scala +++ b/src/dotty/tools/dotc/core/Mode.scala @@ -84,5 +84,10 @@ object Mode { /** Use Scala2 scheme for overloading and implicit resolution */ val OldOverloadingResolution = newMode(14, "OldOverloadingResolution") + /** Allow hk applications of type lambdas to wildcard arguments; + * used for checking that such applications do not normally arise + */ + val AllowLambdaWildcardApply = newMode(15, "AllowHKApplyToWildcards") + val PatternOrType = Pattern | Type } diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 580cd6569..be0c08d15 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -129,8 +129,10 @@ object TypeApplications { /** A type map that tries to reduce a (part of) the result type of the type lambda `tycon` * with the given `args`(some of which are wildcard arguments represented by type bounds). * Non-wildcard arguments are substituted everywhere as usual. A wildcard argument - * `>: L <: H` is substituted for a type lambda parameter `X` only if `X` appears - * in a toplevel refinement of the form + * `>: L <: H` is substituted for a type lambda parameter `X` only under certain conditions. + * + * 1. If Mode.AllowLambdaWildcardApply is set: + * The wildcard argument is substituted only if `X` appears in a toplevel refinement of the form * * { type A = X } * @@ -141,19 +143,48 @@ object TypeApplications { * * The `allReplaced` field indicates whether all occurrences of type lambda parameters * in the reduced type have been replaced with arguments. + * + * 2. If Mode.AllowLambdaWildcardApply is not set: + * All refinements of the form + * + * { type A = X } + * + * are replaced by: + * + * { type A >: L <: U } + * + * Any other occurrence of `X` in `tycon` is replaced by `U`, if the + * occurrence of `X` in `tycon` is covariant, or nonvariant, or by `L`, + * if the occurrence is contravariant. + * + * The idea is that the `AllowLambdaWildcardApply` mode is used to check whether + * a type can be soundly reduced, and to give an error or warning if that + * is not the case. By contrast, the default mode, with `AllowLambdaWildcardApply` + * not set, reduces all applications even if this yields a different type, so + * its postcondition is that no type parameters of `tycon` appear in the + * result type. Using this mode, we can guarantee that `appliedTo` will never + * produce a higher-kinded application with a type lambda as type constructor. */ class Reducer(tycon: TypeLambda, args: List[Type])(implicit ctx: Context) extends TypeMap { private var available = Set((0 until args.length): _*) var allReplaced = true def hasWildcardArg(p: PolyParam) = p.binder == tycon && args(p.paramNum).isInstanceOf[TypeBounds] + def canReduceWildcard(p: PolyParam) = + !ctx.mode.is(Mode.AllowLambdaWildcardApply) || available.contains(p.paramNum) def apply(t: Type) = t match { - case t @ TypeAlias(p: PolyParam) if hasWildcardArg(p) && available.contains(p.paramNum) => + case t @ TypeAlias(p: PolyParam) if hasWildcardArg(p) && canReduceWildcard(p) => available -= p.paramNum args(p.paramNum) case p: PolyParam if p.binder == tycon => - if (hasWildcardArg(p)) { allReplaced = false; p } - else args(p.paramNum) + args(p.paramNum) match { + case TypeBounds(lo, hi) => + if (ctx.mode.is(Mode.AllowLambdaWildcardApply)) { allReplaced = false; p } + else if (variance < 0) lo + else hi + case arg => + arg + } case _: TypeBounds | _: HKApply => val saved = available available = Set() diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 3aa63aeeb..aa13bdc3d 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -55,6 +55,24 @@ object Checking { def checkBounds(args: List[tpd.Tree], poly: GenericType)(implicit ctx: Context): Unit = checkBounds(args, poly.paramBounds, _.substParams(poly, _)) + /** If type is a higher-kinded application with wildcard arguments, + * check that it or one of its supertypes can be reduced to a normal application. + * Unreducible applications correspond to general existentials, and we + * cannot handle those. + */ + def checkWildcardHKApply(tp: Type, pos: Position)(implicit ctx: Context): Unit = tp match { + case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) => + tycon match { + case tycon: TypeLambda => + ctx.errorOrMigrationWarning( + d"unreducible application of higher-kinded type $tycon to wildcard arguments", + pos) + case _ => + checkWildcardHKApply(tp.superType, pos) + } + case _ => + } + /** Traverse type tree, performing the following checks: * 1. All arguments of applied type trees must conform to their bounds. * 2. Prefixes of type selections and singleton types must be realizable. @@ -74,6 +92,10 @@ object Checking { val bounds = tparams.map(tparam => tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds) checkBounds(args, bounds, _.substDealias(tparams, _)) + + def checkValidIfHKApply(implicit ctx: Context): Unit = + checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos) + checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) case Select(qual, name) if name.isTypeName => checkRealizable(qual.tpe, qual.pos) case SelectFromTypeTree(qual, name) if name.isTypeName => diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index f98b8114c..4361ccc13 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -29,7 +29,6 @@ class tests extends CompilerTest { else List("-Ycheck:tailrec,resolveSuper,mixin,restoreScopes,labelDef") } - val testPickling = List("-Xprint-types", "-Ytest-pickler", "-Ystop-after:pickler") val twice = List("#runs", "2") diff --git a/tests/neg/existentials.scala b/tests/neg/existentials.scala new file mode 100644 index 000000000..4798504d9 --- /dev/null +++ b/tests/neg/existentials.scala @@ -0,0 +1,61 @@ +object TestList { + + var x: ([X] -> List[List[X]])[_] = List(List(1)) // error: unreducible + var y: ([X] -> List[Seq[X]])[_] = List(List(1)) // error: unreducible + + x = x + y = y + y = x + + val h = x.head + val x1: List[_] = h + + var z: List[_] = x + +} +object TestSet { + + var x: ([Y] -> Set[Set[Y]])[_] = Set(Set("a")) // error: unreducible + var y: ([Y] -> Set[Iterable[Y]])[_] = Set(Set("a")) // error: unreducible + + x = x + y = y + + val h = x.head + val h1: Set[_] = h + + // val p = x.+ // infinite loop in implicit search + + var z: Set[_] = x + +} +class TestX { + + class C[T](x: T) { + def get: T = x + def cmp: T => Boolean = (x == _) + } + + val x: ([Y] -> C[C[Y]])[_] = new C(new C("a")) // error: unreducible + + type CC[X] = C[C[X]] + val y: CC[_] = ??? // error: unreducible + + type D[X] <: C[X] + + type DD = [X] -> D[D[X]] + val z: DD[_] = ??? // error: unreducible + + val g = x.get + + val c = x.cmp +} + +object Test6014 { + case class CC[T](key: T) + type Alias[T] = Seq[CC[T]] + + def f(xs: Seq[CC[_]]) = xs map { case CC(x) => CC(x) } // ok + def g(xs: Alias[_]) = xs map { case CC(x) => CC(x) } // error: unreducible application +} + diff --git a/tests/pos-scala2/GenTraversableFactory.scala b/tests/pos-scala2/GenTraversableFactory.scala new file mode 100644 index 000000000..2f93ab27b --- /dev/null +++ b/tests/pos-scala2/GenTraversableFactory.scala @@ -0,0 +1,252 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + +package scala +package collection +package generic + +import scala.language.higherKinds + +/** A template for companion objects of `Traversable` and subclasses thereof. + * This class provides a set of operations to create `$Coll` objects. + * It is typically inherited by companion objects of subclasses of `Traversable`. + * + * @since 2.8 + * + * @define coll collection + * @define Coll `Traversable` + * @define factoryInfo + * This object provides a set of operations to create `$Coll` values. + * @author Martin Odersky + * @version 2.8 + * @define canBuildFromInfo + * The standard `CanBuildFrom` instance for $Coll objects. + * @see CanBuildFrom + * @define genericCanBuildFromInfo + * The standard `CanBuildFrom` instance for $Coll objects. + * The created value is an instance of class `GenericCanBuildFrom`, + * which forwards calls to create a new builder to the + * `genericBuilder` method of the requesting collection. + * @see CanBuildFrom + * @see GenericCanBuildFrom + */ +abstract class GenTraversableFactory[CC[X] <: GenTraversable[X] with GenericTraversableTemplate[X, CC]] +extends GenericCompanion[CC] { + + private[this] val ReusableCBFInstance: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { + override def apply() = newBuilder[Nothing] + } + def ReusableCBF: GenericCanBuildFrom[Nothing] = ReusableCBFInstance + + /** A generic implementation of the `CanBuildFrom` trait, which forwards + * all calls to `apply(from)` to the `genericBuilder` method of + * $coll `from`, and which forwards all calls of `apply()` to the + * `newBuilder` method of this factory. + */ + class GenericCanBuildFrom[A] extends CanBuildFrom[CC[_], A, CC[A]] { + /** Creates a new builder on request of a collection. + * @param from the collection requesting the builder to be created. + * @return the result of invoking the `genericBuilder` method on `from`. + */ + def apply(from: Coll) = from.genericBuilder[A] + + /** Creates a new builder from scratch + * @return the result of invoking the `newBuilder` method of this factory. + */ + def apply() = newBuilder[A] + } + + /** Concatenates all argument collections into a single $coll. + * + * @param xss the collections that are to be concatenated. + * @return the concatenation of all the collections. + */ + def concat[A](xss: Traversable[A]*): CC[A] = { + val b = newBuilder[A] + // At present we're using IndexedSeq as a proxy for "has a cheap size method". + if (xss forall (_.isInstanceOf[IndexedSeq[_]])) + b.sizeHint(xss.map(_.size).sum) + + for (xs <- xss.seq) b ++= xs + b.result() + } + + /** Produces a $coll containing the results of some element computation a number of times. + * @param n the number of elements contained in the $coll. + * @param elem the element computation + * @return A $coll that contains the results of `n` evaluations of `elem`. + */ + def fill[A](n: Int)(elem: => A): CC[A] = { + val b = newBuilder[A] + b.sizeHint(n) + var i = 0 + while (i < n) { + b += elem + i += 1 + } + b.result() + } + + /** Produces a two-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param elem the element computation + * @return A $coll that contains the results of `n1 x n2` evaluations of `elem`. + */ + def fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A]] = + tabulate(n1)(_ => fill(n2)(elem)) + + /** Produces a three-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param elem the element computation + * @return A $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`. + */ + def fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]]] = + tabulate(n1)(_ => fill(n2, n3)(elem)) + + /** Produces a four-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param elem the element computation + * @return A $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`. + */ + def fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]]] = + tabulate(n1)(_ => fill(n2, n3, n4)(elem)) + + /** Produces a five-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param elem the element computation + * @return A $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`. + */ + def fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]]] = + tabulate(n1)(_ => fill(n2, n3, n4, n5)(elem)) + + /** Produces a $coll containing values of a given function over a range of integer values starting from 0. + * @param n The number of elements in the $coll + * @param f The function computing element values + * @return A $coll consisting of elements `f(0), ..., f(n -1)` + */ + def tabulate[A](n: Int)(f: Int => A): CC[A] = { + val b = newBuilder[A] + b.sizeHint(n) + var i = 0 + while (i < n) { + b += f(i) + i += 1 + } + b.result() + } + + /** Produces a two-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param f The function computing element values + * @return A $coll consisting of elements `f(i1, i2)` + * for `0 <= i1 < n1` and `0 <= i2 < n2`. + */ + def tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A]] = + tabulate(n1)(i1 => tabulate(n2)(f(i1, _))) + + /** Produces a three-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param f The function computing element values + * @return A $coll consisting of elements `f(i1, i2, i3)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`. + */ + def tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]]] = + tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))) + + /** Produces a four-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param f The function computing element values + * @return A $coll consisting of elements `f(i1, i2, i3, i4)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, and `0 <= i4 < n4`. + */ + def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))) + + /** Produces a five-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3nd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param f The function computing element values + * @return A $coll consisting of elements `f(i1, i2, i3, i4, i5)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, `0 <= i4 < n4`, and `0 <= i5 < n5`. + */ + def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))) + + /** Produces a $coll containing a sequence of increasing of integers. + * + * @param start the first element of the $coll + * @param end the end value of the $coll (the first value NOT contained) + * @return a $coll with values `start, start + 1, ..., end - 1` + */ + def range[T: Integral](start: T, end: T): CC[T] = range(start, end, implicitly[Integral[T]].one) + + /** Produces a $coll containing equally spaced values in some integer interval. + * @param start the start value of the $coll + * @param end the end value of the $coll (the first value NOT contained) + * @param step the difference between successive elements of the $coll (must be positive or negative) + * @return a $coll with values `start, start + step, ...` up to, but excluding `end` + */ + def range[T: Integral](start: T, end: T, step: T): CC[T] = { + val num = implicitly[Integral[T]] + import num._ + + if (step == zero) throw new IllegalArgumentException("zero step") + val b = newBuilder[T] + b sizeHint immutable.NumericRange.count(start, end, step, isInclusive = false) + var i = start + while (if (/*num.mkOrderingOps*/(step) < zero) end < i else i < end) { + b += i + i += step + } + b.result() + } + + /** Produces a $coll containing repeated applications of a function to a start value. + * + * @param start the start value of the $coll + * @param len the number of elements contained inthe $coll + * @param f the function that's repeatedly applied + * @return a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` + */ + def iterate[A](start: A, len: Int)(f: A => A): CC[A] = { + val b = newBuilder[A] + if (len > 0) { + b.sizeHint(len) + var acc = start + var i = 1 + b += acc + + while (i < len) { + acc = f(acc) + i += 1 + b += acc + } + } + b.result() + } +} diff --git a/tests/pos-scala2/t6014.scala b/tests/pos-scala2/t6014.scala new file mode 100644 index 000000000..02535f377 --- /dev/null +++ b/tests/pos-scala2/t6014.scala @@ -0,0 +1,13 @@ +object Test { + case class CC[T](key: T) + type Alias[T] = Seq[CC[T]] + + def f(xs: Seq[CC[_]]) = xs map { case CC(x) => CC(x) } // ok + def g(xs: Alias[_]) = xs map { case CC(x) => CC(x) } // migration warning: unreducible application + // ./a.scala:11: error: missing parameter type for expanded function + // The argument types of an anonymous function must be fully known. (SLS 8.5) + // Expected type was: ? + // def g(xs: Alias[_]) = xs map { case CC(x) => CC(x) } // fails + // ^ + // one error found +} diff --git a/tests/pos/GenTraversableFactory.scala b/tests/pos/GenTraversableFactory.scala deleted file mode 100644 index 2f93ab27b..000000000 --- a/tests/pos/GenTraversableFactory.scala +++ /dev/null @@ -1,252 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala -package collection -package generic - -import scala.language.higherKinds - -/** A template for companion objects of `Traversable` and subclasses thereof. - * This class provides a set of operations to create `$Coll` objects. - * It is typically inherited by companion objects of subclasses of `Traversable`. - * - * @since 2.8 - * - * @define coll collection - * @define Coll `Traversable` - * @define factoryInfo - * This object provides a set of operations to create `$Coll` values. - * @author Martin Odersky - * @version 2.8 - * @define canBuildFromInfo - * The standard `CanBuildFrom` instance for $Coll objects. - * @see CanBuildFrom - * @define genericCanBuildFromInfo - * The standard `CanBuildFrom` instance for $Coll objects. - * The created value is an instance of class `GenericCanBuildFrom`, - * which forwards calls to create a new builder to the - * `genericBuilder` method of the requesting collection. - * @see CanBuildFrom - * @see GenericCanBuildFrom - */ -abstract class GenTraversableFactory[CC[X] <: GenTraversable[X] with GenericTraversableTemplate[X, CC]] -extends GenericCompanion[CC] { - - private[this] val ReusableCBFInstance: GenericCanBuildFrom[Nothing] = new GenericCanBuildFrom[Nothing] { - override def apply() = newBuilder[Nothing] - } - def ReusableCBF: GenericCanBuildFrom[Nothing] = ReusableCBFInstance - - /** A generic implementation of the `CanBuildFrom` trait, which forwards - * all calls to `apply(from)` to the `genericBuilder` method of - * $coll `from`, and which forwards all calls of `apply()` to the - * `newBuilder` method of this factory. - */ - class GenericCanBuildFrom[A] extends CanBuildFrom[CC[_], A, CC[A]] { - /** Creates a new builder on request of a collection. - * @param from the collection requesting the builder to be created. - * @return the result of invoking the `genericBuilder` method on `from`. - */ - def apply(from: Coll) = from.genericBuilder[A] - - /** Creates a new builder from scratch - * @return the result of invoking the `newBuilder` method of this factory. - */ - def apply() = newBuilder[A] - } - - /** Concatenates all argument collections into a single $coll. - * - * @param xss the collections that are to be concatenated. - * @return the concatenation of all the collections. - */ - def concat[A](xss: Traversable[A]*): CC[A] = { - val b = newBuilder[A] - // At present we're using IndexedSeq as a proxy for "has a cheap size method". - if (xss forall (_.isInstanceOf[IndexedSeq[_]])) - b.sizeHint(xss.map(_.size).sum) - - for (xs <- xss.seq) b ++= xs - b.result() - } - - /** Produces a $coll containing the results of some element computation a number of times. - * @param n the number of elements contained in the $coll. - * @param elem the element computation - * @return A $coll that contains the results of `n` evaluations of `elem`. - */ - def fill[A](n: Int)(elem: => A): CC[A] = { - val b = newBuilder[A] - b.sizeHint(n) - var i = 0 - while (i < n) { - b += elem - i += 1 - } - b.result() - } - - /** Produces a two-dimensional $coll containing the results of some element computation a number of times. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param elem the element computation - * @return A $coll that contains the results of `n1 x n2` evaluations of `elem`. - */ - def fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A]] = - tabulate(n1)(_ => fill(n2)(elem)) - - /** Produces a three-dimensional $coll containing the results of some element computation a number of times. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param elem the element computation - * @return A $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`. - */ - def fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]]] = - tabulate(n1)(_ => fill(n2, n3)(elem)) - - /** Produces a four-dimensional $coll containing the results of some element computation a number of times. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param n4 the number of elements in the 4th dimension - * @param elem the element computation - * @return A $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`. - */ - def fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]]] = - tabulate(n1)(_ => fill(n2, n3, n4)(elem)) - - /** Produces a five-dimensional $coll containing the results of some element computation a number of times. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param n4 the number of elements in the 4th dimension - * @param n5 the number of elements in the 5th dimension - * @param elem the element computation - * @return A $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`. - */ - def fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]]] = - tabulate(n1)(_ => fill(n2, n3, n4, n5)(elem)) - - /** Produces a $coll containing values of a given function over a range of integer values starting from 0. - * @param n The number of elements in the $coll - * @param f The function computing element values - * @return A $coll consisting of elements `f(0), ..., f(n -1)` - */ - def tabulate[A](n: Int)(f: Int => A): CC[A] = { - val b = newBuilder[A] - b.sizeHint(n) - var i = 0 - while (i < n) { - b += f(i) - i += 1 - } - b.result() - } - - /** Produces a two-dimensional $coll containing values of a given function over ranges of integer values starting from 0. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param f The function computing element values - * @return A $coll consisting of elements `f(i1, i2)` - * for `0 <= i1 < n1` and `0 <= i2 < n2`. - */ - def tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A]] = - tabulate(n1)(i1 => tabulate(n2)(f(i1, _))) - - /** Produces a three-dimensional $coll containing values of a given function over ranges of integer values starting from 0. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param f The function computing element values - * @return A $coll consisting of elements `f(i1, i2, i3)` - * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`. - */ - def tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]]] = - tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))) - - /** Produces a four-dimensional $coll containing values of a given function over ranges of integer values starting from 0. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param n4 the number of elements in the 4th dimension - * @param f The function computing element values - * @return A $coll consisting of elements `f(i1, i2, i3, i4)` - * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, and `0 <= i4 < n4`. - */ - def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]]] = - tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))) - - /** Produces a five-dimensional $coll containing values of a given function over ranges of integer values starting from 0. - * @param n1 the number of elements in the 1st dimension - * @param n2 the number of elements in the 2nd dimension - * @param n3 the number of elements in the 3nd dimension - * @param n4 the number of elements in the 4th dimension - * @param n5 the number of elements in the 5th dimension - * @param f The function computing element values - * @return A $coll consisting of elements `f(i1, i2, i3, i4, i5)` - * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, `0 <= i4 < n4`, and `0 <= i5 < n5`. - */ - def tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]]] = - tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))) - - /** Produces a $coll containing a sequence of increasing of integers. - * - * @param start the first element of the $coll - * @param end the end value of the $coll (the first value NOT contained) - * @return a $coll with values `start, start + 1, ..., end - 1` - */ - def range[T: Integral](start: T, end: T): CC[T] = range(start, end, implicitly[Integral[T]].one) - - /** Produces a $coll containing equally spaced values in some integer interval. - * @param start the start value of the $coll - * @param end the end value of the $coll (the first value NOT contained) - * @param step the difference between successive elements of the $coll (must be positive or negative) - * @return a $coll with values `start, start + step, ...` up to, but excluding `end` - */ - def range[T: Integral](start: T, end: T, step: T): CC[T] = { - val num = implicitly[Integral[T]] - import num._ - - if (step == zero) throw new IllegalArgumentException("zero step") - val b = newBuilder[T] - b sizeHint immutable.NumericRange.count(start, end, step, isInclusive = false) - var i = start - while (if (/*num.mkOrderingOps*/(step) < zero) end < i else i < end) { - b += i - i += step - } - b.result() - } - - /** Produces a $coll containing repeated applications of a function to a start value. - * - * @param start the start value of the $coll - * @param len the number of elements contained inthe $coll - * @param f the function that's repeatedly applied - * @return a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` - */ - def iterate[A](start: A, len: Int)(f: A => A): CC[A] = { - val b = newBuilder[A] - if (len > 0) { - b.sizeHint(len) - var acc = start - var i = 1 - b += acc - - while (i < len) { - acc = f(acc) - i += 1 - b += acc - } - } - b.result() - } -} diff --git a/tests/pos/t6014.scala b/tests/pos/t6014.scala deleted file mode 100644 index 26e258a27..000000000 --- a/tests/pos/t6014.scala +++ /dev/null @@ -1,13 +0,0 @@ -object Test { - case class CC[T](key: T) - type Alias[T] = Seq[CC[T]] - - def f(xs: Seq[CC[_]]) = xs map { case CC(x) => CC(x) } // ok - def g(xs: Alias[_]) = xs map { case CC(x) => CC(x) } // fails - // ./a.scala:11: error: missing parameter type for expanded function - // The argument types of an anonymous function must be fully known. (SLS 8.5) - // Expected type was: ? - // def g(xs: Alias[_]) = xs map { case CC(x) => CC(x) } // fails - // ^ - // one error found -} -- cgit v1.2.3