summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Mirrors.scala9
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/JavaPlatform.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala22
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala141
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala10
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala14
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala9
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala9
-rw-r--r--src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala73
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala8
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala6
-rw-r--r--src/compiler/scala/tools/reflect/MacroImplementations.scala147
-rw-r--r--src/library/scala/StringContext.scala38
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala3
-rw-r--r--src/library/scala/collection/parallel/TaskSupport.scala2
-rw-r--r--src/library/scala/concurrent/BlockContext.scala81
-rw-r--r--src/library/scala/concurrent/ConcurrentPackageObject.scala34
-rw-r--r--src/library/scala/concurrent/DelayedLazyVal.scala5
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala74
-rw-r--r--src/library/scala/concurrent/Future.scala29
-rw-r--r--src/library/scala/concurrent/Promise.scala9
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala61
-rw-r--r--src/library/scala/concurrent/impl/Future.scala102
-rw-r--r--src/library/scala/concurrent/impl/Promise.scala34
-rw-r--r--src/library/scala/util/control/NonFatal.scala23
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala26
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala72
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala4
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala17
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala332
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala11
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala6
-rw-r--r--src/reflect/scala/reflect/makro/Universe.scala24
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala21
41 files changed, 938 insertions, 555 deletions
diff --git a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala
index 79fa07fdb4..ec970ee696 100644
--- a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala
+++ b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala
@@ -24,11 +24,14 @@ trait Mirrors {
else NoSymbol
}
+ private lazy val libraryClasspathLoader: ClassLoader = {
+ val classpath = platform.classPath.asURLs
+ ScalaClassLoader.fromURLs(classpath)
+ }
+
private def isJavaClass(path: String): Boolean =
try {
- val classpath = platform.classPath.asURLs
- var classLoader = ScalaClassLoader.fromURLs(classpath)
- Class.forName(path, true, classLoader)
+ Class.forName(path, true, libraryClasspathLoader)
true
} catch {
case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) =>
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index a34692f5e0..e70716885e 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -99,7 +99,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
/** Defines valid values for the `target` property. */
object Target extends PermissibleValue {
- val values = List("jvm-1.5", "msil")
+ val values = List("jvm-1.5", "jvm-1.6", "jvm-1.7", "msil")
}
/** Defines valid values for the `deprecation` and `unchecked` properties. */
diff --git a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
index 62885cc73d..80b0f640a4 100644
--- a/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
+++ b/src/compiler/scala/tools/nsc/backend/JavaPlatform.scala
@@ -44,7 +44,7 @@ trait JavaPlatform extends Platform {
else List(dependencyAnalysis)
private def classEmitPhase =
- if (settings.target.value == "jvm-1.5") genJVM
+ if (settings.target.value == "jvm-1.5-fjbg") genJVM
else genASM
def platformPhases = List(
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
index 42921e733d..ff68aba845 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala
@@ -37,7 +37,7 @@ trait BytecodeWriters {
getFile(outputDirectory(sym), clsName, suffix)
trait BytecodeWriter {
- def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile): Unit
+ def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol): Unit
def close(): Unit = ()
}
@@ -48,9 +48,7 @@ trait BytecodeWriters {
)
val writer = new Jar(jfile).jarWriter(jarMainAttrs: _*)
- def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) {
- assert(outfile == null,
- "The outfile formal param is there just because ClassBytecodeWriter overrides this method and uses it.")
+ def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) {
val path = jclassName + ".class"
val out = writer.newOutputStream(path)
@@ -74,21 +72,21 @@ trait BytecodeWriters {
try javap(Seq("-verbose", "dummy")) foreach (_.show())
finally pw.close()
}
- abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) {
- super.writeClass(label, jclassName, jclassBytes, outfile)
+ abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) {
+ super.writeClass(label, jclassName, jclassBytes, sym)
+ val bytes = getFile(sym, jclassName, ".class").toByteArray
val segments = jclassName.split("[./]")
val javapFile = segments.foldLeft(baseDir: Path)(_ / _) changeExtension "javap" toFile;
javapFile.parent.createDirectory()
- emitJavap(jclassBytes, javapFile)
+ emitJavap(bytes, javapFile)
}
}
trait ClassBytecodeWriter extends BytecodeWriter {
- def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) {
- assert(outfile != null,
- "Precisely this override requires its invoker to hand out a non-null AbstractFile.")
+ def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) {
+ val outfile = getFile(sym, jclassName, ".class")
val outstream = new DataOutputStream(outfile.bufferedOutput)
try outstream.write(jclassBytes, 0, jclassBytes.length)
@@ -100,8 +98,8 @@ trait BytecodeWriters {
trait DumpBytecodeWriter extends BytecodeWriter {
val baseDir = Directory(settings.Ydumpclasses.value).createDirectory()
- abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], outfile: AbstractFile) {
- super.writeClass(label, jclassName, jclassBytes, outfile)
+ abstract override def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) {
+ super.writeClass(label, jclassName, jclassBytes, sym)
val pathName = jclassName
var dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile;
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index da06ea3791..324f0a4b65 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -29,10 +29,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
val phaseName = "jvm"
- case class WorkUnit(label: String, jclassName: String, jclass: asm.ClassWriter, outF: AbstractFile)
-
- type WorkUnitQueue = _root_.java.util.concurrent.LinkedBlockingQueue[WorkUnit]
-
/** Create a new phase */
override def newPhase(p: Phase): Phase = new AsmPhase(p)
@@ -152,44 +148,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
}
}
- // -----------------------------------------------------------------------------------------
- // Allow overlapping disk write of classfiles with building of the next classfiles.
- // -----------------------------------------------------------------------------------------
-
- val q = new WorkUnitQueue(500)
-
- class WriteTask(bytecodeWriter: BytecodeWriter) extends _root_.java.lang.Runnable {
-
- def run() {
- var stop = false
- try {
- while (!stop) {
- val WorkUnit(label, jclassName, jclass, outF) = q.take
- if(jclass eq null) { stop = true }
- else { writeIfNotTooBig(label, jclassName, jclass, outF) }
- }
- } catch {
- case ex: InterruptedException => throw ex
- }
- }
-
- private def writeIfNotTooBig(label: String, jclassName: String, jclass: asm.ClassWriter, outF: AbstractFile) {
- try {
- val arr = jclass.toByteArray()
- bytecodeWriter.writeClass(label, jclassName, arr, outF)
- } catch {
- case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") =>
- // TODO check where ASM throws the equivalent of CodeSizeTooBigException
- log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).")
- }
- }
-
- }
-
- // -----------------------------------------------------------------------------------------
- // what AsmPhase does.
- // -----------------------------------------------------------------------------------------
-
override def run() {
if (settings.debug.value)
@@ -203,14 +161,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName)
debuglog("Created new bytecode generator for " + classes.size + " classes.")
- val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint)
- val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
-
- val plainCodeGen = new JPlainBuilder(q, needsOutfileForSymbol)
- val mirrorCodeGen = new JMirrorBuilder(q, needsOutfileForSymbol)
- val beanInfoCodeGen = new JBeanInfoBuilder(q, needsOutfileForSymbol)
-
- new _root_.java.lang.Thread(new WriteTask(bytecodeWriter)).start()
+ val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint)
+ val plainCodeGen = new JPlainBuilder(bytecodeWriter)
+ val mirrorCodeGen = new JMirrorBuilder(bytecodeWriter)
+ val beanInfoCodeGen = new JBeanInfoBuilder(bytecodeWriter)
while(!sortedClasses.isEmpty) {
val c = sortedClasses.head
@@ -233,10 +187,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
classes -= c.symbol // GC opportunity
}
- q put WorkUnit(null, null, null, null)
-
- while(!q.isEmpty) { _root_.java.lang.Thread.sleep(10) }
-
bytecodeWriter.close()
classes.clear()
reverseJavaName.clear()
@@ -499,7 +449,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
val JAVA_LANG_STRING = asm.Type.getObjectType("java/lang/String")
/** basic functionality for class file building */
- abstract class JBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) {
+ abstract class JBuilder(bytecodeWriter: BytecodeWriter) {
val EMPTY_JTYPE_ARRAY = Array.empty[asm.Type]
val EMPTY_STRING_ARRAY = Array.empty[String]
@@ -555,6 +505,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
// utitilies useful when emitting plain, mirror, and beaninfo classes.
// -----------------------------------------------------------------------------------------
+ def writeIfNotTooBig(label: String, jclassName: String, jclass: asm.ClassWriter, sym: Symbol) {
+ try {
+ val arr = jclass.toByteArray()
+ bytecodeWriter.writeClass(label, jclassName, arr, sym)
+ } catch {
+ case e: java.lang.RuntimeException if(e.getMessage() == "Class file too large!") =>
+ // TODO check where ASM throws the equivalent of CodeSizeTooBigException
+ log("Skipped class "+jclassName+" because it exceeds JVM limits (it's too big or has methods that are too long).")
+ }
+ }
+
/** Specialized array conversion to prevent calling
* java.lang.reflect.Array.newInstance via TraversableOnce.toArray
*/
@@ -768,18 +729,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
}
}
- def enqueue(label: String, jclassName: String, jclass: asm.ClassWriter, sym: Symbol) {
- val outF: scala.tools.nsc.io.AbstractFile = {
- if(needsOutfileForSymbol) getFile(sym, jclassName, ".class") else null
- }
- wuQ put WorkUnit(label, jclassName, jclass, outF)
- }
-
} // end of class JBuilder
/** functionality for building plain and mirror classes */
- abstract class JCommonBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JBuilder(wuQ, needsOutfileForSymbol) {
+ abstract class JCommonBuilder(bytecodeWriter: BytecodeWriter) extends JBuilder(bytecodeWriter) {
+
+ def debugLevel = settings.debuginfo.indexOfChoice
+
+ val emitSource = debugLevel >= 1
+ val emitLines = debugLevel >= 2
+ val emitVars = debugLevel >= 3
// -----------------------------------------------------------------------------------------
// more constants
@@ -1337,8 +1297,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
case class BlockInteval(start: BasicBlock, end: BasicBlock)
/** builder of plain classes */
- class JPlainBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean)
- extends JCommonBuilder(wuQ, needsOutfileForSymbol)
+ class JPlainBuilder(bytecodeWriter: BytecodeWriter)
+ extends JCommonBuilder(bytecodeWriter)
with JAndroidBuilder {
val MIN_SWITCH_DENSITY = 0.7
@@ -1428,8 +1388,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
// typestate: entering mode with valid call sequences:
// [ visitSource ] [ visitOuterClass ] ( visitAnnotation | visitAttribute )*
- jclass.visitSource(c.cunit.source.toString,
- null /* SourceDebugExtension */)
+ if(emitSource) {
+ jclass.visitSource(c.cunit.source.toString,
+ null /* SourceDebugExtension */)
+ }
val enclM = getEnclosingMethodAttribute()
if(enclM != null) {
@@ -1492,7 +1454,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
addInnerClasses(clasz.symbol, jclass)
jclass.visitEnd()
- enqueue("" + c.symbol.name, thisName, jclass, c.symbol)
+ writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
}
@@ -1557,12 +1519,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
jfield.visitEnd()
}
- def debugLevel = settings.debuginfo.indexOfChoice
-
- // val emitSource = debugLevel >= 1
- val emitLines = debugLevel >= 2
- val emitVars = debugLevel >= 3
-
var method: IMethod = _
var jmethod: asm.MethodVisitor = _
var jMethodName: String = _
@@ -1941,6 +1897,15 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
i += 1
}
+ // check for duplicate keys to avoid "VerifyError: unsorted lookupswitch" (SI-6011)
+ i = 1
+ while (i < keys.length) {
+ if(keys(i-1) == keys(i)) {
+ abort("duplicate keys in SWITCH, can't pick arbitrarily one of them to evict, see SI-6011.")
+ }
+ i += 1
+ }
+
val keyMin = keys(0)
val keyMax = keys(keys.length - 1)
@@ -2227,9 +2192,15 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
val st = pending.getOrElseUpdate(lv, mutable.Stack.empty[Label])
st.push(start)
}
- def popScope(lv: Local, end: Label) {
- val start = pending(lv).pop()
- seen ::= LocVarEntry(lv, start, end)
+ def popScope(lv: Local, end: Label, iPos: Position) {
+ pending.get(lv) match {
+ case Some(st) if st.nonEmpty =>
+ val start = st.pop()
+ seen ::= LocVarEntry(lv, start, end)
+ case _ =>
+ // TODO SI-6049
+ getCurrentCUnit().warning(iPos, "Visited SCOPE_EXIT before visiting corresponding SCOPE_ENTER. SI-6049")
+ }
}
def getMerged(): collection.Map[Local, List[Interval]] = {
@@ -2442,7 +2413,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
// similarly, these labels aren't tracked in the `labels` map.
val end = new asm.Label
jmethod.visitLabel(end)
- scoping.popScope(lv, end)
+ scoping.popScope(lv, end, instr.pos)
}
}
@@ -2928,7 +2899,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
/** builder of mirror classes */
- class JMirrorBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JCommonBuilder(wuQ, needsOutfileForSymbol) {
+ class JMirrorBuilder(bytecodeWriter: BytecodeWriter) extends JCommonBuilder(bytecodeWriter) {
private var cunit: CompilationUnit = _
def getCurrentCUnit(): CompilationUnit = cunit;
@@ -2958,8 +2929,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
// typestate: entering mode with valid call sequences:
// [ visitSource ] [ visitOuterClass ] ( visitAnnotation | visitAttribute )*
- mirrorClass.visitSource("" + cunit.source,
- null /* SourceDebugExtension */)
+ if(emitSource) {
+ mirrorClass.visitSource("" + cunit.source,
+ null /* SourceDebugExtension */)
+ }
val ssa = getAnnotPickle(mirrorName, modsym.companionSymbol)
mirrorClass.visitAttribute(if(ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign)
@@ -2972,7 +2945,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
addInnerClasses(modsym, mirrorClass)
mirrorClass.visitEnd()
- enqueue("" + modsym.name, mirrorName, mirrorClass, modsym)
+ writeIfNotTooBig("" + modsym.name, mirrorName, mirrorClass, modsym)
}
@@ -2980,7 +2953,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
/** builder of bean info classes */
- class JBeanInfoBuilder(wuQ: WorkUnitQueue, needsOutfileForSymbol: Boolean) extends JBuilder(wuQ, needsOutfileForSymbol) {
+ class JBeanInfoBuilder(bytecodeWriter: BytecodeWriter) extends JBuilder(bytecodeWriter) {
/**
* Generate a bean info class that describes the given class.
@@ -3101,7 +3074,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
addInnerClasses(clasz.symbol, beanInfoClass)
beanInfoClass.visitEnd()
- enqueue("BeanInfo ", beanInfoName, beanInfoClass, clasz.symbol)
+ writeIfNotTooBig("BeanInfo ", beanInfoName, beanInfoClass, clasz.symbol)
}
} // end of class JBeanInfoBuilder
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index bae59ffaf8..9661ae6b3e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -183,6 +183,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
class BytecodeGenerator(bytecodeWriter: BytecodeWriter) extends BytecodeUtil {
def this() = this(new ClassBytecodeWriter { })
def debugLevel = settings.debuginfo.indexOfChoice
+ import bytecodeWriter.writeClass
val MIN_SWITCH_DENSITY = 0.7
val INNER_CLASSES_FLAGS =
@@ -343,15 +344,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
writeClass("" + sym.name, jclass.getName(), toByteArray(jclass), sym)
}
- val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter]
-
- def writeClass(label: String, jclassName: String, jclassBytes: Array[Byte], sym: Symbol) {
- val outF: scala.tools.nsc.io.AbstractFile = {
- if(needsOutfileForSymbol) getFile(sym, jclassName, ".class") else null
- }
- bytecodeWriter.writeClass(label, jclassName, jclassBytes, outF)
- }
-
/** Returns the ScalaSignature annotation if it must be added to this class,
* none otherwise; furthermore, it adds to `jclass` the ScalaSig marker
* attribute (marking that a scala signature annotation is present) or the
diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala
index f622f11ffd..afb8985700 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala
@@ -82,13 +82,17 @@ abstract class InteractiveTest
/** Test's entry point */
def main(args: Array[String]) {
+ try execute()
+ finally shutdown()
+ }
+
+ protected def execute(): Unit = {
loadSources()
- runTests()
- shutdown()
+ runDefaultTests()
}
/** Load all sources before executing the test. */
- private def loadSources() {
+ protected def loadSources() {
// ask the presentation compiler to track all sources. We do
// not wait for the file to be entirely typed because we do want
// to exercise the presentation compiler on scoped type requests.
@@ -100,7 +104,7 @@ abstract class InteractiveTest
}
/** Run all defined `PresentationCompilerTestDef` */
- protected def runTests() {
+ protected def runDefaultTests() {
//TODO: integrate random tests!, i.e.: if (runRandomTests) randomTests(20, sourceFiles)
testActions.foreach(_.runTest())
}
@@ -109,7 +113,7 @@ abstract class InteractiveTest
private def randomTests(n: Int, files: Array[SourceFile]) {
val tester = new Tester(n, files, settings) {
override val compiler = self.compiler
- override val reporter = compilerReporter
+ override val reporter = new reporters.StoreReporter
}
tester.run()
}
diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala
index 36671555d1..4d85ab9d88 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala
@@ -4,10 +4,8 @@ package tests
import java.io.File.pathSeparatorChar
import java.io.File.separatorChar
-
import scala.tools.nsc.interactive.tests.core.PresentationCompilerInstance
-import scala.tools.nsc.io.File
-
+import scala.tools.nsc.io.{File,Path}
import core.Reporter
import core.TestSettings
@@ -46,6 +44,11 @@ trait InteractiveTestSettings extends TestSettings with PresentationCompilerInst
println("error processing arguments (unprocessed: %s)".format(rest))
case _ => ()
}
+
+ // Make the --sourcepath path provided in the .flags file (if any) relative to the test's base directory
+ if(settings.sourcepath.isSetByUser)
+ settings.sourcepath.value = (baseDir / Path(settings.sourcepath.value)).path
+
adjustPaths(settings.bootclasspath, settings.classpath, settings.javabootclasspath, settings.sourcepath)
}
diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
index 8ccb5aa075..5c1837b3bf 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
@@ -2,12 +2,15 @@ package scala.tools.nsc
package interactive
package tests.core
-import reporters.StoreReporter
+import reporters.{Reporter => CompilerReporter}
+import scala.reflect.internal.util.Position
/** Trait encapsulating the creation of a presentation compiler's instance.*/
-private[tests] trait PresentationCompilerInstance {
+private[tests] trait PresentationCompilerInstance extends TestSettings {
protected val settings = new Settings
- protected val compilerReporter = new StoreReporter
+ protected val compilerReporter: CompilerReporter = new InteractiveReporter {
+ override def compiler = PresentationCompilerInstance.this.compiler
+ }
protected lazy val compiler: Global = {
prepareSettings(settings)
diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
index 1bb0948168..f0ee8b11f3 100644
--- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
@@ -40,7 +40,9 @@ trait StandardScalaSettings {
val nowarn = BooleanSetting ("-nowarn", "Generate no warnings.")
val optimise: BooleanSetting // depends on post hook which mutates other settings
val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.")
- val target = ChoiceSetting ("-target", "target", "Target platform for object files.", List("jvm-1.5", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil"), "jvm-1.5")
+ val target = ChoiceSetting ("-target", "target", "Target platform for object files.",
+ List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil"),
+ "jvm-1.5-asm")
val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked (erasure) warnings.")
val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.")
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 49f5fca19d..ba6c43f9d3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -562,7 +562,9 @@ trait ContextErrors {
// SelectFromTypeTree
def TypeSelectionFromVolatileTypeError(tree: Tree, qual: Tree) = {
- issueNormalTypeError(tree, "illegal type selection from volatile type "+qual.tpe)
+ val hiBound = qual.tpe.bounds.hi
+ val addendum = if (hiBound =:= qual.tpe) "" else s" (with upper bound ${hiBound})"
+ issueNormalTypeError(tree, s"illegal type selection from volatile type ${qual.tpe}${addendum}")
setError(tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 6428173577..9580cd5676 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -52,27 +52,6 @@ trait Namers extends MethodSynthesis {
def newNamerFor(context: Context, tree: Tree): Namer =
newNamer(context.makeNewScope(tree, tree.symbol))
- // In the typeCompleter (templateSig) of a case class (resp it's module),
- // synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute
- // their signatures, the corresponding ClassDef is needed.
- // During naming, for each case class module symbol, the corresponding ClassDef
- // is stored in this map. The map is cleared lazily, i.e. when the new symbol
- // is created with the same name, the old one (if present) is wiped out, or the
- // entry is deleted when it is used and no longer needed.
- private val classOfModuleClass = perRunCaches.newWeakMap[Symbol, WeakReference[ClassDef]]()
-
- // Default getters of constructors are added to the companion object in the
- // typeCompleter of the constructor (methodSig). To compute the signature,
- // we need the ClassDef. To create and enter the symbols into the companion
- // object, we need the templateNamer of that module class.
- // This map is extended during naming of classes, the Namer is added in when
- // it's available, i.e. in the type completer (templateSig) of the module class.
- private[typechecker] val classAndNamerOfModule = perRunCaches.newMap[Symbol, (ClassDef, Namer)]()
-
- def resetNamer() {
- classAndNamerOfModule.clear()
- }
-
abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer =>
import NamerErrorGen._
@@ -618,7 +597,7 @@ trait Namers extends MethodSynthesis {
MaxParametersCaseClassError(tree)
val m = ensureCompanionObject(tree, caseModuleDef)
- classOfModuleClass(m.moduleClass) = new WeakReference(tree)
+ m.moduleClass.addAttachment(new ClassForCaseCompanionAttachment(tree))
}
val hasDefault = impl.body exists {
case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault)
@@ -626,7 +605,7 @@ trait Namers extends MethodSynthesis {
}
if (hasDefault) {
val m = ensureCompanionObject(tree)
- classAndNamerOfModule(m) = (tree, null)
+ m.addAttachment(new ConstructorDefaultsAttachment(tree, null))
}
val owner = tree.symbol.owner
if (settings.lint.value && owner.isPackageObjectClass && !mods.isImplicit) {
@@ -657,7 +636,8 @@ trait Namers extends MethodSynthesis {
if (sym.isLazy)
sym.lazyAccessor andAlso enterIfNotThere
- defaultParametersOfMethod(sym) foreach { symRef => enterIfNotThere(symRef()) }
+ for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment])
+ defAtt.defaultGetters foreach enterIfNotThere
}
this.context
}
@@ -846,23 +826,20 @@ trait Namers extends MethodSynthesis {
// add apply and unapply methods to companion objects of case classes,
// unless they exist already; here, "clazz" is the module class
if (clazz.isModuleClass) {
- Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
- val cdef = cdefRef()
- if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
- classOfModuleClass -= clazz
+ clazz.attachments.get[ClassForCaseCompanionAttachment] foreach { cma =>
+ val cdef = cma.caseClass
+ assert(cdef.mods.isCase, "expected case class: "+ cdef)
+ addApplyUnapply(cdef, templateNamer)
}
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
// the namer phase must traverse this copy method to create default getters for its parameters.
// here, clazz is the ClassSymbol of the case class (not the module).
- // @check: this seems to work only if the type completer of the class runs before the one of the
- // module class: the one from the module class removes the entry from classOfModuleClass (see above).
if (clazz.isClass && !clazz.hasModuleFlag) {
val modClass = companionSymbolOf(clazz, context).moduleClass
- Namers.this.classOfModuleClass get modClass map { cdefRef =>
- val cdef = cdefRef()
-
+ modClass.attachments.get[ClassForCaseCompanionAttachment] foreach { cma =>
+ val cdef = cma.caseClass
def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol
if (cdef.mods.isCase && !hasCopy(decls) &&
!parents.exists(p => hasCopy(p.typeSymbol.info.decls)) &&
@@ -874,9 +851,8 @@ trait Namers extends MethodSynthesis {
// if default getters (for constructor defaults) need to be added to that module, here's the namer
// to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods.
val module = clazz.sourceModule
- classAndNamerOfModule get module foreach {
- case (cdef, _) =>
- classAndNamerOfModule(module) = (cdef, templateNamer)
+ for (cda <- module.attachments.get[ConstructorDefaultsAttachment]) {
+ cda.companionModuleClassNamer = templateNamer
}
ClassInfoType(parents, decls, clazz)
}
@@ -1097,13 +1073,15 @@ trait Namers extends MethodSynthesis {
val module = companionSymbolOf(clazz, context)
module.initialize // call type completer (typedTemplate), adds the
// module's templateNamer to classAndNamerOfModule
- classAndNamerOfModule get module match {
- case s @ Some((cdef, nmr)) if nmr != null =>
- moduleNamer = s
- (cdef, nmr)
+ 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*/ =>
+ val p = (cda.classWithDefault, cda.companionModuleClassNamer)
+ moduleNamer = Some(p)
+ p
case _ =>
return // fix #3649 (prevent crash in erroneous source code)
- // nmr == null can happen in IDE; this is really an ugly hack on top[ of an ugly hack but it seems to work
}
}
deftParams = cdef.tparams map copyUntypedInvariant
@@ -1141,11 +1119,14 @@ trait Namers extends MethodSynthesis {
clazz.resetFlag(INTERFACE) // there's a concrete member now
val default = parentNamer.enterSyntheticSym(defaultTree)
if (forInteractive && default.owner.isTerm) {
- // enter into map from method symbols to default arguments.
- // if compiling the same local block several times (which can happen in interactive mode)
- // we might otherwise not find the default symbol, because the second time it the
- // method symbol will be re-entered in the scope but the default parameter will not.
- defaultParametersOfMethod(meth) += new WeakReference(default)
+ // save the default getters as attachments in the method symbol. if compiling the
+ // same local block several times (which can happen in interactive mode) we might
+ // otherwise not find the default symbol, because the second time it the method
+ // symbol will be re-entered in the scope but the default parameter will not.
+ val att = meth.attachments.get[DefaultsOfLocalMethodAttachment] match {
+ case Some(att) => att.defaultGetters += default
+ case None => meth.addAttachment(new DefaultsOfLocalMethodAttachment(default))
+ }
}
} else if (baseHasDefault) {
// the parameter does not have a default itself, but the
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 61443faba0..a0c1342026 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -21,8 +21,19 @@ trait NamesDefaults { self: Analyzer =>
import definitions._
import NamesDefaultsErrorsGen._
- val defaultParametersOfMethod =
- perRunCaches.newWeakMap[Symbol, Set[WeakReference[Symbol]]]() withDefaultValue Set()
+ // Default getters of constructors are added to the companion object in the
+ // typeCompleter of the constructor (methodSig). To compute the signature,
+ // we need the ClassDef. To create and enter the symbols into the companion
+ // object, we need the templateNamer of that module class. These two are stored
+ // as an attachment in the companion module symbol
+ class ConstructorDefaultsAttachment(val classWithDefault: ClassDef, var companionModuleClassNamer: Namer)
+
+ // To attach the default getters of local (term-owned) methods to the method symbol.
+ // Used in Namer.enterExistingSym: it needs to re-enter the method symbol and also
+ // default getters, which could not be found otherwise.
+ class DefaultsOfLocalMethodAttachment(val defaultGetters: mutable.Set[Symbol]) {
+ def this(default: Symbol) = this(mutable.Set(default))
+ }
case class NamedApplyInfo(
qual: Option[Tree],
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ccd346e72d..b9fe269e43 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -47,7 +47,6 @@ trait Typers extends Modes with Adaptations with Tags {
def resetTyper() {
//println("resetTyper called")
resetContexts()
- resetNamer()
resetImplicits()
transformed.clear()
}
@@ -4431,7 +4430,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (!qual.tpe.widen.isErroneous) {
if ((mode & QUALmode) != 0) {
- val lastTry = missingHook(qual.tpe.typeSymbol, name)
+ val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
}
NotAMemberError(tree, qual, name)
@@ -4673,7 +4672,7 @@ trait Typers extends Modes with Adaptations with Tags {
log("Allowing empty package member " + name + " due to settings.")
else {
if ((mode & QUALmode) != 0) {
- val lastTry = missingHook(rootMirror.RootClass, name)
+ val lastTry = rootMirror.missingHook(rootMirror.RootClass, name)
if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
}
if (settings.debug.value) {
@@ -5114,7 +5113,7 @@ trait Typers extends Modes with Adaptations with Tags {
case SelectFromTypeTree(qual, selector) =>
val qual1 = typedType(qual, mode)
- if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual)
+ if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1)
else typedSelect(qual1, selector)
case CompoundTypeTree(templ) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 1b89f3db44..ad936ac39d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -23,6 +23,14 @@ trait Unapplies extends ast.TreeDSL
private val unapplyParamName = nme.x_0
+
+ // In the typeCompleter (templateSig) of a case class (resp it's module),
+ // synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute
+ // their signatures, the corresponding ClassDef is needed. During naming (in
+ // `enterClassDef`), the case class ClassDef is added as an attachment to the
+ // moduleClass symbol of the companion module.
+ class ClassForCaseCompanionAttachment(val caseClass: ClassDef)
+
/** returns type list for return type of the extraction */
def unapplyTypeList(ufn: Symbol, ufntpe: Type) = {
assert(ufn.isMethod, ufn)
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 59160f87d0..8ea66979bc 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -15,8 +15,9 @@ trait FastTrack {
import definitions._
import language.implicitConversions
- private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
- private implicit def context2contextreifiers(c0: MacroContext) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
+ private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+ private implicit def context2contextreifiers(c0: MacroContext): ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
+ private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations
implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
@@ -42,6 +43,7 @@ trait FastTrack {
ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) }
ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree }
+ StringContext_f bindTo { case (c, Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args) }
registry
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala
new file mode 100644
index 0000000000..a5f7928f55
--- /dev/null
+++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala
@@ -0,0 +1,147 @@
+package scala.tools.reflect
+
+import scala.reflect.makro.{ReificationError, UnexpectedReificationError}
+import scala.reflect.makro.runtime.Context
+import scala.collection.mutable.ListBuffer
+import scala.collection.mutable.Stack
+
+abstract class MacroImplementations {
+ val c: Context
+
+ import c.universe._
+
+ def macro_StringInterpolation_f(parts: List[Tree], args: List[Tree]): Tree = {
+ // the parts all have the same position information (as the expression is generated by the compiler)
+ // the args have correct position information
+
+ // the following conditions can only be violated if invoked directly
+ if (parts.length != args.length + 1) {
+ if(parts.length == 0)
+ c.abort(c.prefix.tree.pos, "too few parts")
+ else if(args.length + 1 < parts.length)
+ c.abort(if(args.length==0) c.enclosingPosition else args.last.pos,
+ "too few arguments for interpolated string")
+ else
+ c.abort(args(parts.length-1).pos,
+ "too many arguments for interpolated string")
+ }
+
+ val stringParts = parts map {
+ case Literal(Constant(s: String)) => s;
+ case _ => throw new IllegalArgumentException("argument parts must be a list of string literals")
+ }
+
+ val pi = stringParts.iterator
+ val bldr = new java.lang.StringBuilder
+ val evals = ListBuffer[ValDef]()
+ val ids = ListBuffer[Ident]()
+ val argsStack = Stack(args : _*)
+
+ def defval(value: Tree, tpe: Type): Unit = {
+ val freshName = newTermName(c.fresh("arg$"))
+ evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value)
+ ids += Ident(freshName)
+ }
+
+ def isFlag(ch: Char): Boolean = {
+ ch match {
+ case '-' | '#' | '+' | ' ' | '0' | ',' | '(' => true
+ case _ => false
+ }
+ }
+
+ def checkType(arg: Tree, variants: Type*): Option[Type] = {
+ variants.find(arg.tpe <:< _).orElse(
+ variants.find(c.inferImplicitView(arg, arg.tpe, _) != EmptyTree).orElse(
+ Some(variants(0))
+ )
+ )
+ }
+
+ def conversionType(ch: Char, arg: Tree): Option[Type] = {
+ ch match {
+ case 'b' | 'B' =>
+ if(arg.tpe <:< NullTpe) Some(NullTpe) else Some(BooleanTpe)
+ case 'h' | 'H' =>
+ Some(AnyTpe)
+ case 's' | 'S' =>
+ Some(AnyTpe)
+ case 'c' | 'C' =>
+ checkType(arg, CharTpe, ByteTpe, ShortTpe, IntTpe)
+ case 'd' | 'o' | 'x' | 'X' =>
+ checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, typeOf[BigInt])
+ case 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' =>
+ checkType(arg, DoubleTpe, FloatTpe, typeOf[BigDecimal])
+ case 't' | 'T' =>
+ checkType(arg, LongTpe, typeOf[java.util.Calendar], typeOf[java.util.Date])
+ case _ => None
+ }
+ }
+
+ def copyString(first: Boolean): Unit = {
+ val str = StringContext.treatEscapes(pi.next())
+ val strLen = str.length
+ val strIsEmpty = strLen == 0
+ var start = 0
+ var idx = 0
+
+ if (!first) {
+ val arg = argsStack.pop
+ if (strIsEmpty || (str charAt 0) != '%') {
+ bldr append "%s"
+ defval(arg, AnyTpe)
+ } else {
+ // PRE str is not empty and str(0) == '%'
+ // argument index parameter is not allowed, thus parse
+ // [flags][width][.precision]conversion
+ var pos = 1
+ while(pos < strLen && isFlag(str charAt pos)) pos += 1
+ while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1
+ if(pos < strLen && str.charAt(pos) == '.') { pos += 1
+ while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1
+ }
+ if(pos < strLen) {
+ conversionType(str charAt pos, arg) match {
+ case Some(tpe) => defval(arg, tpe)
+ case None => c.error(arg.pos, "illegal conversion character")
+ }
+ } else {
+ // TODO: place error message on conversion string
+ c.error(arg.pos, "wrong conversion string")
+ }
+ }
+ idx = 1
+ }
+ if (!strIsEmpty) {
+ val len = str.length
+ while (idx < len) {
+ if (str(idx) == '%') {
+ bldr append (str substring (start, idx)) append "%%"
+ start = idx + 1
+ }
+ idx += 1
+ }
+ bldr append (str substring (start, idx))
+ }
+ }
+
+ copyString(first = true)
+ while (pi.hasNext) {
+ copyString(first = false)
+ }
+
+ val fstring = bldr.toString
+// val expr = c.reify(fstring.format((ids.map(id => Expr(id).eval)) : _*))
+// https://issues.scala-lang.org/browse/SI-5824, therefore
+ val expr =
+ Apply(
+ Select(
+ Literal(Constant(fstring)),
+ newTermName("format")),
+ List(ids: _* )
+ );
+
+ Block(evals.toList, expr)
+ }
+
+} \ No newline at end of file
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index f400f18dab..f11dfb72ae 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -8,7 +8,7 @@
package scala
-import collection.mutable.ArrayBuffer
+import language.experimental.macros
/** A class to support string interpolation.
* This class supports string interpolation as outlined in Scala SIP-11.
@@ -42,7 +42,7 @@ case class StringContext(parts: String*) {
* @throws A `StringContext.InvalidEscapeException` if if a `parts` string contains a backslash (`\`) character
* that does not start a valid escape sequence.
*/
- def s(args: Any*) = {
+ def s(args: Any*): String = {
checkLengths(args: _*)
val pi = parts.iterator
val ai = args.iterator
@@ -82,38 +82,8 @@ case class StringContext(parts: String*) {
* string literally. This is achieved by replacing each such occurrence by the
* format specifier `%%`.
*/
- def f(args: Any*) = {
- checkLengths(args: _*)
- val pi = parts.iterator
- val bldr = new java.lang.StringBuilder
- def copyString(first: Boolean): Unit = {
- val str = treatEscapes(pi.next())
- val strIsEmpty = str.length == 0
- var start = 0
- var idx = 0
- if (!first) {
- if (strIsEmpty || (str charAt 0) != '%')
- bldr append "%s"
- idx = 1
- }
- if (!strIsEmpty) {
- val len = str.length
- while (idx < len) {
- if (str(idx) == '%') {
- bldr append (str substring (start, idx)) append "%%"
- start = idx + 1
- }
- idx += 1
- }
- bldr append (str substring (start, idx))
- }
- }
- copyString(first = true)
- while (pi.hasNext) {
- copyString(first = false)
- }
- bldr.toString format (args: _*)
- }
+ // The implementation is magically hardwired into `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f`
+ def f(args: Any*): String = macro ???
}
object StringContext {
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
index 8c603dc91b..75707b69b0 100644
--- a/src/library/scala/collection/convert/Wrappers.scala
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -467,4 +467,5 @@ private[collection] trait Wrappers {
}
}
-object Wrappers extends Wrappers
+@SerialVersionUID(0 - 5857859809262781311L)
+object Wrappers extends Wrappers with Serializable
diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala
index 2eaa861429..3d27f619bb 100644
--- a/src/library/scala/collection/parallel/TaskSupport.scala
+++ b/src/library/scala/collection/parallel/TaskSupport.scala
@@ -48,7 +48,7 @@ extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks
* By default, parallel collections are parametrized with this task support object, so parallel collections
* share the same execution context backend as the rest of the `scala.concurrent` package.
*/
-class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.defaultExecutionContext)
+class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.ExecutionContext.global)
extends TaskSupport with ExecutionContextTasks
diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala
new file mode 100644
index 0000000000..a5b878c546
--- /dev/null
+++ b/src/library/scala/concurrent/BlockContext.scala
@@ -0,0 +1,81 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.concurrent
+
+import java.lang.Thread
+import scala.concurrent.util.Duration
+
+/**
+ * A context to be notified by `scala.concurrent.blocking()` when
+ * a thread is about to block. In effect this trait provides
+ * the implementation for `scala.concurrent.blocking()`. `scala.concurrent.blocking()`
+ * locates an instance of `BlockContext` by first looking for one
+ * provided through `BlockContext.withBlockContext()` and failing that,
+ * checking whether `Thread.currentThread` is an instance of `BlockContext`.
+ * So a thread pool can have its `java.lang.Thread` instances implement
+ * `BlockContext`. There's a default `BlockContext` used if the thread
+ * doesn't implement `BlockContext`.
+ *
+ * Typically, you'll want to chain to the previous `BlockContext`,
+ * like this:
+ * {{{
+ * val oldContext = BlockContext.current
+ * val myContext = new BlockContext {
+ * override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = {
+ * // you'd have code here doing whatever you need to do
+ * // when the thread is about to block.
+ * // Then you'd chain to the previous context:
+ * oldContext.internalBlockingCall(awaitable, atMost)
+ * }
+ * }
+ * BlockContext.withBlockContext(myContext) {
+ * // then this block runs with myContext as the handler
+ * // for scala.concurrent.blocking
+ * }
+ * }}}
+ */
+trait BlockContext {
+
+ /** Used internally by the framework; blocks execution for at most
+ * `atMost` time while waiting for an `awaitable` object to become ready.
+ *
+ * Clients should use `scala.concurrent.blocking` instead; this is
+ * the implementation of `scala.concurrent.blocking`, generally
+ * provided by a `scala.concurrent.ExecutionContext` or `java.util.concurrent.Executor`.
+ */
+ def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T
+}
+
+object BlockContext {
+ private object DefaultBlockContext extends BlockContext {
+ override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T =
+ awaitable.result(atMost)(Await.canAwaitEvidence)
+ }
+
+ private val contextLocal = new ThreadLocal[BlockContext]() {
+ override def initialValue = Thread.currentThread match {
+ case ctx: BlockContext => ctx
+ case _ => DefaultBlockContext
+ }
+ }
+
+ /** Obtain the current thread's current `BlockContext`. */
+ def current: BlockContext = contextLocal.get
+
+ /** Pushes a current `BlockContext` while executing `body`. */
+ def withBlockContext[T](blockContext: BlockContext)(body: => T): T = {
+ val old = contextLocal.get
+ try {
+ contextLocal.set(blockContext)
+ body
+ } finally {
+ contextLocal.set(old)
+ }
+ }
+}
diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala
index 330a2f0e25..86a86966ef 100644
--- a/src/library/scala/concurrent/ConcurrentPackageObject.scala
+++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala
@@ -17,23 +17,6 @@ import language.implicitConversions
/** This package object contains primitives for concurrent and parallel programming.
*/
abstract class ConcurrentPackageObject {
- /** A global execution environment for executing lightweight tasks.
- */
- lazy val defaultExecutionContext: ExecutionContext with Executor = impl.ExecutionContextImpl.fromExecutor(null: Executor)
-
- val currentExecutionContext = new ThreadLocal[ExecutionContext]
-
- val handledFutureException: PartialFunction[Throwable, Throwable] = {
- case t: Throwable if isFutureThrowable(t) => t
- }
-
- // TODO rename appropriately and make public
- private[concurrent] def isFutureThrowable(t: Throwable) = t match {
- case e: Error => false
- case t: scala.util.control.ControlThrowable => false
- case i: InterruptedException => false
- case _ => true
- }
/* concurrency constructs */
@@ -46,8 +29,7 @@ abstract class ConcurrentPackageObject {
* @param execctx the execution context on which the future is run
* @return the `Future` holding the result of the computation
*/
- def future[T](body: =>T)(implicit execctx: ExecutionContext = defaultExecutionContext): Future[T] =
- Future[T](body)
+ def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
/** Creates a promise object which can be completed with a value.
*
@@ -55,8 +37,7 @@ abstract class ConcurrentPackageObject {
* @param execctx the execution context on which the promise is created on
* @return the newly created `Promise` object
*/
- def promise[T]()(implicit execctx: ExecutionContext = defaultExecutionContext): Promise[T] =
- Promise[T]()
+ def promise[T]()(implicit execctx: ExecutionContext): Promise[T] = Promise[T]()
/** Used to block on a piece of code which potentially blocks.
*
@@ -67,8 +48,7 @@ abstract class ConcurrentPackageObject {
* - InterruptedException - in the case that a wait within the blockable object was interrupted
* - TimeoutException - in the case that the blockable object timed out
*/
- def blocking[T](body: =>T): T =
- blocking(impl.Future.body2awaitable(body), Duration.Inf)
+ def blocking[T](body: =>T): T = blocking(impl.Future.body2awaitable(body), Duration.Inf)
/** Blocks on an awaitable object.
*
@@ -79,12 +59,8 @@ abstract class ConcurrentPackageObject {
* - InterruptedException - in the case that a wait within the blockable object was interrupted
* - TimeoutException - in the case that the blockable object timed out
*/
- def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = {
- currentExecutionContext.get match {
- case null => awaitable.result(atMost)(Await.canAwaitEvidence)
- case ec => ec.internalBlockingCall(awaitable, atMost)
- }
- }
+ def blocking[T](awaitable: Awaitable[T], atMost: Duration): T =
+ BlockContext.current.internalBlockingCall(awaitable, atMost)
@inline implicit final def int2durationops(x: Int): DurationOps = new DurationOps(x)
}
diff --git a/src/library/scala/concurrent/DelayedLazyVal.scala b/src/library/scala/concurrent/DelayedLazyVal.scala
index 96a66d83b6..91e41748f5 100644
--- a/src/library/scala/concurrent/DelayedLazyVal.scala
+++ b/src/library/scala/concurrent/DelayedLazyVal.scala
@@ -23,7 +23,7 @@ package scala.concurrent
* @author Paul Phillips
* @version 2.8
*/
-class DelayedLazyVal[T](f: () => T, body: => Unit) {
+class DelayedLazyVal[T](f: () => T, body: => Unit){
@volatile private[this] var _isDone = false
private[this] lazy val complete = f()
@@ -39,7 +39,8 @@ class DelayedLazyVal[T](f: () => T, body: => Unit) {
*/
def apply(): T = if (isDone) complete else f()
- // TODO replace with scala.concurrent.future { ... }
+ // FIXME need to take ExecutionContext in constructor
+ import ExecutionContext.Implicits.global
future {
body
_isDone = true
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index 436a17a33b..b486e5269e 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -9,58 +9,80 @@
package scala.concurrent
-
-import java.util.concurrent.atomic.{ AtomicInteger }
-import java.util.concurrent.{ Executors, Future => JFuture, Callable, ExecutorService, Executor }
+import java.util.concurrent.{ ExecutorService, Executor }
import scala.concurrent.util.Duration
-import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveTask => FJTask, RecursiveAction, ForkJoinWorkerThread }
-import scala.collection.generic.CanBuildFrom
-import collection._
-
-
+import scala.annotation.implicitNotFound
+/**
+ * An `ExecutionContext` is an abstraction over an entity that can execute program logic.
+ */
+@implicitNotFound("Cannot find an implicit ExecutionContext, either require one yourself or import ExecutionContext.Implicits.global")
trait ExecutionContext {
/** Runs a block of code on this execution context.
*/
def execute(runnable: Runnable): Unit
- /** Used internally by the framework - blocks execution for at most `atMost` time while waiting
- * for an `awaitable` object to become ready.
- *
- * Clients should use `scala.concurrent.blocking` instead.
- */
- def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T
-
/** Reports that an asynchronous computation failed.
*/
def reportFailure(t: Throwable): Unit
}
+/**
+ * Union interface since Java does not support union types
+ */
+trait ExecutionContextExecutor extends ExecutionContext with Executor
+
+/**
+ * Union interface since Java does not support union types
+ */
+trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService
+
/** Contains factory methods for creating execution contexts.
*/
object ExecutionContext {
-
- implicit def defaultExecutionContext: ExecutionContext = scala.concurrent.defaultExecutionContext
-
+ /**
+ * The `ExecutionContext` associated with the current `Thread`
+ */
+ val currentExecutionContext: ThreadLocal[ExecutionContext] = new ThreadLocal //FIXME might want to set the initial value to an executionContext that throws an exception on execute and warns that it's not set
+
+ /**
+ * This is the explicit global ExecutionContext,
+ * call this when you want to provide the global ExecutionContext explicitly
+ */
+ def global: ExecutionContextExecutor = Implicits.global
+
+ object Implicits {
+ /**
+ * This is the implicit global ExecutionContext,
+ * import this when you want to provide the global ExecutionContext implicitly
+ */
+ implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor)
+ }
+
/** Creates an `ExecutionContext` from the given `ExecutorService`.
*/
- def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit = defaultReporter): ExecutionContext with ExecutorService =
+ def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit): ExecutionContextExecutorService =
impl.ExecutionContextImpl.fromExecutorService(e, reporter)
+
+ /** Creates an `ExecutionContext` from the given `ExecutorService` with the default Reporter.
+ */
+ def fromExecutorService(e: ExecutorService): ExecutionContextExecutorService = fromExecutorService(e, defaultReporter)
/** Creates an `ExecutionContext` from the given `Executor`.
*/
- def fromExecutor(e: Executor, reporter: Throwable => Unit = defaultReporter): ExecutionContext with Executor =
+ def fromExecutor(e: Executor, reporter: Throwable => Unit): ExecutionContextExecutor =
impl.ExecutionContextImpl.fromExecutor(e, reporter)
+
+ /** Creates an `ExecutionContext` from the given `Executor` with the default Reporter.
+ */
+ def fromExecutor(e: Executor): ExecutionContextExecutor = fromExecutor(e, defaultReporter)
- def defaultReporter: Throwable => Unit = {
- // re-throwing `Error`s here causes an exception handling test to fail.
- //case e: Error => throw e
- case t => t.printStackTrace()
- }
-
+ /** The default reporter simply prints the stack trace of the `Throwable` to System.err.
+ */
+ def defaultReporter: Throwable => Unit = { case t => t.printStackTrace() }
}
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index 2de0c57253..75a83d6ef8 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -8,7 +8,7 @@
package scala.concurrent
-
+import language.higherKinds
import java.util.concurrent.{ ConcurrentLinkedQueue, TimeUnit, Callable }
import java.util.concurrent.TimeUnit.{ NANOSECONDS => NANOS, MILLISECONDS ⇒ MILLIS }
@@ -23,11 +23,9 @@ import scala.Option
import scala.util.{Try, Success, Failure}
import scala.annotation.tailrec
-import scala.collection.mutable.Stack
import scala.collection.mutable.Builder
import scala.collection.generic.CanBuildFrom
import scala.reflect.ClassTag
-import language.higherKinds
@@ -138,7 +136,7 @@ trait Future[+T] extends Awaitable[T] {
* $callbackInContext
*/
def onFailure[U](callback: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete {
- case Left(t) if (isFutureThrowable(t) && callback.isDefinedAt(t)) => callback(t)
+ case Left(t) if (impl.Future.isFutureThrowable(t) && callback.isDefinedAt(t)) => callback(t)
case _ =>
}(executor)
@@ -580,6 +578,20 @@ object Future {
classOf[Double] -> classOf[jl.Double],
classOf[Unit] -> classOf[scala.runtime.BoxedUnit]
)
+
+ /** Creates an already completed Future with the specified exception.
+ *
+ * @tparam T the type of the value in the future
+ * @return the newly created `Future` object
+ */
+ def failed[T](exception: Throwable): Future[T] = Promise.failed(exception).future
+
+ /** Creates an already completed Future with the specified result.
+ *
+ * @tparam T the type of the value in the future
+ * @return the newly created `Future` object
+ */
+ def successful[T](result: T): Future[T] = Promise.successful(result).future
/** Starts an asynchronous computation and returns a `Future` object with the result of that computation.
*
@@ -710,5 +722,12 @@ object Future {
}
}
-
+/** A marker indicating that a `java.lang.Runnable` provided to `scala.concurrent.ExecutionContext`
+ * wraps a callback provided to `Future.onComplete`.
+ * All callbacks provided to a `Future` end up going through `onComplete`, so this allows an
+ * `ExecutionContext` to special-case callbacks that were executed by `Future` if desired.
+ */
+trait OnCompleteRunnable {
+ self: Runnable =>
+}
diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala
index 578642966f..5d1b2c00b6 100644
--- a/src/library/scala/concurrent/Promise.scala
+++ b/src/library/scala/concurrent/Promise.scala
@@ -34,6 +34,15 @@ trait Promise[T] {
*/
def future: Future[T]
+ /** Returns whether the promise has already been completed with
+ * a value or an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return `true` if the promise is already completed, `false` otherwise
+ */
+ def isCompleted: Boolean
+
/** Completes the promise with either an exception or a value.
*
* @param result Either the value or the exception to complete the promise with.
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 4c6347dce0..551a444425 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -13,34 +13,34 @@ package scala.concurrent.impl
import java.util.concurrent.{ Callable, Executor, ExecutorService, Executors, ThreadFactory, TimeUnit }
import java.util.Collection
import scala.concurrent.forkjoin._
-import scala.concurrent.{ ExecutionContext, Awaitable }
+import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, ExecutionContextExecutor, ExecutionContextExecutorService }
import scala.concurrent.util.Duration
import scala.util.control.NonFatal
-private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContext with Executor {
+private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContextExecutor {
val executor: Executor = es match {
case null => createExecutorService
case some => some
}
-
- // to ensure that the current execution context thread local is properly set
- def executorsThreadFactory = new ThreadFactory {
- def newThread(r: Runnable) = new Thread(new Runnable {
- override def run() {
- scala.concurrent.currentExecutionContext.set(ExecutionContextImpl.this)
- r.run()
- }
- })
- }
-
- // to ensure that the current execution context thread local is properly set
+
+ // Implement BlockContext on FJP threads
def forkJoinPoolThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory {
- def newThread(fjp: ForkJoinPool) = new ForkJoinWorkerThread(fjp) {
- override def onStart() {
- scala.concurrent.currentExecutionContext.set(ExecutionContextImpl.this)
+ def newThread(fjp: ForkJoinPool) = new ForkJoinWorkerThread(fjp) with BlockContext {
+ override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = {
+ var result: T = null.asInstanceOf[T]
+ ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker {
+ @volatile var isdone = false
+ def block(): Boolean = {
+ result = awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) // FIXME what happens if there's an exception thrown here?
+ isdone = true
+ true
+ }
+ def isReleasable = isdone
+ })
+ result
}
}
}
@@ -68,7 +68,7 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter:
case NonFatal(t) =>
System.err.println("Failed to create ForkJoinPool for the default ExecutionContext, falling back to Executors.newCachedThreadPool")
t.printStackTrace(System.err)
- Executors.newCachedThreadPool(executorsThreadFactory) //FIXME use the same desired parallelism here too?
+ Executors.newCachedThreadPool() //FIXME use the same desired parallelism here too?
}
def execute(runnable: Runnable): Unit = executor match {
@@ -84,27 +84,6 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter:
case generic => generic execute runnable
}
- def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = {
- Future.releaseStack(this)
-
- executor match {
- case fj: ForkJoinPool =>
- var result: T = null.asInstanceOf[T]
- ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker {
- @volatile var isdone = false
- def block(): Boolean = {
- result = awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) // FIXME what happens if there's an exception thrown here?
- isdone = true
- true
- }
- def isReleasable = isdone
- })
- result
- case _ =>
- awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence)
- }
- }
-
def reportFailure(t: Throwable) = reporter(t)
}
@@ -112,8 +91,8 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter:
private[concurrent] object ExecutionContextImpl {
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 ExecutorService =
- new ExecutionContextImpl(es, reporter) with ExecutorService {
+ def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutionContextExecutorService =
+ new ExecutionContextImpl(es, reporter) with ExecutionContextExecutorService {
final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService]
override def execute(command: Runnable) = executor.execute(command)
override def shutdown() { asExecutorService.shutdown() }
diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala
index 8012ea6a93..073e6c4c9f 100644
--- a/src/library/scala/concurrent/impl/Future.scala
+++ b/src/library/scala/concurrent/impl/Future.scala
@@ -46,11 +46,19 @@ private[concurrent] object Future {
def boxedType(c: Class[_]): Class[_] = if (c.isPrimitive) toBoxed(c) else c
- private[impl] class PromiseCompletingTask[T](override val executor: ExecutionContext, body: => T)
- extends Task {
+ // TODO rename appropriately and make public
+ private[concurrent] def isFutureThrowable(t: Throwable) = t match {
+ case e: Error => false
+ case t: scala.util.control.ControlThrowable => false
+ case i: InterruptedException => false
+ case _ => true
+ }
+
+ private[impl] class PromiseCompletingRunnable[T](body: => T)
+ extends Runnable {
val promise = new Promise.DefaultPromise[T]()
- protected override def task() = {
+ override def run() = {
promise complete {
try Right(body) catch {
case NonFatal(e) =>
@@ -63,90 +71,8 @@ private[concurrent] object Future {
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = {
- val task = new PromiseCompletingTask(executor, body)
- task.dispatch()
-
- task.promise.future
- }
-
- private[impl] val throwableId: Throwable => Throwable = identity _
-
- // an optimization for batching futures
- // TODO we should replace this with a public queue,
- // so that it can be stolen from
- // OR: a push to the local task queue should be so cheap that this is
- // not even needed, but stealing is still possible
-
- private[impl] case class TaskStack(stack: Stack[Task], executor: ExecutionContext)
-
- private val _taskStack = new ThreadLocal[TaskStack]()
-
- private[impl] trait Task extends Runnable {
- def executor: ExecutionContext
-
- // run the original callback (no dispatch)
- protected def task(): Unit
-
- // we implement Runnable to avoid creating
- // an extra object. run() runs ourselves with
- // a TaskStack pushed, and then runs any
- // other tasks that show up in the stack.
- final override def run() = {
- try {
- val taskStack = TaskStack(Stack[Task](this), executor)
- _taskStack set taskStack
- while (taskStack.stack.nonEmpty) {
- val next = taskStack.stack.pop()
- require(next.executor eq executor)
- try next.task() catch { case NonFatal(e) => executor reportFailure e }
- }
- } finally {
- _taskStack.remove()
- }
- }
-
- // send the task to the running executor.execute() via
- // _taskStack, or start a new executor.execute()
- def dispatch(force: Boolean = false): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && (executor eq stack.executor) && !force => stack.stack push this
- case _ => executor.execute(this)
- }
- }
-
- private[impl] class ReleaseTask(override val executor: ExecutionContext, val elems: List[Task])
- extends Task {
- protected override def task() = {
- _taskStack.get.stack.elems = elems
- }
- }
-
- private[impl] def releaseStack(executor: ExecutionContext): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && stack.stack.nonEmpty =>
- val tasks = stack.stack.elems
- stack.stack.clear()
- _taskStack.remove()
- val release = new ReleaseTask(executor, tasks)
- release.dispatch(force=true)
- case null =>
- // do nothing - there is no local batching stack anymore
- case _ =>
- _taskStack.remove()
- }
-
- private[impl] class OnCompleteTask[T](override val executor: ExecutionContext, val onComplete: (Either[Throwable, T]) => Any)
- extends Task {
- private var value: Either[Throwable, T] = null
-
- protected override def task() = {
- require(value ne null) // dispatch(value) must be called before dispatch()
- onComplete(value)
- }
-
- def dispatch(value: Either[Throwable, T]): Unit = {
- this.value = value
- dispatch()
- }
+ val runnable = new PromiseCompletingRunnable(body)
+ executor.execute(runnable)
+ runnable.promise.future
}
}
diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala
index c5060a2368..3ac34bef8a 100644
--- a/src/library/scala/concurrent/impl/Promise.scala
+++ b/src/library/scala/concurrent/impl/Promise.scala
@@ -11,11 +11,12 @@ package scala.concurrent.impl
import java.util.concurrent.TimeUnit.{ NANOSECONDS, MILLISECONDS }
-import scala.concurrent.{ Awaitable, ExecutionContext, blocking, CanAwait, TimeoutException, ExecutionException }
+import scala.concurrent.{ Awaitable, ExecutionContext, blocking, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException }
//import scala.util.continuations._
import scala.concurrent.util.Duration
import scala.util
import scala.annotation.tailrec
+import scala.util.control.NonFatal
//import scala.concurrent.NonDeterministic
@@ -24,6 +25,21 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu
def future: this.type = this
}
+private class CallbackRunnable[T](val executor: ExecutionContext, val onComplete: (Either[Throwable, T]) => Any) extends Runnable with OnCompleteRunnable {
+ // must be filled in before running it
+ var value: Either[Throwable, T] = null
+
+ override def run() = {
+ require(value ne null) // must set value to non-null before running!
+ try onComplete(value) catch { case NonFatal(e) => executor reportFailure e }
+ }
+
+ def executeWithValue(v: Either[Throwable, T]): Unit = {
+ require(value eq null) // can't complete it twice
+ value = v
+ executor.execute(this)
+ }
+}
object Promise {
@@ -94,10 +110,10 @@ object Promise {
val resolved = resolveEither(value)
(try {
@tailrec
- def tryComplete(v: Either[Throwable, T]): List[Future.OnCompleteTask[T]] = {
+ def tryComplete(v: Either[Throwable, T]): List[CallbackRunnable[T]] = {
getState match {
case raw: List[_] =>
- val cur = raw.asInstanceOf[List[Future.OnCompleteTask[T]]]
+ val cur = raw.asInstanceOf[List[CallbackRunnable[T]]]
if (updateState(cur, v)) cur else tryComplete(v)
case _ => null
}
@@ -107,19 +123,19 @@ object Promise {
synchronized { notifyAll() } //Notify any evil blockers
}) match {
case null => false
- case cs if cs.isEmpty => true
- case cs => cs.foreach(c => c.dispatch(resolved)); true
+ case rs if rs.isEmpty => true
+ case rs => rs.foreach(r => r.executeWithValue(resolved)); true
}
}
def onComplete[U](func: Either[Throwable, T] => U)(implicit executor: ExecutionContext): Unit = {
- val bound = new Future.OnCompleteTask[T](executor, func)
+ val runnable = new CallbackRunnable[T](executor, func)
@tailrec //Tries to add the callback, if already completed, it dispatches the callback to be executed
def dispatchOrAddCallback(): Unit =
getState match {
- case r: Either[_, _] => bound.dispatch(r.asInstanceOf[Either[Throwable, T]])
- case listeners: List[_] => if (updateState(listeners, bound :: listeners)) () else dispatchOrAddCallback()
+ case r: Either[_, _] => runnable.executeWithValue(r.asInstanceOf[Either[Throwable, T]])
+ case listeners: List[_] => if (updateState(listeners, runnable :: listeners)) () else dispatchOrAddCallback()
}
dispatchOrAddCallback()
}
@@ -139,7 +155,7 @@ object Promise {
def onComplete[U](func: Either[Throwable, T] => U)(implicit executor: ExecutionContext): Unit = {
val completedAs = value.get
- (new Future.OnCompleteTask(executor, func)).dispatch(completedAs)
+ (new CallbackRunnable(executor, func)).executeWithValue(completedAs)
}
def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
diff --git a/src/library/scala/util/control/NonFatal.scala b/src/library/scala/util/control/NonFatal.scala
index 9da2f63307..5137f0f2f5 100644
--- a/src/library/scala/util/control/NonFatal.scala
+++ b/src/library/scala/util/control/NonFatal.scala
@@ -23,16 +23,23 @@ package scala.util.control
* // dangerous stuff
* } catch {
* case NonFatal(e) => log.error(e, "Something not that bad.")
+ * // or
+ * case e if NonFatal(e) => log.error(e, "Something not that bad.")
* }
* }}}
*/
object NonFatal {
-
- def unapply(t: Throwable): Option[Throwable] = t match {
- case e: StackOverflowError ⇒ Some(e) // StackOverflowError ok even though it is a VirtualMachineError
- // VirtualMachineError includes OutOfMemoryError and other fatal errors
- case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable | _: NotImplementedError => None
- case e ⇒ Some(e)
- }
-
+ /**
+ * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
+ */
+ def apply(t: Throwable): Boolean = t match {
+ case _: StackOverflowError => true // StackOverflowError ok even though it is a VirtualMachineError
+ // VirtualMachineError includes OutOfMemoryError and other fatal errors
+ case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable | _: NotImplementedError => false
+ case _ => true
+ }
+ /**
+ * Returns Some(t) if NonFatal(t) == true, otherwise None
+ */
+ def unapply(t: Throwable): Option[Throwable] = if (apply(t)) Some(t) else None
}
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index eb9921a31a..1d2888961b 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -232,7 +232,31 @@ trait Symbols extends base.Symbols { self: Universe =>
/** The overloaded alternatives of this symbol */
def alternatives: List[Symbol]
- def resolveOverloaded(pre: Type = NoPrefix, targs: Seq[Type] = List(), actuals: Seq[Type]): Symbol
+ /** Performs method overloading resolution. More precisely, resolves an overloaded TermSymbol
+ * to a single, non-overloaded TermSymbol that accepts the specified argument types.
+ * @param pre The prefix type, i.e. the type of the value the method is dispatched on.
+ * This is required when resolving references to type parameters of the type
+ * the method is declared in. For example if the method is declared in class `List[A]`,
+ * providing the prefix as `List[Int]` allows the overloading resolution to use
+ * `Int` instead of `A`.
+ * @param targs Type arguments that a candidate alternative must be able to accept. Candidates
+ * will be considered with these arguments substituted for their corresponding
+ * type parameters.
+ * @param posVargs Positional argument types that a candidate alternative must be able to accept.
+ * @param nameVargs Named argument types that a candidate alternative must be able to accept.
+ * Each element in the sequence should be a pair of a parameter name and an
+ * argument type.
+ * @param expected Return type that a candidate alternative has to be compatible with.
+ * @return Either a single, non-overloaded Symbol referring to the selected alternative
+ * or NoSymbol if no single member could be selected given the passed arguments.
+ */
+ def resolveOverloaded(
+ pre: Type = NoPrefix,
+ targs: Seq[Type] = List(),
+ posVargs: Seq[Type] = List(),
+ nameVargs: Seq[(TermName, Type)] = List(),
+ expected: Type = NoType
+ ): Symbol
}
/** The API of type symbols */
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index 0bf5aa4b69..ad59605760 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -20,7 +20,7 @@ trait BuildUtils extends base.BuildUtils { self: SymbolTable =>
val result = owner.info decl name
if (result ne NoSymbol) result
else
- mirrorThatLoaded(owner).tryMissingHooks(owner, name) orElse
+ mirrorThatLoaded(owner).missingHook(owner, name) orElse
MissingRequirementError.notFound("%s %s in %s".format(if (name.isTermName) "term" else "type", name, owner.fullName))
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7891433b4f..60689d70fe 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -496,6 +496,9 @@ trait Definitions extends api.StandardDefinitions {
def MacroInternal_materializeAbsTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeAbsTypeTag)
def MacroInternal_materializeTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeTypeTag)
+ lazy val StringContextClass = requiredClass[scala.StringContext]
+ def StringContext_f = getMemberMethod(StringContextClass, nme.f)
+
lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature]
lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature]
@@ -1125,6 +1128,39 @@ trait Definitions extends api.StandardDefinitions {
/** Is symbol a phantom class for which no runtime representation exists? */
lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
+ lazy val magicSymbols = List(
+ AnnotationDefaultAttr, // #2264
+ RepeatedParamClass,
+ JavaRepeatedParamClass,
+ ByNameParamClass,
+ AnyClass,
+ AnyRefClass,
+ AnyValClass,
+ NullClass,
+ NothingClass,
+ SingletonClass,
+ EqualsPatternClass,
+ Any_==,
+ Any_!=,
+ Any_equals,
+ Any_hashCode,
+ Any_toString,
+ Any_getClass,
+ Any_isInstanceOf,
+ Any_asInstanceOf,
+ Any_##,
+ Object_eq,
+ Object_ne,
+ Object_==,
+ Object_!=,
+ Object_##,
+ Object_synchronized,
+ Object_isInstanceOf,
+ Object_asInstanceOf,
+ String_+,
+ ComparableClass,
+ JavaSerializableClass
+ )
/** Is the symbol that of a parent which is added during parsing? */
lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass
@@ -1188,41 +1224,7 @@ trait Definitions extends api.StandardDefinitions {
def init() {
if (isInitialized) return
-
- val forced = List( // force initialization of every symbol that is entered as a side effect
- AnnotationDefaultAttr, // #2264
- RepeatedParamClass,
- JavaRepeatedParamClass,
- ByNameParamClass,
- AnyClass,
- AnyRefClass,
- AnyValClass,
- NullClass,
- NothingClass,
- SingletonClass,
- EqualsPatternClass,
- Any_==,
- Any_!=,
- Any_equals,
- Any_hashCode,
- Any_toString,
- Any_getClass,
- Any_isInstanceOf,
- Any_asInstanceOf,
- Any_##,
- Object_eq,
- Object_ne,
- Object_==,
- Object_!=,
- Object_##,
- Object_synchronized,
- Object_isInstanceOf,
- Object_asInstanceOf,
- String_+,
- ComparableClass,
- JavaSerializableClass
- )
-
+ val forced = magicSymbols // force initialization of every symbol that is entered as a side effect
isInitialized = true
} //init
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index dedfd41e83..210af661ee 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -41,7 +41,7 @@ trait Mirrors extends api.Mirrors {
if (result != NoSymbol) result
else {
if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug
- tryMissingHooks(owner, name) orElse {
+ thisMirror.missingHook(owner, name) orElse {
MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror)
}
}
@@ -51,7 +51,7 @@ trait Mirrors extends api.Mirrors {
protected def symbolTableMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name)
- private[reflect] def tryMissingHooks(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name)
+ private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name)
/** If you're looking for a class, pass a type name.
* If a module, a term name.
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index 4ea9b27da9..60b3a6f436 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -4,9 +4,24 @@ package internal
trait StdAttachments {
self: SymbolTable =>
+ /**
+ * Common code between reflect-internal Symbol and Tree related to Attachments.
+ */
+ trait Attachable {
+ protected var rawatt: base.Attachments { type Pos = Position } = NoPosition
+ def attachments = rawatt
+ def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this }
+ def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
+
+ // cannot be final due to SynchronizedSymbols
+ def pos: Position = rawatt.pos
+ def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
+ def setPos(newpos: Position): this.type = { pos = newpos; this }
+ }
+
case object BackquotedIdentifierAttachment
case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
case class MacroExpansionAttachment(original: Tree)
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 72a99589d5..22b0908cab 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -662,6 +662,7 @@ trait StdNames {
val eval: NameType = "eval"
val ex: NameType = "ex"
val experimental: NameType = "experimental"
+ val f: NameType = "f"
val false_ : NameType = "false"
val filter: NameType = "filter"
val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 32330f752a..957202e448 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -10,6 +10,7 @@ import scala.collection.{ mutable, immutable }
import scala.collection.mutable.ListBuffer
import util.Statistics
import Flags._
+import base.Attachments
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
@@ -82,71 +83,280 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def getAnnotations: List[AnnotationInfo] = { initialize; annotations }
def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this }
- private def lastElemType(ts: Seq[Type]): Type = ts.last.normalize.typeArgs.head
+ def resolveOverloaded(
+ pre: Type,
+ targs: Seq[Type],
+ posVargTypes: Seq[Type],
+ nameVargTypes: Seq[(TermName, Type)],
+ expected: Type
+ ): Symbol = {
+
+ // Begin Correlation Helpers
+
+ def isCompatible(tp: Type, pt: Type): Boolean = {
+ def isCompatibleByName(tp: Type, pt: Type): Boolean = pt match {
+ case TypeRef(_, ByNameParamClass, List(res)) if !definitions.isByNameParamType(tp) =>
+ isCompatible(tp, res)
+ case _ =>
+ false
+ }
+ (tp <:< pt) || isCompatibleByName(tp, pt)
+ }
- private def formalTypes(formals: List[Type], nargs: Int): List[Type] = {
- val formals1 = formals mapConserve {
- case TypeRef(_, ByNameParamClass, List(arg)) => arg
- case formal => formal
+ def signatureAsSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = {
+ (substituteTypeParams(method1), substituteTypeParams(method2)) match {
+ case (NullaryMethodType(r1), NullaryMethodType(r2)) =>
+ r1 <:< r2
+ case (NullaryMethodType(_), MethodType(_, _)) =>
+ true
+ case (MethodType(_, _), NullaryMethodType(_)) =>
+ false
+ case (MethodType(p1, _), MethodType(p2, _)) =>
+ val len = p1.length max p2.length
+ val sub = extend(p1 map (_.typeSignature), len)
+ val sup = extend(p2 map (_.typeSignature), len)
+ (sub corresponds sup)(isCompatible)
+ }
}
- if (isVarArgTypes(formals1)) {
- val ft = lastElemType(formals)
- formals1.init ::: List.fill(nargs - (formals1.length - 1))(ft)
- } else formals1
- }
-
- def resolveOverloaded(pre: Type, targs: Seq[Type], actuals: Seq[Type]): Symbol = {
- def firstParams(tpe: Type): (List[Symbol], List[Type]) = tpe match {
- case PolyType(tparams, restpe) =>
- val (Nil, formals) = firstParams(restpe)
- (tparams, formals)
- case MethodType(params, _) =>
- (Nil, params map (_.tpe))
- case _ =>
- (Nil, Nil)
+
+ def scopeMoreSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = {
+ val o1 = method1.owner.asClassSymbol
+ val o2 = method2.owner.asClassSymbol
+ val c1 = if (o1.hasFlag(Flag.MODULE)) o1.companionSymbol else o1
+ val c2 = if (o2.hasFlag(Flag.MODULE)) o2.companionSymbol else o2
+ c1.typeSignature <:< c2.typeSignature
}
- def isApplicable(alt: Symbol, targs: List[Type], actuals: Seq[Type]) = {
- def isApplicableType(tparams: List[Symbol], tpe: Type): Boolean = {
- val (tparams, formals) = firstParams(pre memberType alt)
- val formals1 = formalTypes(formals, actuals.length)
- val actuals1 =
- if (isVarArgTypes(actuals)) {
- if (!isVarArgTypes(formals)) return false
- actuals.init :+ lastElemType(actuals)
- } else actuals
- if (formals1.length != actuals1.length) return false
-
- if (tparams.isEmpty) return (actuals1 corresponds formals1)(_ <:< _)
-
- if (targs.length == tparams.length)
- isApplicableType(List(), tpe.instantiateTypeParams(tparams, targs))
- else if (targs.nonEmpty)
- false
- else {
- val tvars = tparams map (TypeVar(_))
- (actuals1 corresponds formals1) { (actual, formal) =>
- val tp1 = actual.deconst.instantiateTypeParams(tparams, tvars)
- val pt1 = actual.instantiateTypeParams(tparams, tvars)
- tp1 <:< pt1
- } &&
- solve(tvars, tparams, List.fill(tparams.length)(COVARIANT), upper = false)
+
+ def moreSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = {
+ def points(m1: MethodSymbol, m2: MethodSymbol) = {
+ val p1 = if (signatureAsSpecific(m1, m2)) 1 else 0
+ val p2 = if (scopeMoreSpecific(m1, m2)) 1 else 0
+ p1 + p2
+ }
+ points(method1, method2) > points(method2, method1)
+ }
+
+ def combineInto (
+ variadic: Boolean
+ )(
+ positional: Seq[Type],
+ named: Seq[(TermName, Type)]
+ )(
+ target: Seq[TermName],
+ defaults: Map[Int, Type]
+ ): Option[Seq[Type]] = {
+
+ val offset = positional.length
+ val unfilled = target.zipWithIndex drop offset
+ val canAcceptAllNameVargs = named forall { case (argName, _) =>
+ unfilled exists (_._1 == argName)
+ }
+
+ val paramNamesUnique = {
+ named.length == named.map(_._1).distinct.length
+ }
+
+ if (canAcceptAllNameVargs && paramNamesUnique) {
+
+ val rest = unfilled map { case (paramName, paramIndex) =>
+ val passedIn = named.collect {
+ case (argName, argType) if argName == paramName => argType
+ }.headOption
+ if (passedIn isDefined) passedIn
+ else defaults.get(paramIndex).map(_.asInstanceOf[Type])
+ }
+
+ val rest1 = {
+ if (variadic && !rest.isEmpty && !rest.last.isDefined) rest.init
+ else rest
}
+
+
+ if (rest1 forall (_.isDefined)) {
+ val joined = positional ++ rest1.map(_.get)
+ val repeatedCollapsed = {
+ if (variadic) {
+ val (normal, repeated) = joined.splitAt(target.length - 1)
+ if (repeated.forall(_ =:= repeated.head)) Some(normal ++ repeated.headOption)
+ else None
+ }
+ else Some(joined)
+ }
+ if (repeatedCollapsed.exists(_.length == target.length))
+ repeatedCollapsed
+ else if (variadic && repeatedCollapsed.exists(_.length == target.length - 1))
+ repeatedCollapsed
+ else None
+ } else None
+
+ } else None
+ }
+
+ // Begin Reflection Helpers
+
+ // Replaces a repeated parameter type at the end of the parameter list
+ // with a number of non-repeated parameter types in order to pad the
+ // list to be nargs in length
+ def extend(types: Seq[Type], nargs: Int): Seq[Type] = {
+ if (isVarArgTypes(types)) {
+ val repeatedType = types.last.normalize.typeArgs.head
+ types.init ++ Seq.fill(nargs - (types.length - 1))(repeatedType)
+ } else types
+ }
+
+ // Replaces by-name parameters with their result type and
+ // TypeRefs with the thing they reference
+ def unwrap(paramType: Type): Type = paramType match {
+ case TypeRef(_, IntClass, _) => typeOf[Int]
+ case TypeRef(_, LongClass, _) => typeOf[Long]
+ case TypeRef(_, ShortClass, _) => typeOf[Short]
+ case TypeRef(_, ByteClass, _) => typeOf[Byte]
+ case TypeRef(_, CharClass, _) => typeOf[Char]
+ case TypeRef(_, FloatClass, _) => typeOf[Float]
+ case TypeRef(_, DoubleClass, _) => typeOf[Double]
+ case TypeRef(_, BooleanClass, _) => typeOf[Boolean]
+ case TypeRef(_, UnitClass, _) => typeOf[Unit]
+ case TypeRef(_, NullClass, _) => typeOf[Null]
+ case TypeRef(_, AnyClass, _) => typeOf[Any]
+ case TypeRef(_, NothingClass, _) => typeOf[Nothing]
+ case TypeRef(_, AnyRefClass, _) => typeOf[AnyRef]
+ case TypeRef(_, ByNameParamClass, List(resultType)) => unwrap(resultType)
+ case t: Type => t
+ }
+
+ // Gives the names of the parameters to a method
+ def paramNames(signature: Type): Seq[TermName] = signature match {
+ case PolyType(_, resultType) => paramNames(resultType)
+ case MethodType(params, _) => params.map(_.name.asInstanceOf[TermName])
+ case NullaryMethodType(_) => Seq.empty
+ }
+
+ def valParams(signature: Type): Seq[TermSymbol] = signature match {
+ case PolyType(_, resultType) => valParams(resultType)
+ case MethodType(params, _) => params.map(_.asTermSymbol)
+ case NullaryMethodType(_) => Seq.empty
+ }
+
+ // Returns a map from parameter index to default argument type
+ def defaultTypes(method: MethodSymbol): Map[Int, Type] = {
+ val typeSig = substituteTypeParams(method)
+ val owner = method.owner
+ valParams(typeSig).zipWithIndex.filter(_._1.hasFlag(Flag.DEFAULTPARAM)).map { case(_, index) =>
+ val name = nme.defaultGetterName(method.name.decodedName, index + 1)
+ val default = owner.asType member name
+ index -> default.typeSignature.asInstanceOf[NullaryMethodType].resultType
+ }.toMap
+ }
+
+ // True if any of method's parameters have default values. False otherwise.
+ def usesDefault(method: MethodSymbol): Boolean = valParams(method.typeSignature) drop(posVargTypes).length exists { param =>
+ (param hasFlag Flag.DEFAULTPARAM) && nameVargTypes.forall { case (argName, _) =>
+ param.name != argName
+ }
+ }
+
+ // The number of type parameters that the method takes
+ def numTypeParams(x: MethodSymbol): Int = {
+ x.typeSignature.typeParams.length
+ }
+
+ def substituteTypeParams(m: MethodSymbol): Type = {
+ (pre memberType m) match {
+ case m: MethodType => m
+ case n: NullaryMethodType => n
+ case PolyType(tparams, rest) => rest.substituteTypes(tparams, targs.toList)
}
- isApplicableType(List(), pre.memberType(alt))
}
- def isAsGood(alt1: Symbol, alt2: Symbol): Boolean = {
- alt1 == alt2 ||
- alt2 == NoSymbol || {
- val (tparams, formals) = firstParams(pre memberType alt1)
- isApplicable(alt2, tparams map (_.tpe), formals)
+
+ // Begin Selection Helpers
+
+ def select(
+ alternatives: Seq[MethodSymbol],
+ filters: Seq[Seq[MethodSymbol] => Seq[MethodSymbol]]
+ ): Seq[MethodSymbol] =
+ filters.foldLeft(alternatives)((a, f) => {
+ if (a.size > 1) f(a) else a
+ })
+
+ // Drop arguments that take the wrong number of type
+ // arguments.
+ val posTargLength: Seq[MethodSymbol] => Seq[MethodSymbol] = _.filter { alt =>
+ numTypeParams(alt) == targs.length
+ }
+
+ // Drop methods that are not applicable to the arguments
+ val applicable: Seq[MethodSymbol] => Seq[MethodSymbol] = _.filter { alt =>
+ // Note: combine returns None if a is not applicable and
+ // None.exists(_ => true) == false
+ val paramTypes =
+ valParams(substituteTypeParams(alt)).map(p => unwrap(p.typeSignature))
+ val variadic = isVarArgTypes(paramTypes)
+ val maybeArgTypes =
+ combineInto(variadic)(posVargTypes, nameVargTypes)(paramNames(alt.typeSignature), defaultTypes(alt))
+ maybeArgTypes exists { argTypes =>
+ if (isVarArgTypes(argTypes) && !isVarArgTypes(paramTypes)) false
+ else {
+ val a = argTypes
+ val p = extend(paramTypes, argTypes.length)
+ (a corresponds p)(_ <:< _)
}
+ }
}
- assert(isOverloaded)
- val applicables = alternatives filter (isApplicable(_, targs.toList, actuals))
- def winner(alts: List[Symbol]) =
- ((NoSymbol: Symbol) /: alts)((best, alt) => if (isAsGood(alt, best)) alt else best)
- val best = winner(applicables)
- if (best == winner(applicables.reverse)) best else NoSymbol
+
+ // Always prefer methods that don't need to use default
+ // arguments over those that do.
+ // e.g. when resolving foo(1), prefer def foo(x: Int) over
+ // def foo(x: Int, y: Int = 4)
+ val noDefaults: Seq[MethodSymbol] => Seq[MethodSymbol] =
+ _ filterNot usesDefault
+
+ // Try to select the most specific method. If that's not possible,
+ // return all of the candidates (this will likely cause an error
+ // higher up in the call stack)
+ val mostSpecific: Seq[MethodSymbol] => Seq[MethodSymbol] = { alts =>
+ val sorted = alts.sortWith(moreSpecific)
+ val mostSpecific = sorted.head
+ val agreeTest: MethodSymbol => Boolean =
+ moreSpecific(mostSpecific, _)
+ val disagreeTest: MethodSymbol => Boolean =
+ moreSpecific(_, mostSpecific)
+ if (!sorted.tail.forall(agreeTest)) {
+ mostSpecific +: sorted.tail.filterNot(agreeTest)
+ } else if (sorted.tail.exists(disagreeTest)) {
+ mostSpecific +: sorted.tail.filter(disagreeTest)
+ } else {
+ Seq(mostSpecific)
+ }
+ }
+
+ def finalResult(t: Type): Type = t match {
+ case PolyType(_, rest) => finalResult(rest)
+ case MethodType(_, result) => finalResult(result)
+ case NullaryMethodType(result) => finalResult(result)
+ case t: Type => t
+ }
+
+ // If a result type is given, drop alternatives that don't meet it
+ val resultType: Seq[MethodSymbol] => Seq[MethodSymbol] =
+ if (expected == NoType) identity
+ else _.filter { alt =>
+ finalResult(substituteTypeParams(alt)) <:< expected
+ }
+
+ def defaultFilteringOps =
+ Seq(posTargLength, resultType, applicable, noDefaults, mostSpecific)
+
+ // Begin Method Proper
+
+
+ val alts = alternatives.map(_.asMethodSymbol)
+
+ val selection = select(alts, defaultFilteringOps)
+
+ val knownApplicable = applicable(selection)
+
+ if (knownApplicable.size == 1) knownApplicable.head
+ else NoSymbol
}
}
@@ -154,7 +364,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
extends SymbolContextApiImpl
with HasFlags
- with Annotatable[Symbol] {
+ with Annotatable[Symbol]
+ with Attachable {
type AccessBoundaryType = Symbol
type AnnotationType = AnnotationInfo
@@ -176,7 +387,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def rawowner = _rawowner
def rawflags = _rawflags
- private var rawpos = initPos
+ rawatt = initPos
val id = nextId() // identity displayed when -uniqid
//assert(id != 3390, initName)
@@ -189,8 +400,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def validTo = _validTo
def validTo_=(x: Period) { _validTo = x}
- def pos = rawpos
- def setPos(pos: Position): this.type = { this.rawpos = pos; this }
def setName(name: Name): this.type = { this.name = asNameType(name) ; this }
// Update the surrounding scopes
@@ -1612,6 +1821,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
setInfo (this.info cloneInfo clone)
setAnnotations this.annotations
)
+ this.attachments.all.foreach(clone.addAttachment)
if (clone.thisSym != clone)
clone.typeOfThis = (clone.typeOfThis cloneInfo clone)
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index dd13dd4c4c..e92d644f4a 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -15,20 +15,13 @@ trait Trees extends api.Trees { self: SymbolTable =>
private[scala] var nodeCount = 0
- abstract class Tree extends TreeContextApiImpl with Product {
+ abstract class Tree extends TreeContextApiImpl with Attachable with Product {
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
Statistics.incCounter(TreesStats.nodeByType, getClass)
- @inline final def pos: Position = rawatt.pos
- def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
- def setPos(newpos: Position): this.type = { pos = newpos; this }
-
- private var rawatt: Attachments { type Pos = Position } = NoPosition
- def attachments = rawatt
- def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this }
- def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
+ @inline final override def pos: Position = rawatt.pos
private[this] var rawtpe: Type = _
@inline final def tpe = rawtpe
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 757163a074..4d8e932862 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -818,7 +818,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
- missingHook(owner, name) orElse MissingRequirementError.signal(
+ mirrorThatLoaded(owner).missingHook(owner, name) orElse MissingRequirementError.signal(
s"bad reference while unpickling $filename: ${name.longString} not found in ${owner.tpe.widen}"
)
@@ -832,8 +832,10 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
* Similar in intent to what SymbolLoader does (but here we don't have access to
* error reporting, so we rely on the typechecker to report the error).
*/
- def toTypeError(e: MissingRequirementError) =
+ def toTypeError(e: MissingRequirementError) = {
+ // e.printStackTrace()
new TypeError(e.msg)
+ }
/** A lazy type which when completed returns type at index `i`. */
private class LazyTypeRef(i: Int) extends LazyType {
diff --git a/src/reflect/scala/reflect/makro/Universe.scala b/src/reflect/scala/reflect/makro/Universe.scala
index 98046be555..a676f7f1de 100644
--- a/src/reflect/scala/reflect/makro/Universe.scala
+++ b/src/reflect/scala/reflect/makro/Universe.scala
@@ -5,13 +5,24 @@ abstract class Universe extends scala.reflect.api.Universe {
val treeBuild: TreeBuilder { val global: Universe.this.type }
+ trait AttachableApi {
+ /** ... */
+ def attachments: base.Attachments { type Pos = Position }
+
+ /** ... */
+ def addAttachment(attachment: Any): AttachableApi.this.type
+
+ /** ... */
+ def removeAttachment[T: ClassTag]: AttachableApi.this.type
+ }
+
// Symbol extensions ---------------------------------------------------------------
override type Symbol >: Null <: SymbolContextApi
/** The extended API of symbols that's supported in macro context universes
*/
- trait SymbolContextApi extends SymbolApi { this: Symbol =>
+ trait SymbolContextApi extends SymbolApi with AttachableApi { this: Symbol =>
// [Eugene++ to Martin] should we also add mutability methods here (similarly to what's done below for trees)?
// I'm talking about `setAnnotations` and friends
@@ -23,7 +34,7 @@ abstract class Universe extends scala.reflect.api.Universe {
/** The extended API of trees that's supported in macro context universes
*/
- trait TreeContextApi extends TreeApi { this: Tree =>
+ trait TreeContextApi extends TreeApi with AttachableApi { this: Tree =>
/** ... */
def pos_=(pos: Position): Unit
@@ -62,15 +73,6 @@ abstract class Universe extends scala.reflect.api.Universe {
/** ... */
def setSymbol(sym: Symbol): this.type
-
- /** ... */
- def attachments: base.Attachments { type Pos = Position }
-
- /** ... */
- def addAttachment(attachment: Any): this.type
-
- /** ... */
- def removeAttachment[T: ClassTag]: this.type
}
override type SymTree >: Null <: Tree with SymTreeContextApi
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 41955170bd..eae6a3b297 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -999,10 +999,10 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
mirrors(rootToLoader getOrElseUpdate(root, findLoader)).get.get
}
- private def byName(sym: Symbol): (Name, Symbol) = sym.name -> sym
-
- private lazy val phantomTypes: Map[Name, Symbol] =
- Map(byName(definitions.AnyRefClass)) ++ (definitions.isPhantomClass map byName)
+ private lazy val magicSymbols: Map[(String, Name), Symbol] = {
+ def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym
+ Map() ++ (definitions.magicSymbols filter (_.isClass) map mapEntry)
+ }
/** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package
* <owner>.<name>, otherwise return NoSymbol.
@@ -1020,13 +1020,12 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
if (name.isTermName && !owner.isEmptyPackageClass)
return mirror.makeScalaPackage(
if (owner.isRootSymbol) name.toString else owner.fullName+"."+name)
- if (owner.name.toTermName == nme.scala_ && owner.owner.isRoot)
- phantomTypes get name match {
- case Some(tsym) =>
- owner.info.decls enter tsym
- return tsym
- case None =>
- }
+ magicSymbols get (owner.fullName, name) match {
+ case Some(tsym) =>
+ owner.info.decls enter tsym
+ return tsym
+ case None =>
+ }
}
info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass)
super.missingHook(owner, name)