diff options
author | Martin Odersky <odersky@gmail.com> | 2014-09-12 02:29:53 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-09-12 02:29:53 +0200 |
commit | 2317764b683fe548f7c5e3b5ee5ede9760433c61 (patch) | |
tree | 812021ca83db7c3120ebe4a1797015b04856996e /src/dotty/tools | |
parent | bb5b049076ca733ea42e528ecef81de438a15b19 (diff) | |
download | dotty-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')
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/CapturedVars.scala | 107 |
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 |