diff options
41 files changed, 471 insertions, 587 deletions
diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala index 0051c3bdec..15e2929ff1 100644 --- a/src/compiler/scala/tools/nsc/Driver.scala +++ b/src/compiler/scala/tools/nsc/Driver.scala @@ -1,10 +1,12 @@ package scala.tools.nsc import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import Properties.{ versionString, copyrightString } +import Properties.{ versionString, copyrightString, residentPromptString } import scala.reflect.internal.util.{ BatchSourceFile, FakePos } abstract class Driver { + + val prompt = residentPromptString val versionMsg = "Scala compiler " + versionString + " -- " + diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index 19c872b6d3..8b7e76e994 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -12,15 +12,13 @@ import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} import scala.reflect.internal.util.{ BatchSourceFile, FakePos } //{Position} -import Properties.{ versionString, copyrightString, residentPromptString, msilLibPath } +import Properties.msilLibPath /** The main class for NSC, a compiler for the programming - * language Scala. + * language Scala. */ object Main extends Driver with EvalLoop { - val prompt = residentPromptString - def resident(compiler: Global) { loop { line => val args = line.split(' ').toList diff --git a/src/compiler/scala/tools/nsc/MainBench.scala b/src/compiler/scala/tools/nsc/MainBench.scala new file mode 100644 index 0000000000..0037de7b94 --- /dev/null +++ b/src/compiler/scala/tools/nsc/MainBench.scala @@ -0,0 +1,48 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools.nsc + +import java.io.File +import File.pathSeparator + +import scala.tools.nsc.interactive.{ RefinedBuildManager, SimpleBuildManager } +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} +import scala.reflect.internal.util.{ BatchSourceFile, FakePos } //{Position} +import Properties.{ versionString, copyrightString, residentPromptString, msilLibPath } +import scala.reflect.internal.util.Statistics + +/** The main class for NSC, a compiler for the programming + * language Scala. + */ +object MainBench extends Driver with EvalLoop { + + lazy val theCompiler = Global(settings, reporter) + + override def newCompiler() = theCompiler + + val NIter = 50 + val NBest = 10 + + override def main(args: Array[String]) = { + val times = new Array[Long](NIter) + var start = System.nanoTime() + for (i <- 0 until NIter) { + if (i == NIter-1) { + theCompiler.settings.Ystatistics.value = true + Statistics.enabled = true + } + process(args) + val end = System.nanoTime() + val duration = (end-start)/1000000 + println(s"${duration}ms") + times(i) = duration + start = end + } + val avg = times.sorted.take(NBest).sum / NBest + println(s"avg shortest $NBest times ${avg}ms") + } +} diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 0c988ceae4..9b4e793241 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -34,8 +34,7 @@ abstract class SymbolLoaders { /** Enter class with given `name` into scope of `root` * and give them `completer` as type. */ - def enterClass(root: Symbol, name: String, completer: SymbolLoader): Symbol = { - val owner = root.ownerOfNewSymbols + def enterClass(owner: Symbol, name: String, completer: SymbolLoader): Symbol = { val clazz = owner.newClass(newTypeName(name)) clazz setInfo completer enterIfNew(owner, clazz, completer) @@ -44,8 +43,7 @@ abstract class SymbolLoaders { /** Enter module with given `name` into scope of `root` * and give them `completer` as type. */ - def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = { - val owner = root.ownerOfNewSymbols + def enterModule(owner: Symbol, name: String, completer: SymbolLoader): Symbol = { val module = owner.newModule(newTermName(name)) module setInfo completer module.moduleClass setInfo moduleClassLoader @@ -217,15 +215,18 @@ abstract class SymbolLoaders { root.setInfo(new PackageClassInfoType(newScope, root)) val sourcepaths = classpath.sourcepaths - for (classRep <- classpath.classes if platform.doLoad(classRep)) { - initializeFromClassPath(root, classRep) + if (!root.isRoot) { + for (classRep <- classpath.classes if platform.doLoad(classRep)) { + initializeFromClassPath(root, classRep) + } } + if (!root.isEmptyPackageClass) { + for (pkg <- classpath.packages) { + enterPackage(root, pkg.name, new PackageLoader(pkg)) + } - for (pkg <- classpath.packages) { - enterPackage(root, pkg.name, new PackageLoader(pkg)) + openPackageModule(root) } - - openPackageModule(root) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 7318538de7..3518316fbb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -119,7 +119,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // those with the DEFAULTPARAM flag, and infer the methods. Looking for the methods // directly requires inspecting the parameter list of every one. That modification // shaved 95% off the time spent in this method. - val defaultGetters = clazz.info.findMember(nme.ANYNAME, 0L, DEFAULTPARAM, false).alternatives + val defaultGetters = clazz.info.findMembers(0L, DEFAULTPARAM) val defaultMethodNames = defaultGetters map (sym => nme.defaultGetterToMethod(sym.name)) defaultMethodNames.distinct foreach { name => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a570cd74d6..9371af4848 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4509,6 +4509,8 @@ trait Typers extends Modes with Adaptations with Tags { assert(errorContainer == null, "Cannot set ambiguous error twice for identifier") errorContainer = tree } + + val fingerPrint: Long = name.fingerPrint var defSym: Symbol = tree.symbol // the directly found symbol var pre: Type = NoPrefix // the prefix type of defSym, if a class member @@ -4547,7 +4549,10 @@ trait Typers extends Modes with Adaptations with Tags { var cx = startingIdentContext while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators pre = cx.enclClass.prefix - defEntry = cx.scope.lookupEntry(name) + defEntry = { + val scope = cx.scope + if ((fingerPrint & scope.fingerPrints) != 0) scope.lookupEntry(name) else null + } if ((defEntry ne null) && qualifies(defEntry.sym)) { // Right here is where SI-1987, overloading in package objects, can be // seen to go wrong. There is an overloaded symbol, but when referring diff --git a/src/library/scala/Double.scala b/src/library/scala/Double.scala index 2ff46c433d..510de92a2a 100644 --- a/src/library/scala/Double.scala +++ b/src/library/scala/Double.scala @@ -370,9 +370,6 @@ object Double extends AnyValCompanion { final val PositiveInfinity = java.lang.Double.POSITIVE_INFINITY final val NegativeInfinity = java.lang.Double.NEGATIVE_INFINITY - @deprecated("use Double.MinPositiveValue instead", "2.9.0") - final val Epsilon = MinPositiveValue - /** The negative number with the greatest (finite) absolute value which is representable * by a Double. Note that it differs from [[java.lang.Double.MIN_VALUE]], which * is the smallest positive value representable by a Double. In Scala that number diff --git a/src/library/scala/Float.scala b/src/library/scala/Float.scala index bd7a07fece..b9c116da0b 100644 --- a/src/library/scala/Float.scala +++ b/src/library/scala/Float.scala @@ -370,9 +370,6 @@ object Float extends AnyValCompanion { final val PositiveInfinity = java.lang.Float.POSITIVE_INFINITY final val NegativeInfinity = java.lang.Float.NEGATIVE_INFINITY - @deprecated("use Float.MinPositiveValue instead", "2.9.0") - final val Epsilon = MinPositiveValue - /** The negative number with the greatest (finite) absolute value which is representable * by a Float. Note that it differs from [[java.lang.Float.MIN_VALUE]], which * is the smallest positive value representable by a Float. In Scala that number diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala index a5b878c546..640560a174 100644 --- a/src/library/scala/concurrent/BlockContext.scala +++ b/src/library/scala/concurrent/BlockContext.scala @@ -12,9 +12,10 @@ import java.lang.Thread import scala.concurrent.util.Duration /** - * A context to be notified by `scala.concurrent.blocking()` when + * 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()` + * the implementation for `scala.concurrent.Await`. + * `scala.concurrent.Await.result()` and `scala.concurrent.Await.ready()` * 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`. @@ -27,11 +28,11 @@ import scala.concurrent.util.Duration * {{{ * val oldContext = BlockContext.current * val myContext = new BlockContext { - * override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = { + * override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): 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) + * oldContext.blockOn(thunk) * } * } * BlockContext.withBlockContext(myContext) { @@ -42,35 +43,33 @@ import scala.concurrent.util.Duration */ trait BlockContext { - /** Used internally by the framework; blocks execution for at most - * `atMost` time while waiting for an `awaitable` object to become ready. + /** Used internally by the framework; + * Designates (and eventually executes) a thunk which potentially blocks the calling `Thread`. * - * 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`. + * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead. */ - def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T + def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T } object BlockContext { private object DefaultBlockContext extends BlockContext { - override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = - awaitable.result(atMost)(Await.canAwaitEvidence) + override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk } - private val contextLocal = new ThreadLocal[BlockContext]() { - override def initialValue = Thread.currentThread match { + private val contextLocal = new ThreadLocal[BlockContext]() + + /** Obtain the current thread's current `BlockContext`. */ + def current: BlockContext = contextLocal.get match { + case null => Thread.currentThread match { case ctx: BlockContext => ctx case _ => DefaultBlockContext } + case some => some } - /** 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 + val old = contextLocal.get // can be null try { contextLocal.set(blockContext) body diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index f82b79cb18..d24fdbf005 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -707,11 +707,9 @@ object Future { // doesn't need to create defaultExecutionContext as // a side effect. private[concurrent] object InternalCallbackExecutor extends ExecutionContext { - def execute(runnable: Runnable): Unit = + override def execute(runnable: Runnable): Unit = runnable.run() - def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = - throw new IllegalStateException("bug in scala.concurrent, called blocking() from internal callback") - def reportFailure(t: Throwable): Unit = + override def reportFailure(t: Throwable): Unit = throw new IllegalStateException("problem in scala.concurrent internal callback", t) } } diff --git a/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled b/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled deleted file mode 100644 index 241efa8857..0000000000 --- a/src/library/scala/concurrent/default/SchedulerImpl.scala.disabled +++ /dev/null @@ -1,44 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent -package default - -import scala.concurrent.util.Duration - -private[concurrent] final class SchedulerImpl extends Scheduler { - private val timer = - new java.util.Timer(true) // the associated thread runs as a daemon - - def schedule(delay: Duration, frequency: Duration)(thunk: => Unit): Cancellable = ??? - - def scheduleOnce(delay: Duration, task: Runnable): Cancellable = { - val timerTask = new java.util.TimerTask { - def run(): Unit = - task.run() - } - timer.schedule(timerTask, delay.toMillis) - new Cancellable { - def cancel(): Unit = - timerTask.cancel() - } - } - - def scheduleOnce(delay: Duration)(task: => Unit): Cancellable = { - val timerTask = new java.util.TimerTask { - def run(): Unit = - task - } - timer.schedule(timerTask, delay.toMillis) - new Cancellable { - def cancel(): Unit = - timerTask.cancel() - } - } - -} diff --git a/src/library/scala/concurrent/default/TaskImpl.scala.disabled b/src/library/scala/concurrent/default/TaskImpl.scala.disabled deleted file mode 100644 index 8b4eb12d4f..0000000000 --- a/src/library/scala/concurrent/default/TaskImpl.scala.disabled +++ /dev/null @@ -1,313 +0,0 @@ -package scala.concurrent -package default - - - -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater -import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveAction, ForkJoinWorkerThread } -import scala.util.Try -import scala.util -import scala.concurrent.util.Duration -import scala.annotation.tailrec -import scala.util.control.NonFatal - - -private[concurrent] trait Completable[T] { -self: Future[T] => - - val executor: ExecutionContextImpl - - def newPromise[S]: Promise[S] = executor promise - - type Callback = Try[T] => Any - - def getState: State[T] - - def casState(oldv: State[T], newv: State[T]): Boolean - - protected def dispatch[U](r: Runnable) = executionContext execute r - - protected def processCallbacks(cbs: List[Callback], r: Try[T]) = - for (cb <- cbs) dispatch(new Runnable { - override def run() = cb(r) - }) - - def future: Future[T] = self - - def onComplete[U](callback: Try[T] => U): this.type = { - @tailrec def tryAddCallback(): Try[T] = { - getState match { - case p @ Pending(lst) => - val pt = p.asInstanceOf[Pending[T]] - if (casState(pt, Pending(callback :: pt.callbacks))) null - else tryAddCallback() - case Success(res) => util.Success(res) - case Failure(t) => util.Failure(t) - } - } - - val res = tryAddCallback() - if (res != null) dispatch(new Runnable { - override def run() = - try callback(res) - catch handledFutureException andThen { - t => Console.err.println(t) - } - }) - - this - } - - def isTimedout: Boolean = getState match { - case Failure(ft: FutureTimeoutException) => true - case _ => false - } - -} - -private[concurrent] class PromiseImpl[T](context: ExecutionContextImpl) -extends Promise[T] with Future[T] with Completable[T] { - - val executor: scala.concurrent.default.ExecutionContextImpl = context - - @volatile private var state: State[T] = _ - - val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[PromiseImpl[T]], classOf[State[T]], "state") - - updater.set(this, Pending(List())) - - def casState(oldv: State[T], newv: State[T]): Boolean = { - updater.compareAndSet(this, oldv, newv) - } - - def getState: State[T] = { - updater.get(this) - } - - @tailrec private def tryCompleteState(completed: State[T]): List[Callback] = (getState: @unchecked) match { - case p @ Pending(cbs) => if (!casState(p, completed)) tryCompleteState(completed) else cbs - case _ => null - } - - def tryComplete(r: Try[T]) = r match { - case util.Failure(t) => tryFailure(t) - case util.Success(v) => trySuccess(v) - } - - override def trySuccess(value: T): Boolean = { - val cbs = tryCompleteState(Success(value)) - if (cbs == null) - false - else { - processCallbacks(cbs, util.Success(value)) - this.synchronized { - this.notifyAll() - } - true - } - } - - override def tryFailure(t: Throwable): Boolean = { - val wrapped = wrap(t) - val cbs = tryCompleteState(Failure(wrapped)) - if (cbs == null) - false - else { - processCallbacks(cbs, util.Failure(wrapped)) - this.synchronized { - this.notifyAll() - } - true - } - } - - def await(atMost: Duration)(implicit canawait: scala.concurrent.CanAwait): T = getState match { - case Success(res) => res - case Failure(t) => throw t - case _ => - this.synchronized { - while (true) - getState match { - case Pending(_) => this.wait() - case Success(res) => return res - case Failure(t) => throw t - } - } - sys.error("unreachable") - } - -} - -private[concurrent] class TaskImpl[T](context: ExecutionContextImpl, body: => T) -extends RecursiveAction with Task[T] with Future[T] with Completable[T] { - - val executor: ExecutionContextImpl = context - - @volatile private var state: State[T] = _ - - val updater = AtomicReferenceFieldUpdater.newUpdater(classOf[TaskImpl[T]], classOf[State[T]], "state") - - updater.set(this, Pending(List())) - - def casState(oldv: State[T], newv: State[T]): Boolean = { - updater.compareAndSet(this, oldv, newv) - } - - def getState: State[T] = { - updater.get(this) - } - - @tailrec private def tryCompleteState(completed: State[T]): List[Callback] = (getState: @unchecked) match { - case p @ Pending(cbs) => if (!casState(p, completed)) tryCompleteState(completed) else cbs - } - - def compute(): Unit = { - var cbs: List[Callback] = null - try { - val res = body - processCallbacks(tryCompleteState(Success(res)), util.Success(res)) - } catch { - case t if NonFatal(t) => - processCallbacks(tryCompleteState(Failure(t)), util.Failure(t)) - case t => - val ee = new ExecutionException(t) - processCallbacks(tryCompleteState(Failure(ee)), util.Failure(ee)) - throw t - } - } - - def start(): Unit = { - Thread.currentThread match { - case fj: ForkJoinWorkerThread if fj.getPool eq executor.pool => fork() - case _ => executor.pool.execute(this) - } - } - - // TODO FIXME: handle timeouts - def await(atMost: Duration): this.type = - await - - def await: this.type = { - this.join() - this - } - - def tryCancel(): Unit = - tryUnfork() - - def await(atMost: Duration)(implicit canawait: CanAwait): T = { - join() // TODO handle timeout also - (updater.get(this): @unchecked) match { - case Success(r) => r - case Failure(t) => throw t - } - } - -} - - -private[concurrent] sealed abstract class State[T] - - -case class Pending[T](callbacks: List[Try[T] => Any]) extends State[T] - - -case class Success[T](result: T) extends State[T] - - -case class Failure[T](throwable: Throwable) extends State[T] - - -private[concurrent] final class ExecutionContextImpl extends ExecutionContext { - import ExecutionContextImpl._ - - val pool = { - val p = new ForkJoinPool - p.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler { - def uncaughtException(t: Thread, throwable: Throwable) { - Console.err.println(throwable.getMessage) - throwable.printStackTrace(Console.err) - } - }) - p - } - - @inline - private def executeTask(task: RecursiveAction) { - if (Thread.currentThread.isInstanceOf[ForkJoinWorkerThread]) - task.fork() - else - pool execute task - } - - def execute(task: Runnable) { - val action = new RecursiveAction { def compute() { task.run() } } - executeTask(action) - } - - def execute[U](body: () => U) { - val action = new RecursiveAction { def compute() { body() } } - executeTask(action) - } - - def task[T](body: => T): Task[T] = { - new TaskImpl(this, body) - } - - def future[T](body: => T): Future[T] = { - val t = task(body) - t.start() - t.future - } - - def promise[T]: Promise[T] = - new PromiseImpl[T](this) - - def blocking[T](atMost: Duration)(body: =>T): T = blocking(body2awaitable(body), atMost) - - def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = { - currentExecutionContext.get match { - case null => awaitable.await(atMost)(null) // outside - TODO - fix timeout case - case x if x eq this => this.blockingCall(awaitable) // inside an execution context thread on this executor - case x => x.blocking(awaitable, atMost) - } - } - - private def blockingCall[T](b: Awaitable[T]): T = b match { - case fj: TaskImpl[_] if fj.executor.pool eq pool => - fj.await(Duration.fromNanos(0)) - case _ => - var res: T = null.asInstanceOf[T] - @volatile var blockingDone = false - // TODO add exception handling here! - val mb = new ForkJoinPool.ManagedBlocker { - def block() = { - res = b.await(Duration.fromNanos(0))(CanAwaitEvidence) - blockingDone = true - true - } - def isReleasable = blockingDone - } - ForkJoinPool.managedBlock(mb, true) - res - } - - def reportFailure(t: Throwable): Unit = {} - -} - - -object ExecutionContextImpl { - - private[concurrent] def currentExecutionContext: ThreadLocal[ExecutionContext] = new ThreadLocal[ExecutionContext] { - override protected def initialValue = null - } - -} - - - - - - - diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 98f821652f..875a558887 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -13,7 +13,7 @@ package scala.concurrent.impl import java.util.concurrent.{ LinkedBlockingQueue, Callable, Executor, ExecutorService, Executors, ThreadFactory, TimeUnit, ThreadPoolExecutor } import java.util.Collection import scala.concurrent.forkjoin._ -import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, ExecutionContextExecutor, ExecutionContextExecutorService } +import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService } import scala.concurrent.util.Duration import scala.util.control.NonFatal @@ -37,15 +37,15 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: def newThread(runnable: Runnable): Thread = wire(new Thread(runnable)) def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = wire(new ForkJoinWorkerThread(fjp) with BlockContext { - override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = { + override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { var result: T = null.asInstanceOf[T] ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { @volatile var isdone = false - def block(): Boolean = { - result = try awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) finally { isdone = true } + override def block(): Boolean = { + result = try thunk finally { isdone = true } true } - def isReleasable = isdone + override def isReleasable = isdone }) result } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 132e1d79e7..098008e958 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -10,31 +10,13 @@ package scala.concurrent.impl -import scala.concurrent.util.Duration -import scala.concurrent.{Awaitable, ExecutionContext, CanAwait} -import scala.collection.mutable.Stack +import scala.concurrent.ExecutionContext import scala.util.control.NonFatal -private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { - -} private[concurrent] object Future { - - /** Wraps a block of code into an awaitable object. */ - private[concurrent] def body2awaitable[T](body: =>T) = new Awaitable[T] { - def ready(atMost: Duration)(implicit permit: CanAwait) = { - body - this - } - def result(atMost: Duration)(implicit permit: CanAwait) = body - } - - def boxedType(c: Class[_]): Class[_] = if (c.isPrimitive) scala.concurrent.Future.toBoxed(c) else c - - private[impl] class PromiseCompletingRunnable[T](body: => T) - extends Runnable { + class PromiseCompletingRunnable[T](body: => T) extends Runnable { val promise = new Promise.DefaultPromise[T]() override def run() = { @@ -44,7 +26,7 @@ private[concurrent] object Future { } } - def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = { + def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = { 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 84638586cf..c2df9ac296 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -18,7 +18,7 @@ import scala.util.control.NonFatal -private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Future[T] { +private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] { def future: this.type = this } diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index 76703bf081..a6488b602f 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -9,6 +9,7 @@ package scala import scala.concurrent.util.Duration +import scala.annotation.implicitNotFound /** This package object contains primitives for concurrent and parallel programming. */ @@ -17,6 +18,41 @@ package object concurrent { type CancellationException = java.util.concurrent.CancellationException type TimeoutException = java.util.concurrent.TimeoutException + @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.") + sealed trait CanAwait + private implicit object AwaitPermission extends CanAwait + + /** + * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. + */ + object Await { + /** + * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. + * ready() blocks until the awaitable has completed or the timeout expires. + * + * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`. + * @param awaitable the `Awaitable` on which `ready` is to be called + * @param atMost the maximum timeout for which to wait + * @return the result of `awaitable.ready` which is defined to be the awaitable itself. + */ + @throws(classOf[TimeoutException]) + def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = + blocking(awaitable.ready(atMost)) + + /** + * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. + * result() blocks until the awaitable has completed or the timeout expires. + * + * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`. + * @param awaitable the `Awaitable` on which `result` is to be called + * @param atMost the maximum timeout for which to wait + * @return the result of `awaitable.result` + */ + @throws(classOf[Exception]) + def result[T](awaitable: Awaitable[T], atMost: Duration): T = + blocking(awaitable.result(atMost)) + } + /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. * * The result becomes available once the asynchronous computation is completed. @@ -36,46 +72,18 @@ package object concurrent { */ def promise[T]()(implicit execctx: ExecutionContext): Promise[T] = Promise[T]() - /** Used to block on a piece of code which potentially blocks. + /** Used to designate a piece of code which potentially blocks, allowing the BlockContext to adjust the runtime's behavior. + * Properly marking blocking code may improve performance or avoid deadlocks. * - * @param body A piece of code which contains potentially blocking or long running calls. - * - * Calling this method may throw the following exceptions: - * - CancellationException - if the computation was cancelled - * - 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) - - /** Blocks on an awaitable object. + * If you have an `Awaitable` then you should use Await.result instead of `blocking`. * - * @param awaitable An object with a `block` method which runs potentially blocking or long running calls. + * @param body A piece of code which contains potentially blocking or long running calls. * * Calling this method may throw the following exceptions: * - CancellationException - if the computation was cancelled * - 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 = - BlockContext.current.internalBlockingCall(awaitable, atMost) -} - -/* concurrency constructs */ -package concurrent { - - sealed trait CanAwait - - object Await { - private[concurrent] implicit val canAwaitEvidence = new CanAwait {} - - def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = { - blocking(awaitable, atMost) - awaitable - } - - def result[T](awaitable: Awaitable[T], atMost: Duration): T = { - blocking(awaitable, atMost) - } - - } + @throws(classOf[Exception]) + def blocking[T](body: =>T): T = BlockContext.current.blockOn(body) } diff --git a/src/partest/scala/tools/partest/nest/DirectRunner.scala b/src/partest/scala/tools/partest/nest/DirectRunner.scala index 6c239721c3..c254472342 100644 --- a/src/partest/scala/tools/partest/nest/DirectRunner.scala +++ b/src/partest/scala/tools/partest/nest/DirectRunner.scala @@ -59,8 +59,12 @@ trait DirectRunner { val futures = kindFiles map (f => (f, pool submit callable(manager runTest f))) toMap pool.shutdown() - if (!pool.awaitTermination(4, TimeUnit.HOURS)) + try if (!pool.awaitTermination(4, TimeUnit.HOURS)) NestUI.warning("Thread pool timeout elapsed before all tests were complete!") + catch { case t: InterruptedException => + NestUI.warning("Thread pool was interrupted") + t.printStackTrace() + } for ((file, future) <- futures) yield { val state = if (future.isCancelled) TestState.Timeout else future.get diff --git a/src/reflect/scala/reflect/api/StandardNames.scala b/src/reflect/scala/reflect/api/StandardNames.scala index 9ec66b8531..eb1ecda900 100644 --- a/src/reflect/scala/reflect/api/StandardNames.scala +++ b/src/reflect/scala/reflect/api/StandardNames.scala @@ -43,7 +43,6 @@ trait StandardNames extends base.StandardNames { val SUPER_PREFIX_STRING: String val TRAIT_SETTER_SEPARATOR_STRING: String - val ANYNAME: TermName val FAKE_LOCAL_THIS: TermName val INITIALIZER: TermName val LAZY_LOCAL: TermName diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 210af661ee..761b993539 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -180,7 +180,7 @@ trait Mirrors extends api.Mirrors { // Still fiddling with whether it's cleaner to do some of this setup here // or from constructors. The latter approach tends to invite init order issues. - EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass) + EmptyPackageClass setInfo rootLoader EmptyPackage setInfo EmptyPackageClass.tpe connectModuleToClass(EmptyPackage, EmptyPackageClass) @@ -231,7 +231,6 @@ trait Mirrors extends api.Mirrors { override def isEffectiveRoot = true override def isStatic = true override def isNestedClass = false - override def ownerOfNewSymbols = EmptyPackageClass } // The empty package, which holds all top level types without given packages. final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 20da38fd63..72e6707f57 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -415,6 +415,9 @@ trait Names extends api.Names with LowPriorityNames { } else toString } + + @inline + final def fingerPrint: Long = (1L << start) /** TODO - find some efficiency. */ def append(ch: Char) = newName("" + this + ch) diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala index ceacd2afb0..89e3c52de6 100644 --- a/src/reflect/scala/reflect/internal/Scopes.scala +++ b/src/reflect/scala/reflect/internal/Scopes.scala @@ -41,10 +41,15 @@ trait Scopes extends api.Scopes { self: SymbolTable => * This is necessary because when run from reflection every scope needs to have a * SynchronizedScope as mixin. */ - class Scope protected[Scopes] (initElems: ScopeEntry = null) extends Iterable[Symbol] { + class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends Iterable[Symbol] { + + /** A bitset containing the last 6 bits of the start value of every name + * stored in this scope. + */ + var fingerPrints: Long = initFingerPrints protected[Scopes] def this(base: Scope) = { - this(base.elems) + this(base.elems, base.fingerPrints) nestinglevel = base.nestinglevel + 1 } @@ -95,7 +100,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => * * @param e ... */ - protected def enter(e: ScopeEntry) { + protected def enterEntry(e: ScopeEntry) { elemsCache = null if (hashtable ne null) enterInHash(e) @@ -113,7 +118,11 @@ trait Scopes extends api.Scopes { self: SymbolTable => * * @param sym ... */ - def enter[T <: Symbol](sym: T): T = { enter(newScopeEntry(sym, this)); sym } + def enter[T <: Symbol](sym: T): T = { + fingerPrints |= sym.name.fingerPrint + enterEntry(newScopeEntry(sym, this)) + sym + } /** enter a symbol, asserting that no symbol with same name exists in scope * @@ -147,6 +156,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => } def rehash(sym: Symbol, newname: Name) { + fingerPrints |= newname.fingerPrint if (hashtable ne null) { val index = sym.name.start & HASHMASK var e1 = hashtable(index) @@ -344,7 +354,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => /** The empty scope (immutable). */ object EmptyScope extends Scope { - override def enter(e: ScopeEntry) { + override def enterEntry(e: ScopeEntry) { abort("EmptyScope.enter") } } diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 165e04863c..c8a2424118 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -297,7 +297,7 @@ trait StdNames { val WHILE_PREFIX = "while$" // Compiler internal names - val ANYNAME: NameType = "<anyname>" + val ANYname: NameType = "<anyname>" val CONSTRUCTOR: NameType = "<init>" val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$" val FAKE_LOCAL_THIS: NameType = "this$" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index fab5c5a2e7..d484617767 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -813,11 +813,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def isEffectiveRoot = false - /** For RootClass, this is EmptyPackageClass. For all other symbols, - * the symbol itself. - */ - def ownerOfNewSymbols = this - final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol final def isOverridableMember = !(isClass || isEffectivelyFinal) && (this ne NoSymbol) && owner.isClass diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index f3dd1f03ad..01679a777d 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -14,6 +14,7 @@ import Flags._ import scala.util.control.ControlThrowable import scala.annotation.tailrec import util.Statistics +import scala.runtime.ObjectRef /* A standard type pattern match: case ErrorType => @@ -668,7 +669,8 @@ trait Types extends api.Types { self: SymbolTable => * Note: unfortunately it doesn't work to exclude DEFERRED this way. */ def membersBasedOnFlags(excludedFlags: Long, requiredFlags: Long): List[Symbol] = - findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives + findMembers(excludedFlags, requiredFlags) +// findMember(nme.ANYNAME, excludedFlags, requiredFlags, false).alternatives def memberBasedOnName(name: Name, excludedFlags: Long): Symbol = findMember(name, excludedFlags, 0, false) @@ -1018,6 +1020,72 @@ trait Types extends api.Types { self: SymbolTable => else (baseClasses.head.newOverloaded(this, alts)) } + def findMembers(excludedFlags: Long, requiredFlags: Long): List[Symbol] = { + // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by + // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements + // without this, the matchesType call would lead to type variables on both sides + // of a subtyping/equality judgement, which can lead to recursive types being constructed. + // See (t0851) for a situation where this happens. + val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this) + + Statistics.incCounter(findMembersCount) + val start = Statistics.pushTimer(typeOpsStack, findMembersNanos) + + //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG + var members: Scope = null + var required = requiredFlags + var excluded = excludedFlags | DEFERRED + var continue = true + var self: Type = null + while (continue) { + continue = false + val bcs0 = baseClasses + var bcs = bcs0 + while (!bcs.isEmpty) { + val decls = bcs.head.info.decls + var entry = decls.elems + while (entry ne null) { + val sym = entry.sym + val flags = sym.flags + if ((flags & required) == required) { + val excl = flags & excluded + if (excl == 0L && + (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. + (bcs eq bcs0) || + (flags & PrivateLocal) != PrivateLocal || + (bcs0.head.hasTransOwner(bcs.head)))) { + if (members eq null) members = newScope + var others: ScopeEntry = members.lookupEntry(sym.name) + var symtpe: Type = null + while ((others ne null) && { + val other = others.sym + (other ne sym) && + ((other.owner eq sym.owner) || + (flags & PRIVATE) != 0 || { + if (self eq null) self = this.narrow + if (symtpe eq null) symtpe = self.memberType(sym) + !(self.memberType(other) matches symtpe) + })}) { + others = members lookupNextEntry others + } + if (others eq null) members enter sym + } else if (excl == DEFERRED) { + continue = true + } + } + entry = entry.next + } // while (entry ne null) + // excluded = excluded | LOCAL + bcs = bcs.tail + } // while (!bcs.isEmpty) + required |= DEFERRED + excluded &= ~(DEFERRED.toLong) + } // while (continue) + Statistics.popTimer(typeOpsStack, start) + if (suspension ne null) suspension foreach (_.suspended = false) + if (members eq null) Nil else members.toList + } + /** * Find member(s) in this type. If several members matching criteria are found, they are * returned in an OverloadedSymbol @@ -1040,75 +1108,83 @@ trait Types extends api.Types { self: SymbolTable => val start = Statistics.pushTimer(typeOpsStack, findMemberNanos) //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG - var members: Scope = null var member: Symbol = NoSymbol + var members: List[Symbol] = null + var lastM: ::[Symbol] = null + var membertpe: Type = null + var required = requiredFlags var excluded = excludedFlags | DEFERRED var continue = true var self: Type = null - var membertpe: Type = null + val fingerPrint: Long = name.fingerPrint + while (continue) { continue = false val bcs0 = baseClasses var bcs = bcs0 while (!bcs.isEmpty) { val decls = bcs.head.info.decls - var entry = - if (name == nme.ANYNAME) decls.elems else decls.lookupEntry(name) - while (entry ne null) { - val sym = entry.sym - if (sym hasAllFlags requiredFlags) { - val excl = sym.getFlag(excluded) - if (excl == 0L && - (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. - (bcs eq bcs0) || - !sym.isPrivateLocal || - (bcs0.head.hasTransOwner(bcs.head)))) { - if (name.isTypeName || stableOnly && sym.isStable) { - Statistics.popTimer(typeOpsStack, start) - if (suspension ne null) suspension foreach (_.suspended = false) - return sym - } else if (member == NoSymbol) { - member = sym - } else if (members eq null) { - if (member.name != sym.name || - !(member == sym || - member.owner != sym.owner && - !sym.isPrivate && { - if (self eq null) self = this.narrow - if (membertpe eq null) membertpe = self.memberType(member) - (membertpe matches self.memberType(sym)) - })) { - members = newScope - members enter member - members enter sym - } - } else { - var prevEntry = members.lookupEntry(sym.name) - var symtpe: Type = null - while ((prevEntry ne null) && - !(prevEntry.sym == sym || - prevEntry.sym.owner != sym.owner && - !sym.hasFlag(PRIVATE) && { - if (self eq null) self = this.narrow - if (symtpe eq null) symtpe = self.memberType(sym) - self.memberType(prevEntry.sym) matches symtpe - })) { - prevEntry = members lookupNextEntry prevEntry - } - if (prevEntry eq null) { - members enter sym + if ((fingerPrint & decls.fingerPrints) != 0) { + var entry = decls.lookupEntry(name) + while (entry ne null) { + val sym = entry.sym + val flags = sym.flags + if ((flags & required) == required) { + val excl = flags & excluded + if (excl == 0L && + (// omit PRIVATE LOCALS unless selector class is contained in class owning the def. + (bcs eq bcs0) || + (flags & PrivateLocal) != PrivateLocal || + (bcs0.head.hasTransOwner(bcs.head)))) { + if (name.isTypeName || stableOnly && sym.isStable) { + Statistics.popTimer(typeOpsStack, start) + if (suspension ne null) suspension foreach (_.suspended = false) + return sym + } else if (member eq NoSymbol) { + member = sym + } else if (members eq null) { + if ((member ne sym) && + ((member.owner eq sym.owner) || + (flags & PRIVATE) != 0 || { + if (self eq null) self = this.narrow + if (membertpe eq null) membertpe = self.memberType(member) + !(membertpe matches self.memberType(sym)) + })) { + lastM = new ::(sym, null) + members = member :: lastM + } + } else { + var others: List[Symbol] = members + var symtpe: Type = null + while ((others ne null) && { + val other = others.head + (other ne sym) && + ((other.owner eq sym.owner) || + (flags & PRIVATE) != 0 || { + if (self eq null) self = this.narrow + if (symtpe eq null) symtpe = self.memberType(sym) + !(self.memberType(other) matches symtpe) + })}) { + others = others.tail + } + if (others eq null) { + val lastM1 = new ::(sym, null) + lastM.tl = lastM1 + lastM = lastM1 + } } + } else if (excl == DEFERRED) { + continue = true } - } else if (excl == DEFERRED.toLong) { - continue = true } - } - entry = if (name == nme.ANYNAME) entry.next else decls lookupNextEntry entry - } // while (entry ne null) + entry = decls lookupNextEntry entry + } // while (entry ne null) + } // if (fingerPrint matches) // excluded = excluded | LOCAL bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail } // while (!bcs.isEmpty) - excluded = excludedFlags + required |= DEFERRED + excluded &= ~(DEFERRED.toLong) } // while (continue) Statistics.popTimer(typeOpsStack, start) if (suspension ne null) suspension foreach (_.suspended = false) @@ -1117,9 +1193,11 @@ trait Types extends api.Types { self: SymbolTable => member } else { Statistics.incCounter(multMemberCount) - baseClasses.head.newOverloaded(this, members.toList) + lastM.tl = Nil + baseClasses.head.newOverloaded(this, members) } } + /** The (existential or otherwise) skolems and existentially quantified variables which are free in this type */ def skolemsExceptMethodTypeParams: List[Symbol] = { var boundSyms: List[Symbol] = List() @@ -1610,8 +1688,13 @@ trait Types extends api.Types { self: SymbolTable => if (period != currentPeriod) { tpe.baseClassesPeriod = currentPeriod if (!isValidForBaseClasses(period)) { - tpe.baseClassesCache = null - tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail) + val start = Statistics.pushTimer(typeOpsStack, baseClassesNanos) + try { + tpe.baseClassesCache = null + tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail) + } finally { + Statistics.popTimer(typeOpsStack, start) + } } } if (tpe.baseClassesCache eq null) @@ -5066,7 +5149,7 @@ trait Types extends api.Types { self: SymbolTable => */ def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(nme.ANYNAME).setInfo(pre.widen) + val dummy = currentOwner.enclClass.newValue(nme.ANYname).setInfo(pre.widen) singleType(ThisType(currentOwner.enclClass), dummy) } def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { @@ -6909,14 +6992,17 @@ object TypesStats { val lubCount = Statistics.newCounter ("#toplevel lubs/glbs") val nestedLubCount = Statistics.newCounter ("#all lubs/glbs") val findMemberCount = Statistics.newCounter ("#findMember ops") + val findMembersCount = Statistics.newCounter ("#findMembers ops") val noMemberCount = Statistics.newSubCounter(" of which not found", findMemberCount) val multMemberCount = Statistics.newSubCounter(" of which multiple overloaded", findMemberCount) val typerNanos = Statistics.newTimer ("time spent typechecking", "typer") val lubNanos = Statistics.newStackableTimer("time spent in lubs", typerNanos) val subtypeNanos = Statistics.newStackableTimer("time spent in <:<", typerNanos) val findMemberNanos = Statistics.newStackableTimer("time spent in findmember", typerNanos) + val findMembersNanos = Statistics.newStackableTimer("time spent in findmembers", typerNanos) val asSeenFromNanos = Statistics.newStackableTimer("time spent in asSeenFrom", typerNanos) val baseTypeSeqNanos = Statistics.newStackableTimer("time spent in baseTypeSeq", typerNanos) + val baseClassesNanos = Statistics.newStackableTimer("time spent in baseClasses", typerNanos) val compoundBaseTypeSeqCount = Statistics.newSubCounter(" of which for compound types", baseTypeSeqCount) val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount) val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount) diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 185621efa4..75d43a7553 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -1001,7 +1001,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym 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) + Map() ++ (definitions.magicSymbols filter (_.isType) map mapEntry) } /** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index c1cd5d2911..eb48e9dc79 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -99,8 +99,10 @@ trait SymbolLoaders { self: SymbolTable => 0 < dp && dp < (name.length - 1) } - class PackageScope(pkgClass: Symbol) extends Scope() with SynchronizedScope { + class PackageScope(pkgClass: Symbol) extends Scope(initFingerPrints = -1L) // disable fingerprinting as we do not know entries beforehand + with SynchronizedScope { assert(pkgClass.isType) + // disable fingerprinting as we do not know entries beforehand private val negatives = mutable.Set[Name]() // Syncnote: Performance only, so need not be protected. override def lookupEntry(name: Name): ScopeEntry = { val e = super.lookupEntry(name) diff --git a/test/files/jvm/future-spec/FutureTests.scala b/test/files/jvm/future-spec/FutureTests.scala index ca9ff5090f..30e1a722bf 100644 --- a/test/files/jvm/future-spec/FutureTests.scala +++ b/test/files/jvm/future-spec/FutureTests.scala @@ -507,6 +507,12 @@ object FutureTests extends MinimalScalaTest { } Await.ready(complex, defaultTimeout).isCompleted mustBe (true) } + + "should not throw when Await.ready" in { + val expected = try Right(5 / 0) catch { case a: ArithmeticException => Left(a) } + val f = future(5).map(_ / 0) + Await.ready(f, defaultTimeout).value.get.toString mustBe expected.toString + } } diff --git a/test/files/jvm/future-spec/PromiseTests.scala b/test/files/jvm/future-spec/PromiseTests.scala index 49bc642b57..d15bb31f36 100644 --- a/test/files/jvm/future-spec/PromiseTests.scala +++ b/test/files/jvm/future-spec/PromiseTests.scala @@ -78,7 +78,7 @@ object PromiseTests extends MinimalScalaTest { "contain a value" in { f((future, result) => future.value mustBe (Some(Right(result)))) } - "return result with 'blocking'" in { f((future, result) => blocking(future, defaultTimeout) mustBe (result)) } + "return when ready with 'Await.ready'" in { f((future, result) => Await.ready(future, defaultTimeout).isCompleted mustBe (true)) } "return result with 'Await.result'" in { f((future, result) => Await.result(future, defaultTimeout) mustBe (result)) } @@ -163,12 +163,9 @@ object PromiseTests extends MinimalScalaTest { }) } - "throw exception with 'blocking'" in { + "throw not throw exception with 'Await.ready'" in { f { - (future, message) => - intercept[E] { - blocking(future, defaultTimeout) - }.getMessage mustBe (message) + (future, message) => Await.ready(future, defaultTimeout).isCompleted mustBe (true) } } diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index 5c9c71f3f8..1209b710b0 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -4,7 +4,9 @@ import scala.concurrent.{ TimeoutException, SyncVar, ExecutionException, - ExecutionContext + ExecutionContext, + CanAwait, + Await } import scala.concurrent.{ future, promise, blocking } import scala.util.{ Try, Success, Failure } @@ -647,7 +649,7 @@ trait FutureProjections extends TestBase { val f = future { throw cause } - assert(blocking(f.failed, Duration(500, "ms")) == cause) + assert(Await.result(f.failed, Duration(500, "ms")) == cause) done() } @@ -655,7 +657,7 @@ trait FutureProjections extends TestBase { done => val f = future { 0 } try { - blocking(f.failed, Duration(500, "ms")) + Await.result(f.failed, Duration(500, "ms")) assert(false) } catch { case nsee: NoSuchElementException => done() @@ -678,7 +680,7 @@ trait Blocking extends TestBase { def testAwaitSuccess(): Unit = once { done => val f = future { 0 } - blocking(f, Duration(500, "ms")) + Await.result(f, Duration(500, "ms")) done() } @@ -689,7 +691,7 @@ trait Blocking extends TestBase { throw cause } try { - blocking(f, Duration(500, "ms")) + Await.result(f, Duration(500, "ms")) assert(false) } catch { case t => @@ -708,7 +710,7 @@ trait BlockContexts extends TestBase { import scala.concurrent.{ Await, Awaitable, BlockContext } private def getBlockContext(body: => BlockContext): BlockContext = { - blocking(Future { body }, Duration(500, "ms")) + Await.result(Future { body }, Duration(500, "ms")) } // test outside of an ExecutionContext @@ -727,8 +729,7 @@ trait BlockContexts extends TestBase { def testPushCustom(): Unit = { val orig = BlockContext.current val customBC = new BlockContext() { - override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = - orig.internalBlockingCall(awaitable, atMost) + override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = orig.blockOn(thunk) } val bc = getBlockContext({ @@ -744,8 +745,7 @@ trait BlockContexts extends TestBase { def testPopCustom(): Unit = { val orig = BlockContext.current val customBC = new BlockContext() { - override def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = - orig.internalBlockingCall(awaitable, atMost) + override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = orig.blockOn(thunk) } val bc = getBlockContext({ diff --git a/test/files/pos/t6047.flags b/test/files/pos/t6047.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/pos/t6047.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/pos/t6047.scala b/test/files/pos/t6047.scala new file mode 100644 index 0000000000..66b52b285f --- /dev/null +++ b/test/files/pos/t6047.scala @@ -0,0 +1,20 @@ +import scala.reflect.makro.Context +import java.io.InputStream + +object Macros { + def unpack[A](input: InputStream): A = macro unpack_impl[A] + + def unpack_impl[A: c.TypeTag](c: Context)(input: c.Expr[InputStream]): c.Expr[A] = { + import c.universe._ + + def unpackcode(tpe: c.Type): c.Expr[_] = { + if (tpe <:< implicitly[c.AbsTypeTag[Traversable[_]]].tpe) { + + } + ??? + } + + unpackcode(c.typeOf[A]) + ??? + } + }
\ No newline at end of file diff --git a/test/files/run/reflection-magicsymbols-repl.check b/test/files/run/reflection-magicsymbols-repl.check new file mode 100644 index 0000000000..d2ef4ad3cd --- /dev/null +++ b/test/files/run/reflection-magicsymbols-repl.check @@ -0,0 +1,39 @@ +Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> import scala.reflect.runtime.universe._
+import scala.reflect.runtime.universe._
+
+scala> class A {
+ def foo1(x: Int*) = ???
+ def foo2(x: => Int) = ???
+ def foo3(x: Any) = ???
+ def foo4(x: AnyRef) = ???
+ def foo5(x: AnyVal) = ???
+ def foo6(x: Null) = ???
+ def foo7(x: Nothing) = ???
+ def foo8(x: Singleton) = ???
+}
+defined class A
+
+scala> def test(n: Int): Unit = {
+ val sig = typeOf[A] member newTermName("foo" + n) typeSignature
+ val x = sig.asInstanceOf[MethodType].params.head
+ println(x.typeSignature)
+}
+warning: there were 1 feature warnings; re-run with -feature for details
+test: (n: Int)Unit
+
+scala> for (i <- 1 to 8) test(i)
+scala.Int*
+=> scala.Int
+scala.Any
+scala.AnyRef
+scala.AnyVal
+scala.Null
+scala.Nothing
+scala.Singleton
+
+scala>
diff --git a/test/files/run/reflection-magicsymbols-repl.scala b/test/files/run/reflection-magicsymbols-repl.scala new file mode 100644 index 0000000000..26127b8661 --- /dev/null +++ b/test/files/run/reflection-magicsymbols-repl.scala @@ -0,0 +1,23 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.reflect.runtime.universe._ + |class A { + | def foo1(x: Int*) = ??? + | def foo2(x: => Int) = ??? + | def foo3(x: Any) = ??? + | def foo4(x: AnyRef) = ??? + | def foo5(x: AnyVal) = ??? + | def foo6(x: Null) = ??? + | def foo7(x: Nothing) = ??? + | def foo8(x: Singleton) = ??? + |} + |def test(n: Int): Unit = { + | val sig = typeOf[A] member newTermName("foo" + n) typeSignature + | val x = sig.asInstanceOf[MethodType].params.head + | println(x.typeSignature) + |} + |for (i <- 1 to 8) test(i) + |""".stripMargin +} diff --git a/test/files/run/reflection-magicsymbols-vanilla.check b/test/files/run/reflection-magicsymbols-vanilla.check new file mode 100644 index 0000000000..4f4e8d94a9 --- /dev/null +++ b/test/files/run/reflection-magicsymbols-vanilla.check @@ -0,0 +1,8 @@ +Int*
+=> Int
+Any
+AnyRef
+AnyVal
+Null
+Nothing
+Singleton
diff --git a/test/files/run/reflection-magicsymbols-vanilla.scala b/test/files/run/reflection-magicsymbols-vanilla.scala new file mode 100644 index 0000000000..32819dcc46 --- /dev/null +++ b/test/files/run/reflection-magicsymbols-vanilla.scala @@ -0,0 +1,20 @@ +class A { + def foo1(x: Int*) = ??? + def foo2(x: => Int) = ??? + def foo3(x: Any) = ??? + def foo4(x: AnyRef) = ??? + def foo5(x: AnyVal) = ??? + def foo6(x: Null) = ??? + def foo7(x: Nothing) = ??? + def foo8(x: Singleton) = ??? +} + +object Test extends App { + import scala.reflect.runtime.universe._ + def test(n: Int): Unit = { + val sig = typeOf[A] member newTermName("foo" + n) typeSignature + val x = sig.asInstanceOf[MethodType].params.head + println(x.typeSignature) + } + for (i <- 1 to 8) test(i) +} diff --git a/test/files/run/reflection-magicsymbols.check b/test/files/run/reflection-magicsymbols.check deleted file mode 100644 index 2600847d99..0000000000 --- a/test/files/run/reflection-magicsymbols.check +++ /dev/null @@ -1,22 +0,0 @@ -Type in expressions to have them evaluated.
-Type :help for more information.
-
-scala>
-
-scala> import scala.reflect.runtime.universe._
-import scala.reflect.runtime.universe._
-
-scala> class A { def foo(x: Int*) = 1 }
-defined class A
-
-scala> val sig = typeOf[A] member newTermName("foo") typeSignature
-warning: there were 1 feature warnings; re-run with -feature for details
-sig: reflect.runtime.universe.Type = (x: <?>)scala.Int
-
-scala> val x = sig.asInstanceOf[MethodType].params.head
-x: reflect.runtime.universe.Symbol = value x
-
-scala> println(x.typeSignature)
-scala.Int*
-
-scala>
diff --git a/test/files/run/reflection-magicsymbols.scala b/test/files/run/reflection-magicsymbols.scala deleted file mode 100644 index a40845d6ac..0000000000 --- a/test/files/run/reflection-magicsymbols.scala +++ /dev/null @@ -1,11 +0,0 @@ -import scala.tools.partest.ReplTest - -object Test extends ReplTest { - def code = """ - |import scala.reflect.runtime.universe._ - |class A { def foo(x: Int*) = 1 } - |val sig = typeOf[A] member newTermName("foo") typeSignature - |val x = sig.asInstanceOf[MethodType].params.head - |println(x.typeSignature) - |""".stripMargin -} diff --git a/test/files/run/t6086-repl.check b/test/files/run/t6086-repl.check new file mode 100644 index 0000000000..f868aa18d0 --- /dev/null +++ b/test/files/run/t6086-repl.check @@ -0,0 +1,12 @@ +Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> case class X(s: String)
+defined class X
+
+scala> scala.reflect.runtime.universe.typeOf[X]
+res0: reflect.runtime.universe.Type = X
+
+scala>
diff --git a/test/files/run/t6086-repl.scala b/test/files/run/t6086-repl.scala new file mode 100644 index 0000000000..87f94ec9f6 --- /dev/null +++ b/test/files/run/t6086-repl.scala @@ -0,0 +1,8 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |case class X(s: String) + |scala.reflect.runtime.universe.typeOf[X] + |""".stripMargin +} diff --git a/test/files/run/t6086-vanilla.check b/test/files/run/t6086-vanilla.check new file mode 100644 index 0000000000..fd66be08d0 --- /dev/null +++ b/test/files/run/t6086-vanilla.check @@ -0,0 +1 @@ +X
diff --git a/test/files/run/t6086-vanilla.scala b/test/files/run/t6086-vanilla.scala new file mode 100644 index 0000000000..b4de581ad5 --- /dev/null +++ b/test/files/run/t6086-vanilla.scala @@ -0,0 +1,6 @@ +case class X(s: String) + +object Test extends App { + import scala.reflect.runtime.universe._ + println(typeOf[X]) +}
\ No newline at end of file |