summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala28
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala11
-rw-r--r--src/library/scala/Application.scala104
-rw-r--r--test/files/run/lazy-locals.scala4
6 files changed, 81 insertions, 75 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 293c32c8a5..a5b5902545 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -1010,10 +1010,13 @@ trait Trees extends reflect.generic.Trees { self: SymbolTable =>
}
class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser {
- override def traverse(tree: Tree) {
+ def changeOwner(tree: Tree) = {
if ((tree.isDef || tree.isInstanceOf[Function]) &&
tree.symbol != NoSymbol && tree.symbol.owner == oldowner)
- tree.symbol.owner = newowner;
+ tree.symbol.owner = newowner
+ }
+ override def traverse(tree: Tree) {
+ changeOwner(tree)
super.traverse(tree)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 57f3ffe801..185c92d825 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -415,8 +415,8 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val closureParents = List(AbstractFunctionClass(0).tpe, ScalaObjectClass.tpe)
closureClass.setInfo(new ClassInfoType(closureParents, new Scope, closureClass))
- val outerField = clazz.newValue(impl.pos, nme.OUTER)
- .setFlag(PRIVATE | LOCAL)
+ val outerField = closureClass.newValue(impl.pos, nme.OUTER)
+ .setFlag(PRIVATE | LOCAL | PARAMACCESSOR)
.setInfo(clazz.tpe)
val applyMethod = closureClass.newMethod(impl.pos, nme.apply)
@@ -429,17 +429,29 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val outerFieldDef = ValDef(outerField)
val changeOwner = new ChangeOwnerTraverser(impl.symbol, applyMethod)
+
+ val closureClassTyper = localTyper.atOwner(closureClass)
+ val applyMethodTyper = closureClassTyper.atOwner(applyMethod)
+
val constrStatTransformer = new Transformer {
override def transform(tree: Tree): Tree = tree match {
- case This(`clazz`) =>
- localTyper.typed {
+ case This(_) if tree.symbol == clazz =>
+ applyMethodTyper.typed {
atPos(tree.pos) {
Select(This(closureClass), outerField)
}
}
case _ =>
- changeOwner traverse tree
- tree
+ tree match {
+ case Select(qual, _) =>
+ val sym = tree.symbol
+ sym makeNotPrivate sym.owner
+ case Assign(lhs @ Select(_, _), _) =>
+ lhs.symbol setFlag MUTABLE
+ case _ =>
+ changeOwner.changeOwner(tree)
+ }
+ super.transform(tree)
}
}
@@ -455,7 +467,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
constrMods = Modifiers(0),
vparamss = List(List(outerFieldDef)),
argss = List(List()),
- body = List(outerFieldDef, applyMethodDef),
+ body = List(applyMethodDef),
superPos = impl.pos)
}
}
@@ -483,7 +495,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
(clazz isSubClass DelayedInitClass) && !(defBuf exists isInitDef) && remainingConstrStats.nonEmpty
if (needsDelayedInit) {
- val dicl = delayedInitClosure(remainingConstrStats)
+ val dicl = new ConstructorTransformer(unit) transform delayedInitClosure(remainingConstrStats)
defBuf += dicl
remainingConstrStats = List(delayedInitCall(dicl))
}
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 8a94442d5a..0e7d3d3fc1 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -469,7 +469,7 @@ abstract class ExplicitOuter extends InfoTransform
else atPos(tree.pos)(outerPath(outerValue, currentClass.outerClass, sym)) // (5)
case Select(qual, name) =>
- if (currentClass != sym.owner/* && currentClass != sym.moduleClass*/) // (3)
+ if (currentClass != sym.owner) // (3)
sym.makeNotPrivate(sym.owner)
val qsym = qual.tpe.widen.typeSymbol
if (sym.isProtected && //(4)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index c47d1d1d73..9f07bd6b0d 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -849,14 +849,21 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
stats1
}
- /** Does this field require an initialized bit? */
+ /** Does this field require an initialized bit?
+ * Note: fields of classes inheriting DelayedInit are not checked.
+ * This is because the they are neither initialized in the constructor
+ * nor do they have a setter (not if they are vals abyway). The usual
+ * logic for setting bitmaps does therefor not work for such fields.
+ * That's why they are excluded.
+ */
def needsInitFlag(sym: Symbol) = {
val res = (settings.checkInit.value
&& sym.isGetter
&& !sym.isInitializedToDefault
&& !sym.hasFlag(PARAMACCESSOR | SPECIALIZED)
&& !sym.accessed.hasFlag(PRESUPER)
- && !sym.isOuterAccessor)
+ && !sym.isOuterAccessor
+ && !(sym.owner isSubClass DelayedInitClass))
// if (settings.debug.value) {
// log("needsInitFlag(" + sym.fullName + "): " + res)
diff --git a/src/library/scala/Application.scala b/src/library/scala/Application.scala
index 21e6b68091..cfc1dfe4a2 100644
--- a/src/library/scala/Application.scala
+++ b/src/library/scala/Application.scala
@@ -11,77 +11,61 @@
package scala
import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
-/** <p>
- * The <code>Application</code> trait can be used to quickly turn objects
- * into executable programs, but is <em>not recommended</em>.
- * Here is an example:
- * </p><pre>
- * <b>object</b> Main <b>extends</b> Application {
- * Console.println("Hello World!")
- * }
- * </pre>
- * <p>
- * Here, object <code>Main</code> inherits the <code>main</code> method
- * of <code>Application</code>. The body of the <code>Main</code> object
- * defines the main program. This technique does not work if the main
- * program depends on command-line arguments (which are not accessible
- * with the technique presented here).
- * </p>
- * <p>
- * It is possible to time the execution of objects that inherit from class
- * <code>Application</code> by setting the global <code>scala.time</code>
- * property. Here is an example for benchmarking object <code>Main</code>:
- * </p><pre>
- * java -Dscala.time Main
- * </pre>
- * <p>
- * In practice the <code>Application</code> trait has a number of serious
- * pitfalls:
- * </p>
- * <ul>
- * <li> Threaded code that references the object will block until static
- * initialization is complete. However, because the entire execution of an
- * <code>object</code> extending <code>Application</code> takes place during
- * static initialization, concurrent code will <em>always</em> deadlock if
- * it must synchronize with the enclosing object.</li>
- * <li>As described above, there is no way to obtain the
- * command-line arguments because all code in body of an <code>object</code>
- * extending <code>Application</code> is run as part of the static initialization
- * which occurs before <code>Application</code>'s <code>main</code> method
- * even begins execution.</li>
- * <li>Static initializers are run only once during program execution, and
- * JVM authors usually assume their execution to be relatively short.
- * Therefore, certain JVM configurations may become confused, or simply fail to
- * optimize or JIT the code in the body of an <code>object</code> extending
- * <code>Application</code>. This can lead to a significant
- * performance degradation.</li>
- * </ul>
- *
- * Instead, it is recommended to define a <code>main</code> method explicitly:
- * <pre>
- * <b>object</b> Main {
- * <b>def</b> main(args: Array[String]) {
- * //..
+/** The `Application` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends Application {
+ * Console.println("Hello World: " + (arguments mkString ", "))
* }
- * }
- * </pre>
+ * }}}
+ * Here, object `Main` inherits the `main` method of `Application`.
+ *
+ * `arguments` returns the current command line arguments as an array.
+ *
+ * Note: The use of Application was discouraged prior to 2.9 because
+ * application code would be run in the object constructor. This is no longer true.
+ * Application code is now stored and run in the main method. As a consequence,
+ * extending `Application` is now recommended over implementing `main` explicitly.
*
- * @author Matthias Zenger
- * @version 1.0, 10/09/2003
+ * @author Martin Odersky
+ * @version 2.0, 14/12/2010
*/
-
-trait Application {
+trait Application extends DelayedInit {
/** The time when the execution of this program started, in milliseconds since 1
* January 1970 UTC. */
val executionStart: Long = currentTime
- /** The default main method.
- *
+ /** The command line arguments passed to the application's `main` method.
+ */
+ protected def arguments: Array[String] = args
+
+ private var args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This methos is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes, objects, and traits
+ * that inherit from the `DelayedInit` trait and that do not themselves define
+ * a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all argument so that they can be retrieved with `arguments`
+ * and the executes all initialization code segements in the order they were
+ * passed to `delayedInit`
* @param args the arguments passed to the main method
*/
- def main(args: Array[String]) {
+ def main(args: Array[String]) = {
+ this.args = args
+ for (proc <- initCode) proc()
if (util.Properties.propIsSet("scala.time")) {
val total = currentTime - executionStart
Console.println("[total " + total + "ms]")
diff --git a/test/files/run/lazy-locals.scala b/test/files/run/lazy-locals.scala
index be738a0f70..15e02dbaf0 100644
--- a/test/files/run/lazy-locals.scala
+++ b/test/files/run/lazy-locals.scala
@@ -162,7 +162,7 @@ object Test extends Application {
}
// see #1589
- object NestedLazyVals extends Application {
+ object NestedLazyVals {
lazy val x = {
lazy val y = { println("forcing y"); 42; }
println("forcing x")
@@ -179,7 +179,7 @@ object Test extends Application {
lazy val x = { lazy val y = 42; y }
}
- object ONestedLazyVals extends Application with TNestedLazyVals {
+ object ONestedLazyVals extends TNestedLazyVals {
println(x)
}