diff options
26 files changed, 228 insertions, 66 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 0d13623e0c..0ac46a18bc 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -285,7 +285,7 @@ abstract class TreeBuilder { def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = { val pat1 = patvarTransformer.transform(pat) val rhs1 = - if (valeq || treeInfo.isVariablePattern(pat)) rhs + if (valeq || treeInfo.isVarPatternDeep(pat)) rhs else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING) if (valeq) ValEq(pos, pat1, rhs1) diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 6cc957a9eb..6f3d7932a5 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -173,9 +173,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { List(This(currentOwner))) val extensionCall = atOwner(origMeth) { localTyper.typedPos(rhs.pos) { - (extensionCallPrefix /: vparamss) { - case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) - } + gen.mkForwarder(extensionCallPrefix, mmap(vparamss)(_.symbol)) } } deriveDefDef(tree)(_ => extensionCall) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 5beba77155..938866deef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -417,7 +417,17 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder) val treeMaker = TypeTestTreeMaker(patBinder, patBinder, extractor.paramType, extractor.paramType)(pos, extractorArgTypeTest = true) (List(treeMaker), treeMaker.nextBinder) - } else (Nil, patBinder) + } else { + // no type test needed, but the tree maker relies on `patBinderOrCasted` having type `extractor.paramType` (and not just some type compatible with it) + // SI-6624 shows this is necessary because apparently patBinder may have an unfortunate type (.decls don't have the case field accessors) + // TODO: get to the bottom of this -- I assume it happens when type checking infers a weird type for an unapply call + // by going back to the parameterType for the extractor call we get a saner type, so let's just do that for now + /* TODO: uncomment when `settings.developer` and `devWarning` become available + if (settings.developer.value && !(patBinder.info =:= extractor.paramType)) + devWarning(s"resetting info of $patBinder: ${patBinder.info} to ${extractor.paramType}") + */ + (Nil, patBinder setInfo extractor.paramType) + } withSubPats(typeTestTreeMaker :+ extractor.treeMaker(patBinderOrCasted, pos), extractor.subBindersAndPatterns: _*) } diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index f72547724d..8be0cb1619 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -120,7 +120,7 @@ case class StringContext(parts: String*) { val bldr = new java.lang.StringBuilder(process(pi.next())) while (ai.hasNext) { bldr append ai.next - bldr append treatEscapes(pi.next()) + bldr append process(pi.next()) } bldr.toString } diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index 8d1fa80815..540bd84b79 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -171,7 +171,7 @@ self => * fewer elements than size. */ def sliding(size: Int): Iterator[Repr] = sliding(size, 1) - + /** Groups elements in fixed size blocks by passing a "sliding window" * over them (as opposed to partitioning them, as is done in grouped.) * @see [[scala.collection.Iterator]], method `sliding` @@ -293,7 +293,6 @@ self => override /*TraversableLike*/ def view = new IterableView[A, Repr] { protected lazy val underlying = self.repr - override def isEmpty = self.isEmpty override def iterator = self.iterator } diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 0ffd99c88c..6871a3cb73 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -630,7 +630,6 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ override def view = new SeqView[A, Repr] { protected lazy val underlying = self.repr - override def isEmpty = self.isEmpty override def iterator = self.iterator override def length = self.length override def apply(idx: Int) = self.apply(idx) diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index fc7202b96b..5f193eb211 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -86,7 +86,7 @@ trait TraversableLike[+A, +Repr] extends Any def repr: Repr = this.asInstanceOf[Repr] final def isTraversableAgain: Boolean = true - + /** The underlying collection seen as an instance of `$Coll`. * By default this is implemented as the current collection object itself, * but this can be overridden. @@ -174,7 +174,7 @@ trait TraversableLike[+A, +Repr] extends Any * * @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B] * @inheritdoc - * + * * Example: * {{{ * scala> val x = List(1) @@ -660,7 +660,6 @@ trait TraversableLike[+A, +Repr] extends Any def view = new TraversableView[A, Repr] { protected lazy val underlying = self.repr override def foreach[U](f: A => U) = self foreach f - override def isEmpty = self.isEmpty } /** Creates a non-strict view of a slice of this $coll. diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 0925fe4770..14f865c2f0 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -59,7 +59,7 @@ trait ViewMkString[+A] { * $viewInfo * * All views for traversable collections are defined by creating a new `foreach` method. - * + * * @author Martin Odersky * @version 2.8 * @since 2.8 @@ -162,7 +162,7 @@ trait TraversableViewLike[+A, // if (b.isInstanceOf[NoBuilder[_]]) newFlatMapped(f).asInstanceOf[That] // else super.flatMap[B, That](f)(bf) } - override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]) = + override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]) = newFlatMapped(asTraversable) private[this] implicit def asThis(xs: Transformed[A]): This = xs.asInstanceOf[This] @@ -193,15 +193,6 @@ trait TraversableViewLike[+A, override def span(p: A => Boolean): (This, This) = (newTakenWhile(p), newDroppedWhile(p)) override def splitAt(n: Int): (This, This) = (newTaken(n), newDropped(n)) - // Without this, isEmpty tests go back to the Traversable default, which - // involves starting a foreach, which can force the first element of the - // view. This is just a backstop - it's overridden at all the "def view" - // instantiation points in the collections where the Coll type is known. - override def isEmpty = underlying match { - case x: GenTraversableOnce[_] => x.isEmpty - case _ => super.isEmpty - } - override def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[This, B, That]): That = newForced(thisSeq.scanLeft(z)(op)).asInstanceOf[That] diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 426ab6f0fb..be2cd91c68 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -937,7 +937,6 @@ self => override def view = new StreamView[A, Stream[A]] { protected lazy val underlying = self.repr - override def isEmpty = self.isEmpty override def iterator = self.iterator override def length = self.length override def apply(idx: Int) = self.apply(idx) diff --git a/src/library/scala/collection/mutable/IndexedSeqLike.scala b/src/library/scala/collection/mutable/IndexedSeqLike.scala index 21cff70473..f0c31ec7fb 100644 --- a/src/library/scala/collection/mutable/IndexedSeqLike.scala +++ b/src/library/scala/collection/mutable/IndexedSeqLike.scala @@ -53,7 +53,6 @@ trait IndexedSeqLike[A, +Repr] extends Any with scala.collection.IndexedSeqLike[ */ override def view = new IndexedSeqView[A, Repr] { protected lazy val underlying = self.repr - override def isEmpty = self.isEmpty override def iterator = self.iterator override def length = self.length override def apply(idx: Int) = self.apply(idx) diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 9825587b0e..0f06ff37af 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -171,9 +171,9 @@ self: ParIterableLike[T, Repr, Sequential] => /** The task support object which is responsible for scheduling and * load-balancing tasks to processors. - * + * * @see [[scala.collection.parallel.TaskSupport]] - */ + */ def tasksupport = { val ts = _tasksupport if (ts eq null) { @@ -188,18 +188,18 @@ self: ParIterableLike[T, Repr, Sequential] => * A task support object can be changed in a parallel collection after it * has been created, but only during a quiescent period, i.e. while there * are no concurrent invocations to parallel collection methods. - * - * Here is a way to change the task support of a parallel collection: - * - * {{{ - * import scala.collection.parallel._ - * val pc = mutable.ParArray(1, 2, 3) - * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) - * }}} + * + * Here is a way to change the task support of a parallel collection: + * + * {{{ + * import scala.collection.parallel._ + * val pc = mutable.ParArray(1, 2, 3) + * pc.tasksupport = new ForkJoinTaskSupport( + * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * }}} * * @see [[scala.collection.parallel.TaskSupport]] - */ + */ def tasksupport_=(ts: TaskSupport) = _tasksupport = ts def seq: Sequential @@ -848,7 +848,6 @@ self: ParIterableLike[T, Repr, Sequential] => override def seq = self.seq.view def splitter = self.splitter def size = splitter.remaining - override def isEmpty = size == 0 } override def toArray[U >: T: ClassTag]: Array[U] = { @@ -878,13 +877,13 @@ self: ParIterableLike[T, Repr, Sequential] => override def toSet[U >: T]: immutable.ParSet[U] = toParCollection[U, immutable.ParSet[U]](() => immutable.ParSet.newCombiner[U]) override def toMap[K, V](implicit ev: T <:< (K, V)): immutable.ParMap[K, V] = toParMap[K, V, immutable.ParMap[K, V]](() => immutable.ParMap.newCombiner[K, V]) - + override def toVector: Vector[T] = to[Vector] override def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, T, Col[T @uncheckedVariance]]): Col[T @uncheckedVariance] = if (cbf().isCombiner) { toParCollection[T, Col[T]](() => cbf().asCombiner) } else seq.to(cbf) - + /* tasks */ protected trait StrictSplitterCheckTask[R, Tp] extends Task[R, Tp] { diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala index 4f1c3fa7a2..201b624c72 100644 --- a/src/library/scala/collection/parallel/ParSeqLike.scala +++ b/src/library/scala/collection/parallel/ParSeqLike.scala @@ -44,7 +44,7 @@ trait ParSeqLike[+T, +Repr <: ParSeq[T], +Sequential <: Seq[T] with SeqLike[T, S extends scala.collection.GenSeqLike[T, Repr] with ParIterableLike[T, Repr, Sequential] { self => - + type SuperParIterator = IterableSplitter[T] /** A more refined version of the iterator found in the `ParallelIterable` trait, @@ -330,7 +330,6 @@ self => def apply(idx: Int) = self(idx) override def seq = self.seq.view def splitter = self.splitter - override def isEmpty = size == 0 } /* tasks */ diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index f7c732b851..3e849f1722 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -29,13 +29,12 @@ package object concurrent { */ def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body) - /** Creates a promise object which can be completed with a value. + /** Creates a promise object which can be completed with a value or an exception. * * @tparam T the type of the value in the promise - * @param execctx the execution context on which the promise is created on * @return the newly created `Promise` object */ - def promise[T]()(implicit execctx: ExecutionContext): Promise[T] = Promise[T]() + def promise[T](): Promise[T] = Promise[T]() /** Used to designate a piece of code which potentially blocks, allowing the current [[BlockContext]] to adjust * the runtime's behavior. diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 38e55a3c01..8ad15f37e4 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -245,6 +245,68 @@ abstract class TreeInfo { isSelfConstrCall(tree1) || isSuperConstrCall(tree1) } + /** + * Does this tree represent an irrefutable pattern match + * in the position `for { <tree> <- expr }` based only + * on information at the `parser` phase? To qualify, there + * may be no subtree that will be interpreted as a + * Stable Identifier Pattern. + * + * For instance: + * + * {{{ + * foo @ (bar, (baz, quux)) + * }}} + * + * is a variable pattern; if the structure matches, + * then the remainder is inevitable. + * + * The following are not variable patterns. + * + * {{{ + * foo @ (bar, (`baz`, quux)) // back quoted ident, not at top level + * foo @ (bar, Quux) // UpperCase ident, not at top level + * }}} + * + * If the pattern is a simple identifier, it is always + * a variable pattern. For example, the following + * introduce new bindings: + * + * {{{ + * for { X <- xs } yield X + * for { `backquoted` <- xs } yield `backquoted` + * }}} + * + * Note that this differs from a case clause: + * + * {{{ + * object X + * scrut match { + * case X => // case _ if scrut == X + * } + * }}} + * + * Background: [[https://groups.google.com/d/msg/scala-internals/qwa_XOw_7Ks/IktkeTBYqg0J]] + * + */ + def isVarPatternDeep(tree: Tree): Boolean = { + def isVarPatternDeep0(tree: Tree): Boolean = { + tree match { + case Bind(name, pat) => isVarPatternDeep0(pat) + case Ident(name) => isVarPattern(tree) + case Apply(sel, args) => + ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) + && (args forall isVarPatternDeep0) + ) + case _ => false + } + } + tree match { + case Ident(name) => true + case _ => isVarPatternDeep0(tree) + } + } + /** Is tree a variable pattern? */ def isVarPattern(pat: Tree): Boolean = pat match { case x: Ident => !x.isBackquoted && nme.isVariableName(x.name) @@ -330,24 +392,6 @@ abstract class TreeInfo { case _ => false } - /** Is this tree comprised of nothing but identifiers, - * but possibly in bindings or tuples? For instance - * - * foo @ (bar, (baz, quux)) - * - * is a variable pattern; if the structure matches, - * then the remainder is inevitable. - */ - def isVariablePattern(tree: Tree): Boolean = tree match { - case Bind(name, pat) => isVariablePattern(pat) - case Ident(name) => true - case Apply(sel, args) => - ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) - && (args forall isVariablePattern) - ) - case _ => false - } - /** Is this argument node of the form <expr> : _* ? */ def isWildcardStarArg(tree: Tree): Boolean = tree match { diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 53b40da8f6..b8f5e73acb 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -482,6 +482,10 @@ trait Trees extends api.Trees { self: SymbolTable => case class TypeTree() extends TypTree with TypeTreeContextApi { private var orig: Tree = null + /** Was this type tree originally empty? That is, does it now contain + * an inferred type that must be forgotten in `resetAttrs` to + * enable retyping. + */ private[scala] var wasEmpty: Boolean = false override def symbol = typeTreeSymbol(this) // if (tpe == null) null else tpe.typeSymbol @@ -502,6 +506,15 @@ trait Trees extends api.Trees { self: SymbolTable => wasEmpty = isEmpty setType(tp) } + + override private[scala] def copyAttrs(tree: Tree) = { + super.copyAttrs(tree) + tree match { + case other: TypeTree => wasEmpty = other.wasEmpty // SI-6648 Critical for correct operation of `resetAttrs`. + case _ => + } + this + } } object TypeTree extends TypeTreeExtractor diff --git a/test/files/pos/t6624.scala b/test/files/pos/t6624.scala new file mode 100644 index 0000000000..1a92b92d53 --- /dev/null +++ b/test/files/pos/t6624.scala @@ -0,0 +1,28 @@ +sealed trait KList[+M[_]] + +case class KCons[M[_], +T <: KList[M]]( + tail: T +) extends KList[M] + +case class KNil[M[_]]() extends KList[M] + +object Test { + val klist: KCons[Option, KCons[Option, KCons[Option, KNil[Nothing]]]] = ??? + + // crashes with + // "Exception in thread "main" scala.reflect.internal.Types$TypeError: value _1 is not a member + // of KCons[Option,KCons[Option,KNil[Nothing]]]" + klist match { + case KCons(KCons(KCons(_))) => + } + + // fails with a similar message as an error, rather than a crash. + klist match { + case KCons(KCons(_)) => + } + + // succeeds + klist match { + case KCons(_) => + } +}
\ No newline at end of file diff --git a/test/files/pos/t6648.scala b/test/files/pos/t6648.scala new file mode 100644 index 0000000000..9593ebfee9 --- /dev/null +++ b/test/files/pos/t6648.scala @@ -0,0 +1,24 @@ +abstract class Node extends NodeSeq +trait NodeSeq extends Seq[Node] +object NodeSeq { + implicit def seqToNodeSeq(ns: Seq[Node]): NodeSeq = ??? + def foo[B, That](f: Seq[B])(implicit bf: scala.collection.generic.CanBuildFrom[Seq[Int], B, That]): That = ??? +} + +class Transformer { + def apply(nodes: Any): Any = ??? +} + +object transformer1 extends Transformer { + // Adding explicit type arguments, or making the impilcit view + // seqToNodeSeq explicit avoids the crash + NodeSeq.foo { + // These both avoid the crash: + // val t = new Transformer {}; t.apply(null) + // new Transformer().apply(null) + new Transformer {}.apply(null) + + null: NodeSeq + }: NodeSeq +} + diff --git a/test/files/run/rawstrings.check b/test/files/run/rawstrings.check index 36e63594df..2b6c40725a 100644 --- a/test/files/run/rawstrings.check +++ b/test/files/run/rawstrings.check @@ -1 +1 @@ -[\n\t'"$] +[\n\t'"$\n] diff --git a/test/files/run/rawstrings.scala b/test/files/run/rawstrings.scala index 9df64f6625..b4d6e0c40a 100644 --- a/test/files/run/rawstrings.scala +++ b/test/files/run/rawstrings.scala @@ -1,3 +1,3 @@ object Test extends App { - println(raw"[\n\t'${'"'}$$]") + println(raw"[\n\t'${'"'}$$\n]") } diff --git a/test/files/run/t6559.scala b/test/files/run/t6559.scala new file mode 100644 index 0000000000..5c671f7275 --- /dev/null +++ b/test/files/run/t6559.scala @@ -0,0 +1,17 @@ + +object Test { + + def main(args: Array[String]) = { + val one = "1" + val two = "2" + + val raw = raw"\n$one\n$two\n" + val escaped = s"\n$one\n$two\n" + val buggy = "\\n1\n2\n" + val correct = "\\n1\\n2\\n" + + assert(raw != escaped, "Raw strings should not be escaped.") + assert(raw != buggy, "Raw strings after variables should not be escaped.") + assert(raw == correct, "Raw strings should stay raw.") + } +} diff --git a/test/files/run/t6628.check b/test/files/run/t6628.check new file mode 100644 index 0000000000..bb101b641b --- /dev/null +++ b/test/files/run/t6628.check @@ -0,0 +1,2 @@ +true +true diff --git a/test/files/run/t6628.scala b/test/files/run/t6628.scala new file mode 100644 index 0000000000..84524a7a35 --- /dev/null +++ b/test/files/run/t6628.scala @@ -0,0 +1,11 @@ +object Test { + def coll = new Traversable[String] { + override def foreach[U](f:String=>U) { f("1") } + } + val dropped = coll.view drop 1 + + def main(args: Array[String]): Unit = { + println(dropped.isEmpty) + println(dropped.force.isEmpty) + } +} diff --git a/test/files/run/t6644.scala b/test/files/run/t6644.scala new file mode 100644 index 0000000000..b8b36f957c --- /dev/null +++ b/test/files/run/t6644.scala @@ -0,0 +1,8 @@ +class Testable(val c: String) extends AnyVal { + def matching(cases: Boolean*) = cases contains true +} + +object Test extends App { + assert(new Testable("").matching(true, false)) +} + diff --git a/test/files/run/t6646.check b/test/files/run/t6646.check new file mode 100644 index 0000000000..b0b7ad32f3 --- /dev/null +++ b/test/files/run/t6646.check @@ -0,0 +1,5 @@ +Found NotNull +Found lower +Found 2 +A single ident is always a pattern +A single ident is always a pattern diff --git a/test/files/run/t6646.scala b/test/files/run/t6646.scala new file mode 100644 index 0000000000..150b0df11e --- /dev/null +++ b/test/files/run/t6646.scala @@ -0,0 +1,19 @@ +sealed trait ColumnOption +case object NotNull extends ColumnOption +case object PrimaryKey extends ColumnOption +case object lower extends ColumnOption + +object Test { + def main(args: Array[String]) { + val l = List(PrimaryKey, NotNull, lower) + + // withFilter must be generated in these + for (option @ NotNull <- l) println("Found " + option) + for (option @ `lower` <- l) println("Found " + option) + for ((`lower`, i) <- l.zipWithIndex) println("Found " + i) + + // no withFilter + for (X <- List("A single ident is always a pattern")) println(X) + for (`x` <- List("A single ident is always a pattern")) println(`x`) + } +} diff --git a/tools/epfl-publish b/tools/epfl-publish index de5e17b13f..cdf18823a5 100755 --- a/tools/epfl-publish +++ b/tools/epfl-publish @@ -24,7 +24,7 @@ if [[ -z $publish_to ]]; then else echo "Publishing nightly build to $publish_to" # Archive Scala nightly distribution - rsync -az dists/archives/ "$publish_to/distributions" + rsync -az --exclude scala-latest-sources.tgz dists/archives/ "$publish_to/distributions" # only publish scaladoc nightly for trunk [[ $version == "master" ]] && rsync -az build/scaladoc/ "$publish_to/docs" # sbaz |