aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-09-12 02:29:53 +0200
committerMartin Odersky <odersky@gmail.com>2014-09-12 02:29:53 +0200
commit2317764b683fe548f7c5e3b5ee5ede9760433c61 (patch)
tree812021ca83db7c3120ebe4a1797015b04856996e /src/dotty/tools/dotc
parentbb5b049076ca733ea42e528ecef81de438a15b19 (diff)
downloaddotty-2317764b683fe548f7c5e3b5ee5ede9760433c61.tar.gz
dotty-2317764b683fe548f7c5e3b5ee5ede9760433c61.tar.bz2
dotty-2317764b683fe548f7c5e3b5ee5ede9760433c61.zip
New phase: CapturedVars
Breaks out boxing functionality of captured vars from lambda lift.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala9
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala2
-rw-r--r--src/dotty/tools/dotc/transform/CapturedVars.scala107
4 files changed, 120 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index cd5ef4cae..302a935e2 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -63,7 +63,8 @@ class Compiler {
new TypeTestsCasts,
new InterceptedMethods,
new Literalize),
- List(new Erasure)
+ List(new Erasure),
+ List(new CapturedVars)
)
var runId = 1
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index cace6df74..72c42e719 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -538,6 +538,15 @@ class Definitions {
vcls
}
+ /** The classes for which a Ref type exists. */
+ lazy val refClasses: collection.Set[Symbol] = ScalaNumericValueClasses + BooleanClass + ObjectClass
+
+ lazy val refClass: Map[Symbol, Symbol] =
+ refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.${rc.name}Ref")).toMap
+
+ lazy val volatileRefClass: Map[Symbol, Symbol] =
+ refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap
+
def wrapArrayMethodName(elemtp: Type): TermName = {
val cls = elemtp.classSymbol
if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name)
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index af4e810de..3cafd2af7 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -344,6 +344,7 @@ object StdNames {
// val conforms : N = "conforms" // Dotty deviation: no special treatment of conforms, so the occurrence of the name here would cause to unintended implicit shadowing. Should find a less common name for it in Predef.
val copy: N = "copy"
val currentMirror: N = "currentMirror"
+ val create: N = "create"
val definitions: N = "definitions"
val delayedInit: N = "delayedInit"
val delayedInitArg: N = "delayedInit$body"
@@ -484,6 +485,7 @@ object StdNames {
val withFilter: N = "withFilter"
val withFilterIfRefutable: N = "withFilterIfRefutable$"
val wrap: N = "wrap"
+ val zero: N = "zero"
val zip: N = "zip"
val synthSwitch: N = "$synthSwitch"
diff --git a/src/dotty/tools/dotc/transform/CapturedVars.scala b/src/dotty/tools/dotc/transform/CapturedVars.scala
new file mode 100644
index 000000000..d5bd56bc3
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/CapturedVars.scala
@@ -0,0 +1,107 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import core.SymDenotations._
+import core.StdNames.nme
+import core.Names._
+import core.NameOps._
+import ast.Trees._
+import SymUtils._
+import collection.{ mutable, immutable }
+import collection.mutable.{ LinkedHashMap, LinkedHashSet, TreeSet }
+
+class CapturedVars extends MiniPhaseTransform with SymTransformer { thisTransformer =>
+ import ast.tpd._
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "capturedVars"
+
+ override def treeTransformPhase = thisTransformer.next
+
+ private var captured: mutable.HashSet[Symbol] = _
+
+ private class CollectCaptured(implicit ctx: Context) extends TreeAccumulator[Symbol] {
+ def apply(enclMeth: Symbol, tree: Tree) = {
+ tree match {
+ case id: Ident =>
+ val sym = id.symbol
+ if (sym.is(Mutable, butNot = Method) && sym.owner.isTerm && sym.enclosingMethod != enclMeth) {
+ ctx.log(i"capturing $sym in ${sym.enclosingMethod}, referenced from $enclMeth")
+ captured += sym
+ }
+ case tree: DefTree if tree.symbol.exists =>
+ foldOver(tree.symbol.enclosingMethod, tree)
+ case _ =>
+ foldOver(enclMeth, tree)
+ }
+ enclMeth
+ }
+ def runOver(tree: Tree) = {
+ captured = mutable.HashSet()
+ apply(NoSymbol, tree)
+ }
+ }
+
+ override def init(implicit ctx: Context, info: TransformerInfo): Unit =
+ (new CollectCaptured).runOver(ctx.compilationUnit.tpdTree)
+
+ override def transformSym(sd: SymDenotation)(implicit ctx: Context): SymDenotation =
+ if (captured(sd.symbol)) {
+ val newd = sd.copySymDenotation(
+ info = refCls(sd.info.classSymbol, sd.hasAnnotation(defn.VolatileAnnot)).typeRef)
+ newd.removeAnnotation(defn.VolatileAnnot)
+ newd
+ } else sd
+
+ /** The {Volatile|}{Int|Double|...|Object}Ref class corresponding to the class `cls`,
+ * depending on whether the reference should be @volatile
+ */
+ def refCls(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = {
+ val refMap = if (isVolatile) defn.volatileRefClass else defn.refClass
+ refMap.getOrElse(cls, refMap(defn.ObjectClass))
+ }
+
+ def capturedType(vble: Symbol)(implicit ctx: Context): Type = {
+ val oldInfo = vble.denot(ctx.withPhase(thisTransformer)).info
+ refCls(oldInfo.classSymbol, vble.isVolatile).typeRef
+ }
+
+ override def transformValDef(vdef: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val vble = vdef.symbol
+ if (captured contains vble) {
+ def boxMethod(name: TermName): Tree =
+ ref(vble.info.classSymbol.companionModule.info.member(name).symbol)
+ cpy.ValDef(vdef)(
+ rhs = vdef.rhs match {
+ case EmptyTree => boxMethod(nme.zero).appliedToNone.withPos(vdef.pos)
+ case arg => boxMethod(nme.create).appliedTo(arg)
+ },
+ tpt = TypeTree(vble.info).withPos(vdef.tpt.pos))
+ }
+ else vdef
+ }
+
+ override def transformIdent(id: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val vble = id.symbol
+ if (captured(vble))
+ (id select nme.elem).ensureConforms(vble.denot(ctx.withPhase(thisTransformer)).info)
+ else id
+ }
+
+ override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val lhs1 = tree.lhs match {
+ case TypeApply(Select(qual @ Select(qual2, nme.elem), nme.asInstanceOf_), _) =>
+ assert(captured(qual2.symbol))
+ qual
+ case _ => tree.lhs
+ }
+ cpy.Assign(tree)(lhs1, tree.rhs)
+ }
+} \ No newline at end of file