summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2007-06-27 14:26:47 +0000
committerIulian Dragos <jaguarul@gmail.com>2007-06-27 14:26:47 +0000
commitb4b91dcb58b5804f7ec1513e8f4d1e4534fd8018 (patch)
tree758a2817dd728101980c7ffc3f206d484ad77ba0
parenta1ec75c2642396a83854510ba7e88d8a302a67fd (diff)
downloadscala-b4b91dcb58b5804f7ec1513e8f4d1e4534fd8018.tar.gz
scala-b4b91dcb58b5804f7ec1513e8f4d1e4534fd8018.tar.bz2
scala-b4b91dcb58b5804f7ec1513e8f4d1e4534fd8018.zip
Merged lazy values branch to trunk.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala52
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Tokens.scala33
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Flags.scala26
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala14
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala121
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala128
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala29
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala4
-rw-r--r--test/files/neg/lazyvals.check25
-rw-r--r--test/files/neg/lazyvals.scala26
-rw-r--r--test/files/run/bug603.scala4
-rw-r--r--test/files/run/lazy-exprs.check10
-rw-r--r--test/files/run/lazy-exprs.scala84
-rw-r--r--test/files/run/lazy-locals.check82
-rw-r--r--test/files/run/lazy-locals.scala143
-rw-r--r--test/files/run/lazy-traits.check154
-rw-r--r--test/files/run/lazy-traits.scala133
27 files changed, 1051 insertions, 75 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 65b358610c..07421f02d4 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -308,6 +308,11 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val global: Global.this.type = Global.this
}
+ object lazyVals extends LazyVals {
+ val global: Global.this.type = Global.this
+ final val FLAGS_PER_WORD = 32
+ }
+
object lambdaLift extends LambdaLift {
val global: Global.this.type = Global.this
}
@@ -388,6 +393,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
explicitOuter, // replace C.this by explicit outer pointers, eliminate pattern matching
// checkDefined,
erasure, // erase generic types to Java 1.4 types, add interfaces for traits
+ lazyVals,
lambdaLift, // move nested functions to top level
// detach,
constructors, // move field definitions into constructors
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 5a2ffbf875..4532980248 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -223,6 +223,10 @@ abstract class TreeGen {
def mkRuntimeCall(meth: Name, args: List[Tree]): Tree =
Apply(Select(mkAttributedRef(ScalaRunTimeModule), meth), args)
+ /** Make a synchronized block on 'monitor'. */
+ def mkSynchronized(monitor: Tree, body: Tree): Tree =
+ Apply(Select(monitor, definitions.Object_synchronized), List(body))
+
def evalOnce(expr: Tree, owner: Symbol, unit: CompilationUnit)(within: (() => Tree) => Tree): Tree =
if (treeInfo.isPureExpr(expr)) {
within(() => expr);
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index 37899949db..71929eb68d 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -98,7 +98,7 @@ abstract class TreePrinters {
}
def printFlags(flags: long, privateWithin: String): unit = {
- var mask = if (settings.debug.value) -1 else PrintableFlags
+ var mask: long = if (settings.debug.value) -1L else PrintableFlags
val s = flagsToString(flags & mask, privateWithin.toString)
if (s.length() != 0) print(s + " ")
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index e49153f732..5f0c0ee7ff 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -310,12 +310,12 @@ trait Parsers {
/////// TOKEN CLASSES //////////////////////////////////////////////////////
def isModifier: Boolean = inToken match {
- case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT => true
+ case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT | LAZY => true
case _ => false
}
def isLocalModifier: Boolean = inToken match {
- case ABSTRACT | FINAL | SEALED | IMPLICIT => true
+ case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true
case _ => false
}
@@ -1540,6 +1540,8 @@ trait Parsers {
loop(addMod(mods, Flags.OVERRIDE))
case IMPLICIT =>
loop(addMod(mods, Flags.IMPLICIT))
+ case LAZY =>
+ loop(addMod(mods, Flags.LAZY))
case _ =>
mods
}
@@ -1547,7 +1549,7 @@ trait Parsers {
}
/** LocalModifiers ::= {LocalModifier}
- * LocalModifier ::= abstract | final | sealed | implicit
+ * LocalModifier ::= abstract | final | sealed | implicit | lazy
*/
def localModifiers(): Modifiers = {
def loop(mods: Modifiers): Modifiers = inToken match {
@@ -1559,6 +1561,8 @@ trait Parsers {
loop(addMod(mods, Flags.SEALED))
case IMPLICIT =>
loop(addMod(mods, Flags.IMPLICIT))
+ case LAZY =>
+ loop(addMod(mods, Flags.LAZY))
case _ =>
mods
}
@@ -1659,6 +1663,7 @@ trait Parsers {
var mods = Modifiers(Flags.PARAM)
if (owner.isTypeName) {
mods = modifiers() | Flags.PARAMACCESSOR
+ if (mods.hasFlag(Flags.LAZY)) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", false)
if (inToken == VAL) {
inNextToken
} else if (inToken == VAR) {
@@ -1906,7 +1911,9 @@ trait Parsers {
* | type [nl] TypeDcl
* XXX: Hook for IDE.
*/
- def defOrDcl(mods: Modifiers): List[Tree] =
+ def defOrDcl(mods: Modifiers): List[Tree] = {
+ if ((mods.hasFlag(Flags.LAZY)) && in.token != VAL)
+ syntaxError("lazy not allowed here. Only vals can be lazy", false)
inToken match {
case VAL =>
patDefOrDcl(mods)
@@ -1921,6 +1928,7 @@ trait Parsers {
case _ =>
List(tmplDef(mods))
}
+ }
/** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr
* ValDcl ::= Id {`,' Id} `:' Type
@@ -1951,6 +1959,7 @@ trait Parsers {
if (rhs == EmptyTree) {
trees match {
case List(ValDef(_, _, _, EmptyTree)) =>
+ if (mods.hasFlag(Flags.LAZY)) syntaxError(p.pos, "lazy values may not be abstract", false)
case _ => syntaxError(p.pos, "pattern definition may not be abstract", false)
}
}
@@ -2088,20 +2097,23 @@ trait Parsers {
* | [case] object ObjectDef
* | trait TraitDef
*/
- def tmplDef(mods: Modifiers): Tree = inToken match {
- case TRAIT =>
- classDef(mods | Flags.TRAIT | Flags.ABSTRACT)
- case CLASS =>
- classDef(mods)
- case CASECLASS =>
- classDef(mods | Flags.CASE)
- case OBJECT =>
- objectDef(mods)
- case CASEOBJECT =>
- objectDef(mods | Flags.CASE)
- case _ =>
- syntaxErrorOrIncomplete("expected start of definition", true)
- EmptyTree
+ def tmplDef(mods: Modifiers): Tree = {
+ if (mods.hasFlag(Flags.LAZY)) syntaxError("classes cannot be lazy", false)
+ inToken match {
+ case TRAIT =>
+ classDef(mods | Flags.TRAIT | Flags.ABSTRACT)
+ case CLASS =>
+ classDef(mods)
+ case CASECLASS =>
+ classDef(mods | Flags.CASE)
+ case OBJECT =>
+ objectDef(mods)
+ case CASEOBJECT =>
+ objectDef(mods | Flags.CASE)
+ case _ =>
+ syntaxErrorOrIncomplete("expected start of definition", true)
+ EmptyTree
+ }
}
/** ClassDef ::= Id [TypeParamClause] Annotations
@@ -2353,14 +2365,14 @@ trait Parsers {
/** BlockStatSeq ::= { BlockStat semi } [ResultExpr]
* BlockStat ::= Import
- * | [implicit] Def
+ * | [implicit] [lazy] Def
* | LocalModifiers TmplDef
* | Expr1
* |
*/
def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = checkNoEscapingPlaceholders {
def localDef(mods: Modifiers) = {
- if (!(mods hasFlag ~Flags.IMPLICIT)) stats ++= defOrDcl(mods)
+ if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) stats ++= defOrDcl(mods)
else stats += tmplDefHooked(mods)
if (inToken == RBRACE || inToken == CASE)
syntaxError("block must end in result expression, not in definition", false)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index a68188c3d7..6081bc568d 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -124,6 +124,7 @@ trait Scanners {
enterKeyword(nme.IFkw, IF)
enterKeyword(nme.IMPLICITkw, IMPLICIT)
enterKeyword(nme.IMPORTkw, IMPORT)
+ enterKeyword(nme.LAZYkw, LAZY)
enterKeyword(nme.MATCHkw, MATCH)
enterKeyword(nme.NEWkw, NEW)
enterKeyword(nme.NULLkw, NULL)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
index 49a497a669..959fba033e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
@@ -74,27 +74,28 @@ object Tokens {
final val MATCH = 58
final val FORSOME = 59
final val REQUIRES = 60
+ final val LAZY = 61
def isKeyword(code : Int) =
- code >= IF && code <= REQUIRES
+ code >= IF && code <= LAZY
/** special symbols */
- final val COMMA = 61
- final val SEMI = 62
- final val DOT = 63
- final val USCORE = 64
- final val COLON = 65
- final val EQUALS = 66
- final val LARROW = 67
- final val ARROW = 68
- final val NEWLINE = 69
- final val NEWLINES = 70
- final val SUBTYPE = 71
- final val SUPERTYPE = 72
- final val HASH = 73
- final val AT = 74
- final val VIEWBOUND = 75
+ final val COMMA = 70
+ final val SEMI = 71
+ final val DOT = 72
+ final val USCORE = 73
+ final val COLON = 74
+ final val EQUALS = 75
+ final val LARROW = 76
+ final val ARROW = 77
+ final val NEWLINE = 78
+ final val NEWLINES = 79
+ final val SUBTYPE = 80
+ final val SUPERTYPE = 81
+ final val HASH = 82
+ final val AT = 83
+ final val VIEWBOUND = 84
def isSymbol(code : Int) =
code >= COMMA && code <= VIEWBOUND
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 5dd43f1438..136e9d2c0a 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -60,6 +60,10 @@ trait Definitions {
var ShortClass: Symbol = _
var CharClass: Symbol = _
var IntClass: Symbol = _
+ def Int_Or = definitions.getMember(definitions.IntClass, nme.OR)
+ def Int_And = definitions.getMember(definitions.IntClass, nme.AND)
+ def Int_== = definitions.getMember(definitions.IntClass, nme.EQEQ)
+
var LongClass: Symbol = _
var FloatClass: Symbol = _
var DoubleClass: Symbol = _
@@ -369,6 +373,8 @@ trait Definitions {
var BeanPropertyAttr: Symbol = _
var AnnotationDefaultAttr: Symbol = _
var NativeAttr: Symbol = _
+ var VolatileAttr: Symbol = _
+
def getModule(fullname: Name): Symbol = getModuleOrClass(fullname, true)
@@ -939,6 +945,7 @@ trait Definitions {
BeanPropertyAttr = if (forCLDC || forMSIL) null else getClass("scala.reflect.BeanProperty")
DeprecatedAttr = getClass("scala.deprecated")
NativeAttr = getClass("scala.native")
+ VolatileAttr = getClass("scala.volatile")
}
var nbScalaCallers: Int = 0
diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala
index a7c3e5b5d7..6a31a94444 100644
--- a/src/compiler/scala/tools/nsc/symtab/Flags.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala
@@ -60,6 +60,7 @@ object Flags extends Enumeration {
// for parameters: is a val parameter
final val MODULEVAR = 0x40000000 // for term symbols: is the variable caching a module value
final val MONOMORPHIC = 0x40000000 // for type symbols: does not have type parameters
+ final val LAZY = 0x80000000L // symbol is a lazy val. can't have MUTABLE unless transformed by typer
final val IS_ERROR = 0x100000000L // symbol is an error symbol
final val OVERLOADED = 0x200000000L // symbol is overloaded
@@ -103,29 +104,29 @@ object Flags extends Enumeration {
// masks
/** This flags can be set when class or module symbol is first created. */
- final val TopLevelCreationFlags =
+ final val TopLevelCreationFlags: Long =
MODULE | PACKAGE | FINAL | JAVA
/** These modifiers can be set explicitly in source programs. */
- final val ExplicitFlags =
+ final val ExplicitFlags: Long =
PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED |
- OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE
+ OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY
/** These modifiers appear in TreePrinter output. */
- final val PrintableFlags =
+ final val PrintableFlags: Long =
ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR |
ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC
- final val FieldFlags =
- MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL | PRESUPER
+ final val FieldFlags: Long =
+ MUTABLE | CASEACCESSOR | PARAMACCESSOR | STATIC | FINAL | PRESUPER | LAZY
- final val AccessFlags = PRIVATE | PROTECTED
+ final val AccessFlags: Long = PRIVATE | PROTECTED
final val VARIANCES = COVARIANT | CONTRAVARIANT
- final val ConstrFlags = JAVA
- final val PickledFlags = 0xFFFFFFFF
+ final val ConstrFlags: Long = JAVA
+ final val PickledFlags: Long = 0xFFFFFFFFL
/** Module flags inherited by their module-class */
- final val ModuleToClassFlags = AccessFlags | PACKAGE | CASE
+ final val ModuleToClassFlags: Long = AccessFlags | PACKAGE | CASE
private def listToString(ss: List[String]): String =
ss.filter("" !=).mkString("", " ", "")
@@ -164,6 +165,7 @@ object Flags extends Enumeration {
else if (flag == IMPLCLASS ) "<presuper/implclass>"
else if (flag == TRANS_FLAG ) "<trans-flag>"
else if (flag == LOCKED ) "<locked>"
+ else if (flag == LAZY ) "lazy"
else flag.asInstanceOf[Int] match {
case IMPLICIT => "implicit"
case FINAL => "final"
@@ -207,13 +209,13 @@ object Flags extends Enumeration {
}
}
- class Flag(mods: Int) {
+ class Flag(mods: Long) {
def isPrivate = (mods & PRIVATE ) != 0
def isProtected = (mods & PROTECTED) != 0
def isVariable = (mods & MUTABLE) != 0
def isPublic = !isPrivate && !isProtected
}
- case class FlagEnum(mask: Int) extends Val(maskToBit(mask), flagToString(mask))
+ case class FlagEnum(mask: Long) extends Val(maskToBit(mask), flagToString(mask))
val Implicit = FlagEnum(IMPLICIT)
val Final = FlagEnum(FINAL)
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index b11c09b478..6bcc6e4126 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -30,6 +30,7 @@ trait StdNames {
val IFkw = newTermName("if")
val IMPLICITkw = newTermName("implicit")
val IMPORTkw = newTermName("import")
+ val LAZYkw = newTermName("lazy")
val MATCHkw = newTermName("match")
val MIXINkw = newTermName("mixin")
val NEWkw = newTermName("new")
@@ -151,6 +152,9 @@ trait StdNames {
/** The name of a setter for protected symbols. Used for inherited Java fields. */
def protSetterName(name: Name): Name = newTermName("protected$set" + name)
+ /** The name of bitmaps for initialized lazy vals. */
+ def bitmapName(n: Int): Name = newTermName("bitmap$" + n)
+
val ERROR = newTermName("<error>")
val ERRORtype = newTypeName("<error>")
val LOCALCHILD = newTypeName("<local child>")
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 5dd47ad8c3..1edc9fd737 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -738,6 +738,9 @@ trait Symbols {
* is an alias, NoSymbol for all others */
def alias: Symbol = NoSymbol
+ /** For a lazy value, it's lazy accessor. NoSymbol for all others */
+ def lazyAccessor: Symbol = NoSymbol
+
/** For an outer accessor: The class from which the outer originates.
* For all other symbols: NoSymbol
*/
@@ -1139,6 +1142,17 @@ trait Symbols {
referenced = clazz
this
}
+
+ def setLazyAccessor(sym: Symbol): TermSymbol = {
+ assert(hasFlag(LAZY) && referenced == NoSymbol, this)
+ referenced = sym
+ this
+ }
+
+ override def lazyAccessor: Symbol = {
+ assert(hasFlag(LAZY), this)
+ referenced
+ }
}
/** A class for module symbols */
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 4cd8515900..a69d27b368 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -205,7 +205,7 @@ abstract class UnPickler {
case _ =>
errorBadSignature("bad symbol tag: " + tag)
}
- sym.setFlag(flags)
+ sym.setFlag(flags.toLong & PickledFlags)
sym.privateWithin = privateWithin
if (readIndex != end) assert(sym hasFlag (SUPERACCESSOR | PARAMACCESSOR))
if (sym hasFlag SUPERACCESSOR) assert(readIndex != end)
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 83cbd27812..b03c05ce3b 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -154,7 +154,7 @@ abstract class Constructors extends Transform {
if (stat.symbol.tpe.isInstanceOf[ConstantType])
assert(stat.symbol.getter(stat.symbol.owner) != NoSymbol, stat)
else {
- if (rhs != EmptyTree) {
+ if (rhs != EmptyTree && !stat.symbol.hasFlag(LAZY)) {
val rhs1 = intoConstructor(stat.symbol, rhs);
(if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign(
stat.symbol, rhs1)
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
new file mode 100644
index 0000000000..e4cfa6029f
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -0,0 +1,121 @@
+package scala.tools.nsc.transform;
+
+import scala.tools.nsc._
+import scala.collection.mutable.HashMap
+
+abstract class LazyVals extends Transform {
+ // inherits abstract value `global' and class `Phase' from Transform
+
+ import global._ // the global environment
+ import definitions._ // standard classes and methods
+ import typer.{typed, atOwner} // methods to type trees
+ import posAssigner.atPos // for filling in tree positions
+
+ val phaseName: String = "lazyvals"
+
+ def newTransformer(unit: CompilationUnit): Transformer =
+ new LazyValues(unit)
+
+ /** Create a new phase which applies transformer */
+ override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new Phase(prev)
+
+ /** The phase defined by this transform */
+ class Phase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) {
+ def apply(unit: global.CompilationUnit): Unit =
+ newTransformer(unit).transformUnit(unit);
+ }
+
+ /**
+ * Transform local lazy accessors to check for the initialized bit.
+ */
+ class LazyValues(unit: CompilationUnit) extends Transformer {
+
+ import definitions.{Int_And, Int_Or, Int_==}
+ /** map from method symbols to the number of lazy values it defines. */
+ private val lazyVals = new HashMap[Symbol, Int] {
+ override def default(meth: Symbol) = 0
+ }
+
+ import symtab.Flags._
+ import lazyVals._
+
+ /** Perform the following transformations:
+ * - for a lazy accessor inside a method, make it check the initialization bitmap
+ * - for all methods, add enough int vars to allow one flag per lazy local value
+ */
+ override def transform(tree: Tree): Tree = {
+ val sym = tree.symbol
+ tree match {
+ case DefDef(mods, name, tparams, vparams, tpt, rhs) =>
+ val res = if (!sym.owner.isClass && sym.hasFlag(LAZY)) {
+ val idx = lazyVals(sym.enclMethod)
+ val rhs1 = mkLazyDef(sym.enclMethod, super.transform(rhs), idx)
+ lazyVals(sym.owner) = idx + 1
+ sym.resetFlag(LAZY)
+ rhs1
+ } else
+ super.transform(rhs)
+ val bmps = bitmaps(sym) map { b => ValDef(b, Literal(Constant(0))) }
+ copy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(if (bmps.isEmpty) res else Block(bmps, res)))
+
+ case _ => super.transform(tree)
+ }
+ }
+
+ /** return a 'lazified' version of rhs. Rhs should conform to the
+ * following schema:
+ * {
+ * l$ = <rhs>
+ * l$
+ * }
+ * The result will be a tree of the form
+ * {
+ * if ((bitmap$n & MASK) == 0) {
+ * l$ = <rhs>
+ * bitmap$n = bimap$n | MASK
+ * }
+ * l$
+ * }
+ * where bitmap$n is an int value acting as a bitmap of initialized values. It is
+ * the 'n' is (offset / 32), the MASK is (1 << (offset % 32)).
+ */
+ private def mkLazyDef(meth: Symbol, tree: Tree, offset: Int): Tree = {
+ val bitmapSym = getBitmapFor(meth, offset)
+ val Block(List(assignment), res) = tree
+ val mask = Literal(Constant(1 << (offset % FLAGS_PER_WORD)))
+ val result =
+ If(Apply(
+ Select(
+ Apply(Select(Ident(bitmapSym), Int_And),
+ List(mask)),
+ Int_==),
+ List(Literal(Constant(0)))), Block(List(assignment, mkSetFlag(bitmapSym, mask)), Literal(Constant(()))), EmptyTree)
+ typed(Block(List(result), res))
+ }
+
+ private def mkSetFlag(bmp: Symbol, mask: Tree): Tree =
+ Assign(Ident(bmp),
+ Apply(Select(Ident(bmp), Int_Or), List(mask)))
+
+
+ final val FLAGS_PER_WORD = 32
+ val bitmaps = new HashMap[Symbol, List[Symbol]] {
+ override def default(meth: Symbol) = Nil
+ }
+
+ /** Return the symbol corresponding of the right bitmap int inside meth,
+ * given offset.
+ */
+ private def getBitmapFor(meth: Symbol, offset: Int): Symbol = {
+ val n = offset / FLAGS_PER_WORD
+ val bmps = bitmaps(meth)
+ if (bmps.length > n)
+ bmps(n)
+ else {
+ val sym = meth.newVariable(meth.pos, nme.bitmapName(n)).setInfo(IntClass.tpe)
+ bitmaps(meth) = (sym :: bmps).reverse
+ sym
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index c02691aa5a..0e515ff64f 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -10,6 +10,7 @@ import symtab._
import Flags._
import scala.collection.mutable.ListBuffer
import scala.tools.nsc.util.{Position,NoPosition}
+import scala.collection.mutable.HashMap
abstract class Mixin extends InfoTransform {
import global._
@@ -37,12 +38,13 @@ abstract class Mixin extends InfoTransform {
* (private modules, on the other hand, are implemented statically, but their
* module variable is not. all such private modules are lifted, because
* non-lifted private modules have been eliminated in ExplicitOuter)
- * - field accessors and superaccessors
+ * - field accessors and superaccessors, except for lazy value accessors which become initializer
+ * methods in the impl class (because they can have arbitrary initializers)
*/
private def isImplementedStatically(sym: Symbol) =
sym.owner.isImplClass && sym.isMethod &&
- (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED)) &&
- !(sym hasFlag (ACCESSOR | SUPERACCESSOR))
+ (!sym.isModule || sym.hasFlag(PRIVATE)) &&
+ (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.hasFlag(LAZY))
/** A member of a trait is static only if it belongs only to the
* implementation class, not the interface, and it is implemented
@@ -124,6 +126,7 @@ abstract class Mixin extends InfoTransform {
* class to its interface unless they are already present. This is done
* only once per class. The mixedin flag is used to remember whether late
* members have been added to an interface.
+ * - lazy fields don't get a setter.
*
* @param clazz ...
*/
@@ -158,7 +161,7 @@ abstract class Mixin extends InfoTransform {
}
val getter = member.getter(clazz)
if (getter == NoSymbol) addMember(clazz, newGetter(member))
- if (!member.tpe.isInstanceOf[ConstantType]) {
+ if (!member.tpe.isInstanceOf[ConstantType] && !member.hasFlag(LAZY)) {
val setter = member.setter(clazz)
if (setter == NoSymbol) addMember(clazz, newSetter(member))
}
@@ -167,6 +170,9 @@ abstract class Mixin extends InfoTransform {
if (settings.debug.value) log("new defs of " + clazz + " = " + clazz.info.decls);
}
+ /** Map a lazy, mixedin field accessor to it's trait member accessor */
+ val initializer = new HashMap[Symbol, Symbol]
+
/** Add all members to be mixed in into a (non-trait-) class
* These are:
* for every mixin trait T that is not also inherited by the superclass:
@@ -208,7 +214,10 @@ abstract class Mixin extends InfoTransform {
}
}
- /** Mix in members of trait mixinClass into class clazz */
+ /** Mix in members of trait mixinClass into class clazz. Also,
+ * for each lazy field in mixinClass, add a link from its mixed in member to it's
+ * initializer method inside the implclass.
+ */
def mixinTraitMembers(mixinClass: Symbol): unit = {
// For all members of a trait's interface do:
for (val member <- mixinClass.info.decls.toList) {
@@ -220,6 +229,11 @@ abstract class Mixin extends InfoTransform {
member.cloneSymbol(clazz)
setPos clazz.pos
setFlag FINAL resetFlag (DEFERRED | lateDEFERRED))
+ if (member.hasFlag(LAZY)) {
+ var init = implClass(mixinClass).info.decl(member.name)
+ assert(init != NoSymbol, "Could not find initializer for " + member.name)
+ initializer(member1) = init
+ }
if (!member.isSetter)
member.tpe match {
case MethodType(List(), ConstantType(_)) =>
@@ -229,7 +243,7 @@ abstract class Mixin extends InfoTransform {
// otherwise mixin a field as well
addMember(clazz,
clazz.newValue(member.pos, nme.getterToLocal(member.name))
- setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE))
+ setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE | LAZY))
setInfo member.tpe.resultType)
}
} else if (member hasFlag SUPERACCESSOR) { // mixin super accessors
@@ -412,6 +426,7 @@ abstract class Mixin extends InfoTransform {
* - for a non-trait class:
* - A field for every in a mixin class
* - Setters and getters for such fields
+ * - getters for mixed in lazy fields are completed
* - module variables and module creators for every module in a mixin class
* (except if module is lifted -- in this case the module variable
* is local to some function, and the creator method is static.)
@@ -422,6 +437,7 @@ abstract class Mixin extends InfoTransform {
*/
private def addNewDefs(clazz: Symbol, stats: List[Tree]): List[Tree] = {
val newDefs = new ListBuffer[Tree]
+ var offset: Int = 0
/** Attribute given tree and anchor at given position */
def attributedDef(pos: Position, tree: Tree): Tree = {
@@ -489,7 +505,92 @@ abstract class Mixin extends InfoTransform {
stat
}
+ import lazyVals._
+
+ /** return a 'lazified' version of rhs.
+ * @param clazz The class symbol
+ * @param init The tree which initializes the field ( f = <rhs> )
+ * @param fieldSym The symbol of this lazy field
+ * @param offset The offset of this field in the flags bitmap
+ *
+ * The result will be a tree of the form
+ * {
+ * if ((bitmap$n & MASK) == 0) {
+ * synhronized(this) {
+ * if ((bitmap$n & MASK) == 0) {
+ * synhronized(this) {
+ * init // l$ = <rhs>
+ * }
+ * bitmap$n = bimap$n | MASK
+ * }}}
+ * l$
+ * }
+ * where bitmap$n is an int value acting as a bitmap of initialized values. It is
+ * the 'n' is (offset / 32), the MASK is (1 << (offset % 32)).
+ */
+ def mkLazyDef(clazz: Symbol, init: Tree, fieldSym: Symbol, offset: Int): Tree = {
+
+ /** Return the bitmap field for 'offset', create one if not inheriting it already. */
+ def bitmapFor(offset: Int): Symbol = {
+ var sym = clazz.info.member(nme.bitmapName(offset / FLAGS_PER_WORD))
+ assert(!sym.hasFlag(OVERLOADED))
+ if (sym == NoSymbol) {
+ sym = clazz.newVariable(clazz.pos, nme.bitmapName(offset / FLAGS_PER_WORD))
+ .setInfo(definitions.IntClass.tpe)
+ .setFlag(PROTECTED)
+ atPhase(currentRun.typerPhase) {
+ sym.attributes = AnnotationInfo(definitions.VolatileAttr.tpe, List(), List()) :: sym.attributes
+ }
+ clazz.info.decls.enter(sym)
+ addDef(clazz.pos, ValDef(sym, Literal(Constant(0))))
+ }
+ sym
+ }
+ val bitmapSym = bitmapFor(offset)
+
+ def mkSetFlag(bmp: Symbol, mask: Tree): Tree =
+ Assign(Select(This(clazz), bmp),
+ Apply(Select(Select(This(clazz), bmp), Int_Or), List(mask)))
+
+ def mkTest(mask: Tree): Tree =
+ Apply(Select(Apply(Select(Select(This(clazz), bitmapSym), Int_And), List(mask)),
+ Int_==), List(Literal(Constant(0))))
+
+ val mask = Literal(Constant(1 << (offset % FLAGS_PER_WORD)))
+ val result =
+ If(mkTest(mask),
+ gen.mkSynchronized(gen.mkAttributedThis(clazz),
+ If(mkTest(mask),
+ Block(List(gen.mkSynchronized(gen.mkAttributedThis(clazz), init),
+ mkSetFlag(bitmapSym, mask)),
+ Literal(Constant(()))),
+ EmptyTree)),
+ EmptyTree)
+ localTyper.typed(Block(List(result), Select(This(clazz), fieldSym)))
+ }
+
+ /** Complete lazy field accessors. Applies only to classes, for it's own (non inherited) lazy fields. */
+ def lazifyOwnFields(clazz: Symbol, stats: List[Tree]): List[Tree] = {
+ var offset = clazz.info.findMember(nme.ANYNAME, METHOD, LAZY, false).alternatives.filter(_.owner != clazz).length
+ val stats1 = for (stat <- stats; sym = stat.symbol) yield stat match {
+ case DefDef(mods, name, tp, vp, tpt, rhs)
+ if sym.hasFlag(LAZY) && rhs != EmptyTree && !clazz.isImplClass =>
+ val Block(List(assignment), res) = rhs
+ val rhs1 = mkLazyDef(clazz, assignment, res.symbol, offset)
+ offset += 1
+ copy.DefDef(stat, mods, name, tp, vp, tpt, rhs1)
+ case _ => stat
+ }
+ stats1
+ }
+
+
+ // the number of inherited lazy fields that are not mixed in
+ offset = (clazz.info.findMember(nme.ANYNAME, METHOD, LAZY, false)
+ .alternatives filter { f => f.owner != clazz || !f.hasFlag(MIXEDIN)}).length
// begin addNewDefs
+ var stats1 = lazifyOwnFields(clazz, stats)
+
// for all symbols `sym' in the class definition, which are mixed in:
for (val sym <- clazz.info.decls.toList) {
if (sym hasFlag MIXEDIN) {
@@ -504,7 +605,18 @@ abstract class Mixin extends InfoTransform {
addDefDef(sym, vparams => {
val accessedRef = sym.tpe match {
case MethodType(List(), ConstantType(c)) => Literal(c)
- case _ => Select(This(clazz), sym.accessed)
+ case _ =>
+ // if it is a mixed-in lazy value, complete the accessor
+ if (sym.hasFlag(LAZY) && sym.isGetter) {
+ val assign =
+ Assign(gen.mkAttributedRef(sym.accessed),
+ Apply(staticRef(initializer(sym)), gen.mkAttributedThis(clazz) :: Nil))
+
+ val rhs1 = mkLazyDef(clazz, assign, sym.accessed, offset)
+ offset += 1
+ rhs1
+ } else
+ Select(This(clazz), sym.accessed)
}
if (sym.isSetter) Assign(accessedRef, Ident(vparams.head))
else gen.mkCheckInit(accessedRef)
@@ -529,7 +641,7 @@ abstract class Mixin extends InfoTransform {
}
}
}
- var stats1 = add(stats, newDefs.toList)
+ stats1 = add(stats1, newDefs.toList)
if (!clazz.isTrait) stats1 = stats1 map completeSuperAccessor
stats1
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 80e5210a36..07d9c3905d 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -211,7 +211,10 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
/** Undo eta expansion for parameterless and nullaray methods */
def deEta(fun: Function): Tree = fun match {
case Function(List(), Apply(expr, List())) if treeInfo.isPureExpr(expr) =>
- expr
+ if (expr.hasSymbol && expr.symbol.hasFlag(LAZY))
+ fun
+ else
+ expr
case Function(List(), expr) if isByNameRef(expr) =>
noApply += expr
expr
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 89f8a26546..ec88ea419b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -106,7 +106,7 @@ trait Namers { self: Analyzer =>
sym.name.toString() + " is already defined as " +
(if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString()))
- def enterInScope(sym: Symbol): Symbol = {
+ def enterInScope[A <: Symbol](sym: A): A = {
// allow for overloaded methods
if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) {
val prev = context.scope.lookupEntry(sym.name);
@@ -284,8 +284,9 @@ trait Namers { self: Analyzer =>
tree.symbol.moduleClass.setInfo(namerOf(tree.symbol).moduleClassTypeCompleter(tree))
finish
case ValDef(mods, name, tp, rhs) =>
- if (context.owner.isClass && (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL)) {
- val accflags = ACCESSOR |
+ if (context.owner.isClass && (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL)
+ || (mods.flags & LAZY) != 0) {
+ val accflags: Long = ACCESSOR |
(if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE & ~PRESUPER
else mods.flags & ~PRESUPER | STABLE)
val getter = owner.newMethod(tree.pos, name).setFlag(accflags)
@@ -301,10 +302,18 @@ trait Namers { self: Analyzer =>
}
tree.symbol =
if ((mods.flags & DEFERRED) == 0) {
- val value =
- enterInScope(owner.newValue(tree.pos, nme.getterToLocal(name)))
- .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL)
+ val vsym =
+ if (!context.owner.isClass) {
+ assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val
+ owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE)
+ } else {
+ owner.newValue(tree.pos, nme.getterToLocal(name))
+ .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0))
+ }
+ val value = enterInScope(vsym)
value.setInfo(namerOf(value).typeCompleter(tree))
+ if ((mods.flags & LAZY) != 0)
+ value.setLazyAccessor(getter)
value
} else getter;
} else {
@@ -345,7 +354,7 @@ trait Namers { self: Analyzer =>
def typeCompleter(tree: Tree) = new TypeCompleter(tree) {
override def complete(sym: Symbol) {
- if (settings.debug.value) log("defining " + sym);
+ if (settings.debug.value) log("defining " + sym + Flags.flagsToString(sym.flags));
val tp = typeSig(tree)
sym.setInfo(tp)
if ((sym.isAliasType || sym.isAbstractType) && !(sym hasFlag PARAM) &&
@@ -741,7 +750,7 @@ trait Namers { self: Analyzer =>
"abstract member may not have " + Flags.flagsToString(flag2) + " modifier";
else
"illegal combination of modifiers: " +
- Flags.flagsToString(flag1) + " and " + Flags.flagsToString(flag2));
+ Flags.flagsToString(flag1) + " and " + Flags.flagsToString(flag2) + " for: " + sym + Flags.flagsToString(sym.rawflags));
if (sym.hasFlag(IMPLICIT) && !sym.isTerm)
context.error(sym.pos, "`implicit' modifier can be used only for values, variables and methods")
if (sym.hasFlag(IMPLICIT) && sym.owner.isPackageClass)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index bad97b2d1c..162d291ddd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -566,6 +566,11 @@ abstract class RefChecks extends InfoTransform {
stats1
}
+ /** Implements lazy value accessors:
+ * - for lazy fields inside traits, the rhs is the initializer itself
+ * - for all other lazy values z the accessor is a block of this form:
+ * { z = <rhs>; z } where z can be an identifier or a field.
+ */
def transformStat(tree: Tree, index: int): List[Tree] = tree match {
case ModuleDef(mods, name, impl) =>
val sym = tree.symbol
@@ -622,11 +627,27 @@ abstract class RefChecks extends InfoTransform {
case ValDef(_, _, _, _) =>
val tree1 = transform(tree); // important to do before forward reference check
- if (tree.symbol.isLocal && index <= currentLevel.maxindex) {
- if (settings.debug.value) Console.println(currentLevel.refsym);
- unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol);
+ val ValDef(_, _, _, rhs) = tree1
+ if (tree.symbol.hasFlag(LAZY)) {
+ assert(tree.symbol.isTerm, tree.symbol)
+ val vsym = tree.symbol
+ val lazyDefSym = vsym.lazyAccessor
+ assert(lazyDefSym != NoSymbol, vsym)
+ val lazyDef = atPos(tree.pos)(
+ DefDef(lazyDefSym, vparamss =>
+ if (tree.symbol.owner.isTrait) rhs // for traits, this is further tranformed in mixins
+ else Block(List(
+ Assign(gen.mkAttributedRef(vsym), rhs)),
+ gen.mkAttributedRef(vsym))))
+ log("Made lazy def: " + lazyDef)
+ typed(ValDef(vsym, EmptyTree)) :: typed(lazyDef) :: Nil
+ } else {
+ if (tree.symbol.isLocal && index <= currentLevel.maxindex && !tree.symbol.hasFlag(LAZY)) {
+ if (settings.debug.value) Console.println(currentLevel.refsym);
+ unit.error(currentLevel.refpos, "forward reference extends over definition of " + tree.symbol);
+ }
+ List(tree1)
}
- List(tree1)
case Import(_, _) =>
List()
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 34f09f6acf..27e358ed77 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -985,7 +985,9 @@ trait Typers { self: Analyzer =>
*/
def addGetterSetter(stat: Tree): List[Tree] = stat match {
case ValDef(mods, name, tpt, rhs)
- if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL) && !stat.symbol.isModuleVar =>
+ if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL)
+ && !stat.symbol.isModuleVar
+ && !stat.symbol.hasFlag(LAZY) =>
val vdef = copy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs)
val value = vdef.symbol
val getter = if ((mods hasFlag DEFERRED) || inIDE) value else value.getter(value.owner)
diff --git a/test/files/neg/lazyvals.check b/test/files/neg/lazyvals.check
new file mode 100644
index 0000000000..c4daf9d842
--- /dev/null
+++ b/test/files/neg/lazyvals.check
@@ -0,0 +1,25 @@
+lazyvals.scala:6: error: lazy values may not be abstract
+ lazy val t: Int
+ ^
+lazyvals.scala:9: error: lazy not allowed here. Only vals can be lazy
+ lazy var p: Int = 100
+ ^
+lazyvals.scala:12: error: lazy not allowed here. Only vals can be lazy
+ lazy def q: Double = 0.0
+ ^
+lazyvals.scala:15: error: '=' expected but ';' found.
+ lazy val t;
+ ^
+lazyvals.scala:20: error: lazy not allowed here. Only vals can be lazy
+ lazy trait T {}
+ ^
+lazyvals.scala:21: error: lazy not allowed here. Only vals can be lazy
+ lazy class C {}
+ ^
+lazyvals.scala:22: error: lazy not allowed here. Only vals can be lazy
+ lazy object O {}
+ ^
+lazyvals.scala:25: error: lazy modifier not allowed here. Use call-by-name parameters instead
+ class A(lazy val obj: Object) {}
+ ^
+8 errors found
diff --git a/test/files/neg/lazyvals.scala b/test/files/neg/lazyvals.scala
new file mode 100644
index 0000000000..8514d42c13
--- /dev/null
+++ b/test/files/neg/lazyvals.scala
@@ -0,0 +1,26 @@
+
+/** Test which should fail compilation */
+class Lazy {
+
+ // no abstract lazy values
+ lazy val t: Int
+
+ // no lazy var
+ lazy var p: Int = 100
+
+ // no lazy defs
+ lazy def q: Double = 0.0
+
+ def foo {
+ lazy val t;
+ ()
+ }
+
+ // no trait/class/object can be lazy
+ lazy trait T {}
+ lazy class C {}
+ lazy object O {}
+
+ // no lazy modifiers in class parameters
+ class A(lazy val obj: Object) {}
+}
diff --git a/test/files/run/bug603.scala b/test/files/run/bug603.scala
index c1e0aace12..361cef1f41 100644
--- a/test/files/run/bug603.scala
+++ b/test/files/run/bug603.scala
@@ -1,4 +1,4 @@
-object lazy {
+object forceDelay {
class Susp[+A](lazyValue: => A) extends Function0[A] {
private var func: () => Any = () => lazyValue
private var value: Any = null
@@ -21,7 +21,7 @@ object lazy {
}
object Test {
- import lazy._
+ import forceDelay._
def main(args: Array[String]) = {
val s: Susp[Int] = delay { Console.println("evaluating..."); 3 }
diff --git a/test/files/run/lazy-exprs.check b/test/files/run/lazy-exprs.check
new file mode 100644
index 0000000000..2aaa0be3f6
--- /dev/null
+++ b/test/files/run/lazy-exprs.check
@@ -0,0 +1,10 @@
+forced <z1>
+lazy val in scrutinee: ok
+forced <z1>
+lazy val in case: ok
+lazy val in case: forced <z1>
+ok
+lazy val in if condition: forced <z1>
+ok
+lazy val in pattern: forced LazyField
+ok
diff --git a/test/files/run/lazy-exprs.scala b/test/files/run/lazy-exprs.scala
new file mode 100644
index 0000000000..307915bcac
--- /dev/null
+++ b/test/files/run/lazy-exprs.scala
@@ -0,0 +1,84 @@
+object TestExpressions {
+
+ def patmatchScrut {
+ lazy val z1: Option[String] = { println("forced <z1>"); Some("lazy z1") }
+
+ val res = z1 match {
+ case Some(msg) => msg
+ case None => "failed"
+ }
+ print("lazy val in scrutinee: ")
+ if (res == "lazy z1")
+ println("ok")
+ else
+ println("failed")
+ }
+
+ def patmatchCase {
+ val t: Option[String] = Some("test")
+ val res = t match {
+ case Some(msg) =>
+ lazy val z1 = { println("forced <z1>"); "lazy z1" }
+ z1
+
+ case None => "failed"
+ }
+ print("lazy val in case: ")
+ if (res == "lazy z1")
+ println("ok")
+ else
+ println("failed")
+ }
+
+
+ def patmatchPat {
+ lazy val Z1 = { println("forced <z1>"); "lazy Z1" }
+ print("lazy val in case: ")
+ val t: Option[String] = Some("lazy Z1")
+ t match {
+ case Some(Z1) =>
+ println("ok")
+
+ case None =>
+ println("failed")
+ }
+ }
+
+ def ifcond {
+ lazy val z1 = { println("forced <z1>"); "lazy z1" }
+ print("lazy val in if condition: ")
+ if (z1 == "lazy z1")
+ println("ok")
+ else
+ println("failed")
+ }
+
+
+ lazy val LazyField = { println("forced LazyField"); "LazyField" }
+
+ def testPatMatchField {
+ print("lazy val in pattern: ")
+ val t: Option[String] = Some("LazyField")
+ t match {
+ case Some(LazyField) =>
+ println("ok")
+
+ case None =>
+ println("failed")
+ }
+ }
+
+ def test {
+ patmatchScrut
+ patmatchCase
+ patmatchPat
+ ifcond
+ testPatMatchField
+ }
+}
+
+
+object Test extends Application {
+
+ TestExpressions.test
+}
diff --git a/test/files/run/lazy-locals.check b/test/files/run/lazy-locals.check
new file mode 100644
index 0000000000..7f65cd3db2
--- /dev/null
+++ b/test/files/run/lazy-locals.check
@@ -0,0 +1,82 @@
+forced lazy val q
+q = 10
+forced lazy val t
+p = 21
+85
+forced lazy val t31
+forced lazy val t30
+forced lazy val t29
+forced lazy val t28
+forced lazy val t27
+forced lazy val t26
+forced lazy val t25
+forced lazy val t24
+forced lazy val t23
+forced lazy val t22
+forced lazy val t21
+forced lazy val t20
+forced lazy val t19
+forced lazy val t18
+forced lazy val t17
+forced lazy val t16
+forced lazy val t15
+forced lazy val t14
+forced lazy val t13
+forced lazy val t12
+forced lazy val t11
+forced lazy val t10
+forced lazy val t09
+forced lazy val t08
+forced lazy val t07
+forced lazy val t06
+forced lazy val t05
+forced lazy val t04
+forced lazy val t03
+forced lazy val t02
+forced lazy val t01
+forced lazy val t00
+Sum is: 496
+forced lazy val t32
+forced lazy val t31
+forced lazy val t30
+forced lazy val t29
+forced lazy val t28
+forced lazy val t27
+forced lazy val t26
+forced lazy val t25
+forced lazy val t24
+forced lazy val t23
+forced lazy val t22
+forced lazy val t21
+forced lazy val t20
+forced lazy val t19
+forced lazy val t18
+forced lazy val t17
+forced lazy val t16
+forced lazy val t15
+forced lazy val t14
+forced lazy val t13
+forced lazy val t12
+forced lazy val t11
+forced lazy val t10
+forced lazy val t09
+forced lazy val t08
+forced lazy val t07
+forced lazy val t06
+forced lazy val t05
+forced lazy val t04
+forced lazy val t03
+forced lazy val t02
+forced lazy val t01
+forced lazy val t00
+Sum is: 528
+forced lazy val t at n = 0
+42
+forced lazy val t at n = 0
+forced lazy val t at n = 1
+forced lazy val t at n = 2
+forced lazy val t at n = 3
+forced lazy val t at n = 4
+forced lazy val t at n = 5
+1764
+First 5 elements of ones: List(1, 1, 1, 1, 1)
diff --git a/test/files/run/lazy-locals.scala b/test/files/run/lazy-locals.scala
new file mode 100644
index 0000000000..937b5a80c0
--- /dev/null
+++ b/test/files/run/lazy-locals.scala
@@ -0,0 +1,143 @@
+
+object Test extends Application {
+
+ lazy val w = 10
+
+ /** normal test */
+ def testLazy = {
+ lazy val t = { Console.println("forced lazy val t"); 42 }
+ lazy val p = t / 2
+ lazy val q = { println("forced lazy val q"); 10}
+ println("q = " + q)
+ println("p = " + p)
+ 1 + t + t
+ }
+
+ /** test 32 lazy vals, which fills one bitmap int. */
+ def testLazy32 = {
+ lazy val t00 = { Console.println("forced lazy val t00"); 0 }
+ lazy val t01 = { Console.println("forced lazy val t01"); 1 }
+ lazy val t02 = { Console.println("forced lazy val t02"); 2 }
+ lazy val t03 = { Console.println("forced lazy val t03"); 3 }
+ lazy val t04 = { Console.println("forced lazy val t04"); 4 }
+ lazy val t05 = { Console.println("forced lazy val t05"); 5 }
+ lazy val t06 = { Console.println("forced lazy val t06"); 6 }
+ lazy val t07 = { Console.println("forced lazy val t07"); 7 }
+ lazy val t08 = { Console.println("forced lazy val t08"); 8 }
+ lazy val t09 = { Console.println("forced lazy val t09"); 9 }
+ lazy val t10 = { Console.println("forced lazy val t10"); 10 }
+ lazy val t11 = { Console.println("forced lazy val t11"); 11 }
+ lazy val t12 = { Console.println("forced lazy val t12"); 12 }
+ lazy val t13 = { Console.println("forced lazy val t13"); 13 }
+ lazy val t14 = { Console.println("forced lazy val t14"); 14 }
+ lazy val t15 = { Console.println("forced lazy val t15"); 15 }
+ lazy val t16 = { Console.println("forced lazy val t16"); 16 }
+ lazy val t17 = { Console.println("forced lazy val t17"); 17 }
+ lazy val t18 = { Console.println("forced lazy val t18"); 18 }
+ lazy val t19 = { Console.println("forced lazy val t19"); 19 }
+ lazy val t20 = { Console.println("forced lazy val t20"); 20 }
+ lazy val t21 = { Console.println("forced lazy val t21"); 21 }
+ lazy val t22 = { Console.println("forced lazy val t22"); 22 }
+ lazy val t23 = { Console.println("forced lazy val t23"); 23 }
+ lazy val t24 = { Console.println("forced lazy val t24"); 24 }
+ lazy val t25 = { Console.println("forced lazy val t25"); 25 }
+ lazy val t26 = { Console.println("forced lazy val t26"); 26 }
+ lazy val t27 = { Console.println("forced lazy val t27"); 27 }
+ lazy val t28 = { Console.println("forced lazy val t28"); 28 }
+ lazy val t29 = { Console.println("forced lazy val t29"); 29 }
+ lazy val t30 = { Console.println("forced lazy val t30"); 30 }
+ lazy val t31 = { Console.println("forced lazy val t31"); 31 }
+
+ val sum = t31 + t30 + t29 + t28 + t27 + t26 + t25 + t24 + t23 +
+ t22 + t21 + t20 + t19 + t18 + t17 + t16 + t15 + t14 +
+ t13 + t12 + t11 + t10 + t09 + t08 + t07 + t06 + t05 +
+ t04 + t03 + t02 + t01 + t00;
+ println("Sum is: " + sum);
+ }
+
+ /** test 32 lazy vals, which needs two bitmap ints. */
+ def testLazy33 = {
+ lazy val t00 = { Console.println("forced lazy val t00"); 0 }
+ lazy val t01 = { Console.println("forced lazy val t01"); 1 }
+ lazy val t02 = { Console.println("forced lazy val t02"); 2 }
+ lazy val t03 = { Console.println("forced lazy val t03"); 3 }
+ lazy val t04 = { Console.println("forced lazy val t04"); 4 }
+ lazy val t05 = { Console.println("forced lazy val t05"); 5 }
+ lazy val t06 = { Console.println("forced lazy val t06"); 6 }
+ lazy val t07 = { Console.println("forced lazy val t07"); 7 }
+ lazy val t08 = { Console.println("forced lazy val t08"); 8 }
+ lazy val t09 = { Console.println("forced lazy val t09"); 9 }
+ lazy val t10 = { Console.println("forced lazy val t10"); 10 }
+ lazy val t11 = { Console.println("forced lazy val t11"); 11 }
+ lazy val t12 = { Console.println("forced lazy val t12"); 12 }
+ lazy val t13 = { Console.println("forced lazy val t13"); 13 }
+ lazy val t14 = { Console.println("forced lazy val t14"); 14 }
+ lazy val t15 = { Console.println("forced lazy val t15"); 15 }
+ lazy val t16 = { Console.println("forced lazy val t16"); 16 }
+ lazy val t17 = { Console.println("forced lazy val t17"); 17 }
+ lazy val t18 = { Console.println("forced lazy val t18"); 18 }
+ lazy val t19 = { Console.println("forced lazy val t19"); 19 }
+ lazy val t20 = { Console.println("forced lazy val t20"); 20 }
+ lazy val t21 = { Console.println("forced lazy val t21"); 21 }
+ lazy val t22 = { Console.println("forced lazy val t22"); 22 }
+ lazy val t23 = { Console.println("forced lazy val t23"); 23 }
+ lazy val t24 = { Console.println("forced lazy val t24"); 24 }
+ lazy val t25 = { Console.println("forced lazy val t25"); 25 }
+ lazy val t26 = { Console.println("forced lazy val t26"); 26 }
+ lazy val t27 = { Console.println("forced lazy val t27"); 27 }
+ lazy val t28 = { Console.println("forced lazy val t28"); 28 }
+ lazy val t29 = { Console.println("forced lazy val t29"); 29 }
+ lazy val t30 = { Console.println("forced lazy val t30"); 30 }
+ lazy val t31 = { Console.println("forced lazy val t31"); 31 }
+ lazy val t32 = { Console.println("forced lazy val t32"); 32 }
+
+ val sum = t32 + t31 + t30 + t29 + t28 + t27 + t26 + t25 + t24 + t23 +
+ t22 + t21 + t20 + t19 + t18 + t17 + t16 + t15 + t14 +
+ t13 + t12 + t11 + t10 + t09 + t08 + t07 + t06 + t05 +
+ t04 + t03 + t02 + t01 + t00;
+ println("Sum is: " + sum);
+ }
+
+
+ /** test recursive method with lazy vals and a single forced */
+ def testLazyRec(n: Int): Int = {
+ lazy val t = { println("forced lazy val t at n = " + n); 42 }
+ if (n > 0)
+ testLazyRec(n - 1)
+ else
+ t
+ }
+
+ /** test recursive method with lazy vals and a all vals forced */
+ def testLazyRecMany(n: Int): Int = {
+ lazy val t = { println("forced lazy val t at n = " + n); 42 }
+ if (n > 0) {
+ testLazyRecMany(n - 1);
+ t*t
+ } else
+ t
+ }
+
+ def testRecVal {
+ lazy val twos: List[Int] = 2 :: twos
+ lazy val ones: Stream[Int] = Stream.cons(1, ones)
+
+ println("First 5 elements of ones: " + ones.take(5).toList)
+ }
+
+ // should compile without error
+ def testMutualRecVal {
+ lazy val odd: Int = 1 + even
+ lazy val even: Int = 1 + odd
+
+ ()
+ }
+
+ println(testLazy)
+ testLazy32
+ testLazy33
+ println(testLazyRec(5))
+ println(testLazyRecMany(5))
+ testRecVal
+
+}
diff --git a/test/files/run/lazy-traits.check b/test/files/run/lazy-traits.check
new file mode 100644
index 0000000000..dcc8228ac1
--- /dev/null
+++ b/test/files/run/lazy-traits.check
@@ -0,0 +1,154 @@
+Cls test:
+<forced z1>
+z1 = lazy z1
+z1 = lazy z1
+z1 = lazy z1
+Cls2 test:
+<forced z1>
+<forced z2>
+z1 = lazy z1 z2 = lazy z2
+z1 = lazy z1 z2 = lazy z2
+z1 = lazy z1 z2 = lazy z2
+Cls with B test:
+<forced z1>
+<forced zb1>
+<forced zc1>
+z1 = lazy z1 zb1 = lazy zb1 zc1 = lazy zc1
+z1 = lazy z1 zb1 = lazy zb1 zc1 = lazy zc1
+z1 = lazy z1 zb1 = lazy zb1 zc1 = lazy zc1
+OverflownLazyFields with A test:
+<forced zc00>
+<forced zc01>
+<forced zc02>
+<forced zc03>
+<forced zc04>
+<forced zc05>
+<forced zc06>
+<forced zc07>
+<forced zc08>
+<forced zc09>
+<forced zc10>
+<forced zc11>
+<forced zc12>
+<forced zc13>
+<forced zc14>
+<forced zc15>
+<forced zc16>
+<forced zc17>
+<forced zc18>
+<forced zc19>
+<forced zc20>
+<forced zc21>
+<forced zc22>
+<forced zc23>
+<forced zc24>
+<forced zc25>
+<forced zc26>
+<forced zc27>
+<forced zc28>
+<forced zc29>
+<forced zc30>
+<forced zc31>
+<forced z1>
+
+zc00 = lazy zc00
+zc01 = lazy zc01
+zc02 = lazy zc02
+zc03 = lazy zc03
+zc04 = lazy zc04
+zc05 = lazy zc05
+zc06 = lazy zc06
+zc07 = lazy zc07
+zc08 = lazy zc08
+zc09 = lazy zc09
+zc10 = lazy zc10
+zc11 = lazy zc11
+zc12 = lazy zc12
+zc13 = lazy zc13
+zc14 = lazy zc14
+zc15 = lazy zc15
+zc16 = lazy zc16
+zc17 = lazy zc17
+zc18 = lazy zc18
+zc19 = lazy zc19
+zc20 = lazy zc20
+zc21 = lazy zc21
+zc22 = lazy zc22
+zc23 = lazy zc23
+zc24 = lazy zc24
+zc25 = lazy zc25
+zc26 = lazy zc26
+zc27 = lazy zc27
+zc28 = lazy zc28
+zc29 = lazy zc29
+zc30 = lazy zc30
+zc31 = lazy zc31
+z1 = lazy z1
+
+zc00 = lazy zc00
+zc01 = lazy zc01
+zc02 = lazy zc02
+zc03 = lazy zc03
+zc04 = lazy zc04
+zc05 = lazy zc05
+zc06 = lazy zc06
+zc07 = lazy zc07
+zc08 = lazy zc08
+zc09 = lazy zc09
+zc10 = lazy zc10
+zc11 = lazy zc11
+zc12 = lazy zc12
+zc13 = lazy zc13
+zc14 = lazy zc14
+zc15 = lazy zc15
+zc16 = lazy zc16
+zc17 = lazy zc17
+zc18 = lazy zc18
+zc19 = lazy zc19
+zc20 = lazy zc20
+zc21 = lazy zc21
+zc22 = lazy zc22
+zc23 = lazy zc23
+zc24 = lazy zc24
+zc25 = lazy zc25
+zc26 = lazy zc26
+zc27 = lazy zc27
+zc28 = lazy zc28
+zc29 = lazy zc29
+zc30 = lazy zc30
+zc31 = lazy zc31
+z1 = lazy z1
+
+zc00 = lazy zc00
+zc01 = lazy zc01
+zc02 = lazy zc02
+zc03 = lazy zc03
+zc04 = lazy zc04
+zc05 = lazy zc05
+zc06 = lazy zc06
+zc07 = lazy zc07
+zc08 = lazy zc08
+zc09 = lazy zc09
+zc10 = lazy zc10
+zc11 = lazy zc11
+zc12 = lazy zc12
+zc13 = lazy zc13
+zc14 = lazy zc14
+zc15 = lazy zc15
+zc16 = lazy zc16
+zc17 = lazy zc17
+zc18 = lazy zc18
+zc19 = lazy zc19
+zc20 = lazy zc20
+zc21 = lazy zc21
+zc22 = lazy zc22
+zc23 = lazy zc23
+zc24 = lazy zc24
+zc25 = lazy zc25
+zc26 = lazy zc26
+zc27 = lazy zc27
+zc28 = lazy zc28
+zc29 = lazy zc29
+zc30 = lazy zc30
+zc31 = lazy zc31
+z1 = lazy z1
diff --git a/test/files/run/lazy-traits.scala b/test/files/run/lazy-traits.scala
new file mode 100644
index 0000000000..f91da7ed1a
--- /dev/null
+++ b/test/files/run/lazy-traits.scala
@@ -0,0 +1,133 @@
+trait A {
+ lazy val z1 = {
+ println("<forced z1>")
+ "lazy z1"
+ }
+}
+
+/** Simple class which mixes in one lazy val. */
+class Cls extends AnyRef with A {
+ override def toString =
+ "z1 = " + z1
+}
+
+/** Own lazy val + one mixed in. */
+class Cls2 extends AnyRef with A {
+ lazy val z2 = {
+ println("<forced z2>")
+ "lazy z2"
+ }
+
+ override def toString =
+ "z1 = " + z1 + " z2 = " + z2
+}
+
+trait B extends A {
+ lazy val zb1 = {
+ println("<forced zb1>")
+ "lazy zb1"
+ }
+}
+
+class ClsB extends Object with B {
+ lazy val zc1 = {
+ println("<forced zc1>")
+ "lazy zc1"
+ }
+ override def toString =
+ "z1 = " + z1 + " zb1 = " + zb1 + " zc1 = " + zc1
+}
+
+/** Class with 32 lazy fields mixes in one more. */
+class OverflownLazyFields extends Object with A {
+ lazy val zc00 = { println("<forced zc00>"); "lazy zc00" }
+ lazy val zc01 = { println("<forced zc01>"); "lazy zc01" }
+ lazy val zc02 = { println("<forced zc02>"); "lazy zc02" }
+ lazy val zc03 = { println("<forced zc03>"); "lazy zc03" }
+ lazy val zc04 = { println("<forced zc04>"); "lazy zc04" }
+ lazy val zc05 = { println("<forced zc05>"); "lazy zc05" }
+ lazy val zc06 = { println("<forced zc06>"); "lazy zc06" }
+ lazy val zc07 = { println("<forced zc07>"); "lazy zc07" }
+ lazy val zc08 = { println("<forced zc08>"); "lazy zc08" }
+ lazy val zc09 = { println("<forced zc09>"); "lazy zc09" }
+ lazy val zc10 = { println("<forced zc10>"); "lazy zc10" }
+ lazy val zc11 = { println("<forced zc11>"); "lazy zc11" }
+ lazy val zc12 = { println("<forced zc12>"); "lazy zc12" }
+ lazy val zc13 = { println("<forced zc13>"); "lazy zc13" }
+ lazy val zc14 = { println("<forced zc14>"); "lazy zc14" }
+ lazy val zc15 = { println("<forced zc15>"); "lazy zc15" }
+ lazy val zc16 = { println("<forced zc16>"); "lazy zc16" }
+ lazy val zc17 = { println("<forced zc17>"); "lazy zc17" }
+ lazy val zc18 = { println("<forced zc18>"); "lazy zc18" }
+ lazy val zc19 = { println("<forced zc19>"); "lazy zc19" }
+ lazy val zc20 = { println("<forced zc20>"); "lazy zc20" }
+ lazy val zc21 = { println("<forced zc21>"); "lazy zc21" }
+ lazy val zc22 = { println("<forced zc22>"); "lazy zc22" }
+ lazy val zc23 = { println("<forced zc23>"); "lazy zc23" }
+ lazy val zc24 = { println("<forced zc24>"); "lazy zc24" }
+ lazy val zc25 = { println("<forced zc25>"); "lazy zc25" }
+ lazy val zc26 = { println("<forced zc26>"); "lazy zc26" }
+ lazy val zc27 = { println("<forced zc27>"); "lazy zc27" }
+ lazy val zc28 = { println("<forced zc28>"); "lazy zc28" }
+ lazy val zc29 = { println("<forced zc29>"); "lazy zc29" }
+ lazy val zc30 = { println("<forced zc30>"); "lazy zc30" }
+ lazy val zc31 = { println("<forced zc31>"); "lazy zc31" }
+
+ override def toString =
+ "\nzc00 = " + zc00 +
+ "\nzc01 = " + zc01 +
+ "\nzc02 = " + zc02 +
+ "\nzc03 = " + zc03 +
+ "\nzc04 = " + zc04 +
+ "\nzc05 = " + zc05 +
+ "\nzc06 = " + zc06 +
+ "\nzc07 = " + zc07 +
+ "\nzc08 = " + zc08 +
+ "\nzc09 = " + zc09 +
+ "\nzc10 = " + zc10 +
+ "\nzc11 = " + zc11 +
+ "\nzc12 = " + zc12 +
+ "\nzc13 = " + zc13 +
+ "\nzc14 = " + zc14 +
+ "\nzc15 = " + zc15 +
+ "\nzc16 = " + zc16 +
+ "\nzc17 = " + zc17 +
+ "\nzc18 = " + zc18 +
+ "\nzc19 = " + zc19 +
+ "\nzc20 = " + zc20 +
+ "\nzc21 = " + zc21 +
+ "\nzc22 = " + zc22 +
+ "\nzc23 = " + zc23 +
+ "\nzc24 = " + zc24 +
+ "\nzc25 = " + zc25 +
+ "\nzc26 = " + zc26 +
+ "\nzc27 = " + zc27 +
+ "\nzc28 = " + zc28 +
+ "\nzc29 = " + zc29 +
+ "\nzc30 = " + zc30 +
+ "\nzc31 = " + zc31 +
+ "\nz1 = " + z1
+}
+
+trait PrivateLazy {
+ private lazy val str = "z1"
+}
+
+/** Test successful compilation. */
+class InheritPrivateLazy extends AnyRef with PrivateLazy {}
+
+
+object Test extends Application {
+
+ def test(name: String, v: A) {
+ println(name + " test:")
+ println(v)
+ println(v)
+ println(v)
+ }
+
+ test("Cls", new Cls)
+ test("Cls2", new Cls2)
+ test("Cls with B", new ClsB)
+ test("OverflownLazyFields with A", new OverflownLazyFields)
+}