object Logs {
val logBuf = new collection.mutable.StringBuilder()
def log(m: Any): Unit = { if (logBuf.nonEmpty) logBuf.append(":"); logBuf.append(m) }
def checkLog(expected: String): Unit = {
val res = logBuf.toString
assert(res == expected, s"expected:\n$expected\nfound:\n$res")
logBuf.clear()
}
}
import Logs._
class C {
def getInt : Int = { log("getInt"); 1 }
def getString: String = { log("getString"); "s" }
def getUnit : Unit = { log("getUnit") }
lazy val t1 = getInt
lazy val t2 = getString
lazy val t3 = getUnit
checkLog("")
def m1 = {
lazy val t1 = getInt
t1 + t1
}
def m2 = {
lazy val t1 = getString
t1 + t1
}
def m3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("")
val vl1 = {
lazy val t1 = getInt
t1 + t1
}
val vl2 = {
lazy val t1 = getString
t1 + t1
}
val vl3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("getInt:getString:getUnit:():()")
var vr1 = {
lazy val t1 = getInt
t1 + t1
}
var vr2 = {
lazy val t1 = getString
t1 + t1
}
var vr3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("getInt:getString:getUnit:():()")
lazy val lvl1 = {
lazy val t1 = getInt
t1 + t1
}
lazy val lvl2 = {
lazy val t1 = getString
t1 + t1
}
lazy val lvl3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("")
{
lazy val t1 = getInt
lazy val t2 = getString
lazy val t3 = getUnit
log(t1 + t1)
log(t2 + t2)
log(t3); log(t3)
}
checkLog("getInt:2:getString:ss:getUnit:():()")
def run(): Unit = {
log(t1); log(t1);
log(t2); log(t2);
log(t3); log(t3);
checkLog("getInt:1:1:getString:s:s:getUnit:():()")
log(m1); log(m1)
log(m2); log(m2)
log(m3); log(m3)
checkLog("getInt:2:getInt:2:getString:ss:getString:ss:getUnit:():():():getUnit:():():()")
log(vl1); log(vl1)
log(vl2); log(vl2)
log(vl3); log(vl3)
checkLog("2:2:ss:ss:():()")
log(vr1); log(vr1); vr1 = 393; log(vr1)
log(vr2); log(vr2); vr2 = "h"; log(vr2)
log(vr3); log(vr3); vr3 = () ; log(vr3)
checkLog("2:2:393:ss:ss:h:():():()")
log(lvl1); log(lvl1)
log(lvl2); log(lvl2)
log(lvl3); log(lvl3)
checkLog("getInt:2:2:getString:ss:ss:getUnit:():():():()")
}
}
trait T {
def getInt : Int = { log("getInt"); 1 }
def getString: String = { log("getString"); "s" }
def getUnit : Unit = { log("getUnit") }
lazy val t1 = getInt
lazy val t2 = getString
lazy val t3 = getUnit
checkLog("")
def m1 = {
lazy val t1 = getInt
t1 + t1
}
def m2 = {
lazy val t1 = getString
t1 + t1
}
def m3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("")
val vl1 = {
lazy val t1 = getInt
t1 + t1
}
val vl2 = {
lazy val t1 = getString
t1 + t1
}
val vl3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("getInt:getString:getUnit:():()")
var vr1 = {
lazy val t1 = getInt
t1 + t1
}
var vr2 = {
lazy val t1 = getString
t1 + t1
}
var vr3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("getInt:getString:getUnit:():()")
lazy val lvl1 = {
lazy val t1 = getInt
t1 + t1
}
lazy val lvl2 = {
lazy val t1 = getString
t1 + t1
}
lazy val lvl3 = {
lazy val t1 = getUnit
log(t1); log(t1)
}
checkLog("")
{
lazy val t1 = getInt
lazy val t2 = getString
lazy val t3 = getUnit
log(t1 + t1)
log(t2 + t2)
log(t3); log(t3)
}
checkLog("getInt:2:getString:ss:getUnit:():()")
def run(): Unit = {
log(t1); log(t1);
log(t2); log(t2);
log(t3); log(t3);
checkLog("getInt:1:1:getString:s:s:getUnit:():()")
log(m1); log(m1)
log(m2); log(m2)
log(m3); log(m3)
checkLog("getInt:2:getInt:2:getString:ss:getString:ss:getUnit:():():():getUnit:():():()")
log(vl1); log(vl1)
log(vl2); log(vl2)
log(vl3); log(vl3)
checkLog("2:2:ss:ss:():()")
log(vr1); log(vr1); vr1 = 393; log(vr1)
log(vr2); log(vr2); vr2 = "h"; log(vr2)
log(vr3); log(vr3); vr3 = () ; log(vr3)
checkLog("2:2:393:ss:ss:h:():():()")
log(lvl1); log(lvl1)
log(lvl2); log(lvl2)
log(lvl3); log(lvl3)
checkLog("getInt:2:2:getString:ss:ss:getUnit:():():():()")
}
}
class D extends T
class D1 extends T {
override lazy val t1 = { log("o-t1"); -1 }
checkLog("")
override def m1 = { log("o-m1"); -2 }
override val m2 = { log("o-m2"); "n" }
override lazy val m3 = { log("o-m3") }
checkLog("o-m2")
override val vl1 = { log("o-vl1"); -3 }
checkLog("o-vl1")
override lazy val lvl1 = { log("o-lvl1"); -4 }
checkLog("")
override def run(): Unit = {
log(t1); log(t1)
checkLog("o-t1:-1:-1")
log(m1); log(m1)
log(m2); log(m2)
log(m3); log(m3)
checkLog("o-m1:-2:o-m1:-2:n:n:o-m3:():()")
log(vl1); log(vl1)
checkLog("-3:-3")
log(lvl1); log(lvl1)
checkLog("o-lvl1:-4:-4")
}
}
class E {
object T { log("init T"); override def toString = "T" }
def m = { object T { log("init T"); val x = 1 }; T.x }
checkLog("")
}
object Test {
def main(args: Array[String]): Unit = {
val c = new C
c.run()
val lzyComputeMethods = c.getClass.getDeclaredMethods.filter(_.getName contains "lzycompute").map(_.getName).toList.sorted
val expComputeMethods = List("lvl1$lzycompute", "lvl2$lzycompute", "lvl3$lzycompute", "t1$lzycompute", "t1$lzycompute$1", "t1$lzycompute$10", "t1$lzycompute$11", "t1$lzycompute$12", "t1$lzycompute$13", "t1$lzycompute$2", "t1$lzycompute$3", "t1$lzycompute$4", "t1$lzycompute$5", "t1$lzycompute$6", "t1$lzycompute$7", "t1$lzycompute$8", "t1$lzycompute$9", "t2$lzycompute", "t2$lzycompute$1", "t3$lzycompute", "t3$lzycompute$1")
assert(
lzyComputeMethods == expComputeMethods,
s"wrong lzycompute methods. expected:\n$expComputeMethods\nfound:\n$lzyComputeMethods")
val fields = c.getClass.getDeclaredFields.toList.sortBy(_.getName).map(_.toString)
val expFields = List(
"private volatile byte C.bitmap$0",
"private int C.lvl1",
"private java.lang.String C.lvl2",
"private scala.runtime.BoxedUnit C.lvl3",
"private int C.t1",
"private java.lang.String C.t2",
"private scala.runtime.BoxedUnit C.t3",
"private final int C.vl1",
"private final java.lang.String C.vl2",
"private final scala.runtime.BoxedUnit C.vl3",
"private int C.vr1",
"private java.lang.String C.vr2",
"private scala.runtime.BoxedUnit C.vr3")
assert(
fields == expFields,
s"wrong fields. expected:\n$expFields\nfound:\n$fields")
val d = new D
d.run()
val dFields = d.getClass.getDeclaredFields.toList.sortBy(_.getName).map(_.toString)
assert(
dFields == expFields.map(_.replaceAll(" C.", " D.")),
s"wrong fields. expected:\n$expFields\nfound:\n$fields")
val d1 = new D1
d1.run()
val e = new E
log(e.T); log(e.T)
checkLog("init T:T:T")
log(e.m); log(e.m)
checkLog("init T:1:init T:1")
}
}