summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2013-02-27 15:22:50 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-02-27 15:22:50 -0800
commit65a5459b0c3ae7daa16a283733ff0070f3ef21ab (patch)
treec0f1e90291f282a46a4e898d725f6f8d9eb497af
parent4265ee8f3846262c778c0e1e6184b3a23f18ec2a (diff)
parent234d05d52b5a2985e53f9cb6877001b3c8fc780e (diff)
downloadscala-65a5459b0c3ae7daa16a283733ff0070f3ef21ab.tar.gz
scala-65a5459b0c3ae7daa16a283733ff0070f3ef21ab.tar.bz2
scala-65a5459b0c3ae7daa16a283733ff0070f3ef21ab.zip
Merge branch 2.10.1 into master
Conflicts: src/compiler/scala/tools/nsc/ast/Trees.scala src/library/scala/concurrent/impl/ExecutionContextImpl.scala
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala53
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala8
-rw-r--r--src/library/scala/collection/Iterator.scala2
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala30
-rwxr-xr-xsrc/library/scala/xml/Utility.scala2
-rw-r--r--test/files/jvm/t7146.check5
-rw-r--r--test/files/jvm/t7146.scala23
-rw-r--r--test/files/pos/t7180.scala13
-rw-r--r--test/files/run/resetattrs-this.check1
-rw-r--r--test/files/run/resetattrs-this.scala11
-rw-r--r--test/files/run/t6827.scala3
-rw-r--r--test/files/run/t7074.check9
-rw-r--r--test/files/run/t7074.scala15
15 files changed, 154 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index c8b878225e..ab6a400c63 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -342,18 +342,59 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
case tpt: TypeTree =>
if (tpt.original != null)
transform(tpt.original)
- else if (tpt.tpe != null && (tpt.wasEmpty || (tpt.tpe exists (tp => locals contains tp.typeSymbol)))) {
- tpt.duplicate.clearType()
+ else {
+ val refersToLocalSymbols = tpt.tpe != null && (tpt.tpe exists (tp => locals contains tp.typeSymbol))
+ val isInferred = tpt.wasEmpty
+ if (refersToLocalSymbols || isInferred) {
+ tpt.duplicate.clearType()
+ } else {
+ tpt
+ }
}
- else tree
+ // If one of the type arguments of a TypeApply gets reset to an empty TypeTree, then this means that:
+ // 1) It isn't empty now (tpt.tpe != null), but it was empty before (tpt.wasEmpty).
+ // 2) Thus, its argument got inferred during a preceding typecheck.
+ // 3) Thus, all its arguments were inferred (because scalac can only infer all or nothing).
+ // Therefore, we can safely erase the TypeApply altogether and have it inferred once again in a subsequent typecheck.
+ // UPD: Actually there's another reason for erasing a type behind the TypeTree
+ // is when this type refers to symbols defined in the tree being processed.
+ // These symbols will be erased, because we can't leave alive a type referring to them.
+ // Here we can only hope that everything will work fine afterwards.
case TypeApply(fn, args) if args map transform exists (_.isEmpty) =>
transform(fn)
- case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
+ case EmptyTree =>
tree
case _ =>
val dupl = tree.duplicate
- if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel))
- dupl.symbol = NoSymbol
+ // Typically the resetAttrs transformer cleans both symbols and types.
+ // However there are exceptions when we cannot erase symbols due to idiosyncrasies of the typer.
+ // vetoXXX local variables declared below describe the conditions under which we cannot erase symbols.
+ //
+ // The first reason to not erase symbols is the threat of non-idempotency (SI-5464).
+ // Here we take care of labels (SI-5562) and references to package classes (SI-5705).
+ // There are other non-idempotencies, but they are not worked around yet.
+ //
+ // The second reason has to do with the fact that resetAttrs itself has limited usefulness.
+ //
+ // First of all, why do we need resetAttrs? Gor one, it's absolutely required to move trees around.
+ // One cannot just take a typed tree from one lexical context and transplant it somewhere else.
+ // Most likely symbols defined by those trees will become borked and the compiler will blow up (SI-5797).
+ // To work around we just erase all symbols and types and then hope that we'll be able to correctly retypecheck.
+ // For ones who're not affected by scalac Stockholm syndrome, this might seem to be an extremely naive fix, but well...
+ //
+ // Of course, sometimes erasing everything won't work, because if a given identifier got resolved to something
+ // in one lexical scope, it can get resolved to something else.
+ //
+ // What do we do in these cases? Enter the workaround for the workaround: resetLocalAttrs, which only destroys
+ // locally defined symbols, but doesn't touch references to stuff declared outside of a given tree.
+ // That's what localOnly and vetoScope are for.
+ if (dupl.hasSymbol) {
+ val sym = dupl.symbol
+ val vetoScope = localOnly && !(locals contains sym)
+ val vetoLabel = keepLabels && sym.isLabel
+ val vetoThis = dupl.isInstanceOf[This] && sym.isPackageClass
+ if (!(vetoScope || vetoLabel || vetoThis)) dupl.symbol = NoSymbol
+ }
dupl.clearType()
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index a7e4006fbe..f0c2b05951 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -1039,6 +1039,9 @@ abstract class ClassfileParser {
for (n <- 0 until nClasses) {
// FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (SI-7065)
val cls = pool.getClassSymbol(in.nextChar.toInt)
+ // we call initialize due to the fact that we call Symbol.isMonomorphicType in addThrowsAnnotation
+ // and that method requires Symbol to be forced to give the right answers, see SI-7107 for details
+ cls.initialize
sym.addThrowsAnnotation(cls)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index c7a4d44588..b4ec90c53e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1003,7 +1003,7 @@ trait Implicits {
args foreach (getParts(_))
}
} else if (sym.isAliasType) {
- getParts(tp.dealias)
+ getParts(tp.normalize) // SI-7180 Normalize needed to expand HK type refs
} else if (sym.isAbstractType) {
getParts(tp.bounds.hi)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 77b0749c20..3c5e484105 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -929,6 +929,7 @@ trait Namers extends MethodSynthesis {
// to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods.
val module = clazz.sourceModule
for (cda <- module.attachments.get[ConstructorDefaultsAttachment]) {
+ debuglog(s"Storing the template namer in the ConstructorDefaultsAttachment of ${module.debugLocationString}.")
cda.companionModuleClassNamer = templateNamer
}
val classTp = ClassInfoType(parents, decls, clazz)
@@ -1250,8 +1251,11 @@ trait Namers extends MethodSynthesis {
// module's templateNamer to classAndNamerOfModule
module.attachments.get[ConstructorDefaultsAttachment] match {
// by martin: the null case can happen in IDE; this is really an ugly hack on top of an ugly hack but it seems to work
- // later by lukas: disabled when fixing SI-5975, i think it cannot happen anymore
- case Some(cda) /*if cma.companionModuleClassNamer == null*/ =>
+ case Some(cda) =>
+ if (cda.companionModuleClassNamer == null) {
+ debugwarn(s"SI-6576 The companion module namer for $meth was unexpectedly null")
+ return
+ }
val p = (cda.classWithDefault, cda.companionModuleClassNamer)
moduleNamer = Some(p)
p
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 77baad71d3..43db7c55e0 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -1109,7 +1109,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
* $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = {
- require(start >= 0 && start < xs.length, s"start $start out of range ${xs.length}")
+ require(start >= 0 && (start < xs.length || xs.length == 0), s"start $start out of range ${xs.length}")
var i = start
val end = start + math.min(len, xs.length - start)
while (i < end && hasNext) {
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 77625e381c..e4a0f464f9 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -19,16 +19,16 @@ import scala.util.control.NonFatal
private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContextExecutor {
+ // Placed here since the creation of the executor needs to read this val
+ private[this] val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler {
+ def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause)
+ }
val executor: Executor = es match {
case null => createExecutorService
case some => some
}
- private val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler {
- def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause)
- }
-
// Implement BlockContext on FJP threads
class DefaultThreadFactory(daemonic: Boolean) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory {
def wire[T <: Thread](thread: T): T = {
@@ -116,18 +116,18 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter:
private[concurrent] object ExecutionContextImpl {
final class AdaptedForkJoinTask(runnable: Runnable) extends ForkJoinTask[Unit] {
- final override def setRawResult(u: Unit): Unit = ()
- final override def getRawResult(): Unit = ()
- final override def exec(): Boolean = try { runnable.run(); true } catch {
- case anything: Throwable ⇒
- val t = Thread.currentThread
- t.getUncaughtExceptionHandler match {
- case null ⇒
- case some ⇒ some.uncaughtException(t, anything)
+ final override def setRawResult(u: Unit): Unit = ()
+ final override def getRawResult(): Unit = ()
+ final override def exec(): Boolean = try { runnable.run(); true } catch {
+ case anything: Throwable ⇒
+ val t = Thread.currentThread
+ t.getUncaughtExceptionHandler match {
+ case null ⇒
+ case some ⇒ some.uncaughtException(t, anything)
+ }
+ throw anything
+ }
}
- throw anything
- }
- }
def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = new ExecutionContextImpl(e, reporter)
def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutionContextExecutorService =
diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala
index 06fd46701a..fff27c6e30 100755
--- a/src/library/scala/xml/Utility.scala
+++ b/src/library/scala/xml/Utility.scala
@@ -64,7 +64,7 @@ object Utility extends AnyRef with parsing.TokenTests {
val key = md.key
val smaller = sort(md.filter { m => m.key < key })
val greater = sort(md.filter { m => m.key > key })
- smaller.copy(md.copy ( greater ))
+ smaller.foldRight (md copy greater) ((x, xs) => x copy xs)
}
/** Return the node with its attribute list sorted alphabetically
diff --git a/test/files/jvm/t7146.check b/test/files/jvm/t7146.check
new file mode 100644
index 0000000000..7c76040205
--- /dev/null
+++ b/test/files/jvm/t7146.check
@@ -0,0 +1,5 @@
+should be scala.concurrent.impl.ExecutionContextImpl == true
+should be scala.concurrent.forkjoin.ForkJoinPool == true
+should have non-null UncaughtExceptionHandler == true
+should be a scala.concurrent.impl.ExecutionContextImpl UncaughtExceptionHandler == true
+should just print out on uncaught == true
diff --git a/test/files/jvm/t7146.scala b/test/files/jvm/t7146.scala
new file mode 100644
index 0000000000..2bd03d6d02
--- /dev/null
+++ b/test/files/jvm/t7146.scala
@@ -0,0 +1,23 @@
+import java.util.concurrent.Executor
+import scala.concurrent._
+import scala.util.control.NoStackTrace
+
+object Test {
+ def main(args: Array[String]) {
+ println("should be scala.concurrent.impl.ExecutionContextImpl == " +
+ ExecutionContext.global.toString.startsWith("scala.concurrent.impl.ExecutionContextImpl"))
+ val i = ExecutionContext.global.asInstanceOf[{ def executor: Executor }]
+ println("should be scala.concurrent.forkjoin.ForkJoinPool == " +
+ i.executor.toString.startsWith("scala.concurrent.forkjoin.ForkJoinPool"))
+ val u = i.executor.
+ asInstanceOf[{ def getUncaughtExceptionHandler: Thread.UncaughtExceptionHandler }].
+ getUncaughtExceptionHandler
+ println("should have non-null UncaughtExceptionHandler == " + (u ne null))
+ println("should be a scala.concurrent.impl.ExecutionContextImpl UncaughtExceptionHandler == " +
+ u.toString.startsWith("scala.concurrent.impl.ExecutionContextImpl"))
+ print("should just print out on uncaught == ")
+ u.uncaughtException(Thread.currentThread, new Throwable {
+ override def printStackTrace() { println("true") }
+ })
+ }
+}
diff --git a/test/files/pos/t7180.scala b/test/files/pos/t7180.scala
new file mode 100644
index 0000000000..15582f6df3
--- /dev/null
+++ b/test/files/pos/t7180.scala
@@ -0,0 +1,13 @@
+trait Higher[F[_]]
+
+trait Box[A]
+object Box {
+ implicit def HigherBox = new Higher[Box] {}
+}
+
+object Foo {
+ val box = implicitly[Higher[Box]] // compiles fine !!!
+
+ type Bar[A] = Box[A]
+ val bar = implicitly[Higher[Bar]] // <-- this doesn't compile in 2.10.1-RC1, but does in 2.10.0 !!!
+}
diff --git a/test/files/run/resetattrs-this.check b/test/files/run/resetattrs-this.check
new file mode 100644
index 0000000000..27ba77ddaf
--- /dev/null
+++ b/test/files/run/resetattrs-this.check
@@ -0,0 +1 @@
+true
diff --git a/test/files/run/resetattrs-this.scala b/test/files/run/resetattrs-this.scala
new file mode 100644
index 0000000000..12afa3d712
--- /dev/null
+++ b/test/files/run/resetattrs-this.scala
@@ -0,0 +1,11 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val tb = cm.mkToolBox()
+ val tree = Select(This(cm.staticPackage("scala").moduleClass), newTermName("Predef"))
+ val ttree = tb.typeCheck(tree)
+ val rttree = tb.resetAllAttrs(ttree)
+ println(tb.eval(rttree) == Predef)
+} \ No newline at end of file
diff --git a/test/files/run/t6827.scala b/test/files/run/t6827.scala
index 7e8918e3dc..8e17af09e2 100644
--- a/test/files/run/t6827.scala
+++ b/test/files/run/t6827.scala
@@ -28,4 +28,7 @@ object Test extends App {
tryit("read -1", 0, -1)
tryit("invalid read 0", 30, 0)
tryit("invalid read -1", 30, -1)
+
+ // okay, see SI-7128
+ "...".toIterator.copyToArray(new Array[Char](0), 0, 0)
}
diff --git a/test/files/run/t7074.check b/test/files/run/t7074.check
new file mode 100644
index 0000000000..ab9cf11f16
--- /dev/null
+++ b/test/files/run/t7074.check
@@ -0,0 +1,9 @@
+<a/>
+<a b="2" c="3" d="1"/>
+<a b="2" c="4" d="1" e="3" f="5"/>
+<a b="5" c="4" d="3" e="2" f="1"/>
+<a b="1" c="2" d="3" e="4" f="5"/>
+<a a:b="2" a:c="3" a:d="1"/>
+<a a:b="2" a:c="4" a:d="1" a:e="3" a:f="5"/>
+<a a:b="5" a:c="4" a:d="3" a:e="2" a:f="1"/>
+<a a:b="1" a:c="2" a:d="3" a:e="4" a:f="5"/>
diff --git a/test/files/run/t7074.scala b/test/files/run/t7074.scala
new file mode 100644
index 0000000000..693a076a7a
--- /dev/null
+++ b/test/files/run/t7074.scala
@@ -0,0 +1,15 @@
+import scala.xml.Utility.sort
+
+object Test extends App {
+ println(sort(<a/>))
+ println(sort(<a d="1" b="2" c="3"/>))
+ println(sort(<a d="1" b="2" e="3" c="4" f="5"/>))
+ println(sort(<a f="1" e="2" d="3" c="4" b="5"/>))
+ println(sort(<a b="1" c="2" d="3" e="4" f="5"/>))
+
+ println(sort(<a a:d="1" a:b="2" a:c="3"/>))
+ println(sort(<a a:d="1" a:b="2" a:e="3" a:c="4" a:f="5"/>))
+ println(sort(<a a:f="1" a:e="2" a:d="3" a:c="4" a:b="5"/>))
+ println(sort(<a a:b="1" a:c="2" a:d="3" a:e="4" a:f="5"/>))
+}
+