From d2670a7e6ddfc3a71f7b38aefb831b684059d468 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Oct 2014 15:20:48 +0100 Subject: [PATCH 1/8] Made LambdaLift capable of having minitransforms run after it. Some changes needed so that Flatten can run after LambdaLift --- .../tools/dotc/transform/LambdaLift.scala | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala index 196753e82d8e..051c6065eeb8 100644 --- a/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -278,20 +278,20 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this } } - override def init(implicit ctx: Context, info: TransformerInfo) = { - free.clear() - proxyMap.clear() - called.clear() - calledFromInner.clear() - liftedOwner.clear() - liftedDefs.clear() - assert(ctx.phase == thisTransform) - (new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree) - computeFreeVars() - computeLiftedOwners() - generateProxies()(ctx.withPhase(thisTransform.next)) - liftLocals()(ctx.withPhase(thisTransform.next)) - } + override def init(implicit ctx: Context, info: TransformerInfo) = + ctx.atPhase(thisTransform) { implicit ctx => + free.clear() + proxyMap.clear() + called.clear() + calledFromInner.clear() + liftedOwner.clear() + liftedDefs.clear() + (new CollectDependencies).traverse(NoSymbol, ctx.compilationUnit.tpdTree) + computeFreeVars() + computeLiftedOwners() + generateProxies()(ctx.withPhase(thisTransform.next)) + liftLocals()(ctx.withPhase(thisTransform.next)) + } private def currentEnclosure(implicit ctx: Context) = ctx.owner.enclosingMethod.skipConstructor @@ -355,8 +355,12 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this } } - private def liftDef(tree: MemberDef)(implicit ctx: Context): Tree = { - liftedDefs(tree.symbol.owner) += rename(tree, tree.symbol.name) + private def liftDef(tree: MemberDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + val buf = liftedDefs(tree.symbol.owner) + transformFollowing(rename(tree, tree.symbol.name)) match { + case Thicket(trees) => buf ++= trees + case tree => buf += tree + } EmptyTree } From ad45e2e4b72057499b33a1cb4fbf5eb41ab8651c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Oct 2014 15:21:33 +0100 Subject: [PATCH 2/8] New miniphase: Flatten --- src/dotty/tools/dotc/Compiler.scala | 3 +- src/dotty/tools/dotc/Flatten.scala | 15 ------ .../dotc/{ => transform}/ElimLocals.scala | 0 src/dotty/tools/dotc/transform/Flatten.scala | 49 +++++++++++++++++++ src/dotty/tools/dotc/transform/SymUtils.scala | 7 ++- .../tools/dotc/transform/TreeChecker.scala | 2 +- test/dotc/tests.scala | 2 +- 7 files changed, 59 insertions(+), 19 deletions(-) delete mode 100644 src/dotty/tools/dotc/Flatten.scala rename src/dotty/tools/dotc/{ => transform}/ElimLocals.scala (100%) create mode 100644 src/dotty/tools/dotc/transform/Flatten.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index d141b7488f2a..cb70480ce7c9 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -55,7 +55,8 @@ class Compiler { List(new Erasure), List(new CapturedVars, new Constructors), - List(new LambdaLift) + List(new LambdaLift, + new Flatten) ) var runId = 1 diff --git a/src/dotty/tools/dotc/Flatten.scala b/src/dotty/tools/dotc/Flatten.scala deleted file mode 100644 index d7ccc1ae4e11..000000000000 --- a/src/dotty/tools/dotc/Flatten.scala +++ /dev/null @@ -1,15 +0,0 @@ -package dotty.tools.dotc -package transform - -import core._ -import DenotTransformers.SymTransformer -import Phases.Phase -import Contexts.Context -import SymDenotations.SymDenotation -import TreeTransforms.MiniPhaseTransform - -class Flatten extends MiniPhaseTransform with SymTransformer { thisTransformer => - override def phaseName = "flatten" - - def transformSym(ref: SymDenotation)(implicit ctx: Context) = ??? -} diff --git a/src/dotty/tools/dotc/ElimLocals.scala b/src/dotty/tools/dotc/transform/ElimLocals.scala similarity index 100% rename from src/dotty/tools/dotc/ElimLocals.scala rename to src/dotty/tools/dotc/transform/ElimLocals.scala diff --git a/src/dotty/tools/dotc/transform/Flatten.scala b/src/dotty/tools/dotc/transform/Flatten.scala new file mode 100644 index 000000000000..769503f9d6ef --- /dev/null +++ b/src/dotty/tools/dotc/transform/Flatten.scala @@ -0,0 +1,49 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.SymTransformer +import Phases.Phase +import Contexts.Context +import Flags._ +import SymUtils._ +import SymDenotations.SymDenotation +import collection.mutable +import TreeTransforms.MiniPhaseTransform +import dotty.tools.dotc.transform.TreeTransforms.TransformerInfo + +class Flatten extends MiniPhaseTransform with SymTransformer { thisTransform => + import ast.tpd._ + override def phaseName = "flatten" + + def transformSym(ref: SymDenotation)(implicit ctx: Context) = { + if (ref.isClass && !ref.is(Package) && !ref.owner.is(Package)) { + ref.copySymDenotation( + name = ref.flatName, + owner = ref.enclosingPackageClass) + } + else ref + } + + override def treeTransformPhase = thisTransform.next + + private val liftedDefs = new mutable.ListBuffer[Tree] + + private def liftIfNested(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = + if (ctx.owner is Package) tree + else { + liftedDefs += transformFollowing(tree) + EmptyTree + } + + override def transformStats(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo) = + if (ctx.owner is Package) { + val liftedStats = stats ++ liftedDefs + liftedDefs.clear + liftedStats + } + else stats + + override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = + liftIfNested(tree) +} diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala index 2875327c4712..ba45d3f04663 100644 --- a/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/src/dotty/tools/dotc/transform/SymUtils.scala @@ -5,6 +5,7 @@ import core._ import Types._ import Contexts._ import Symbols._ +import SymDenotations._ import Decorators._ import Names._ import StdNames._ @@ -13,7 +14,8 @@ import Flags._ import language.implicitConversions object SymUtils { - implicit def decorateSymUtils(sym: Symbol): SymUtils = new SymUtils(sym) + implicit def decorateSymbol(sym: Symbol): SymUtils = new SymUtils(sym) + implicit def decorateSymDenot(d: SymDenotation): SymUtils = new SymUtils(d.symbol) } /** A decorator that provides methods on symbols @@ -64,4 +66,7 @@ class SymUtils(val self: Symbol) extends AnyVal { def field(implicit ctx: Context): Symbol = self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol + + /** `fullName` where `$' is the separator character */ + def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$') } diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index d2f30e7baf78..f6e36a129b6a 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -180,7 +180,7 @@ class TreeChecker { override def typedStats(trees: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = { for (tree <- trees) tree match { case tree: untpd.DefTree => checkOwner(tree) - case _: untpd.Thicket => assert(false, "unexpanded thicket in statement sequence") + case _: untpd.Thicket => assert(false, i"unexpanded thicket $tree in statement sequence $trees%\n%") case _ => } super.typedStats(trees, exprOwner) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 71a1600bb7da..ac1fbe735d60 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -15,7 +15,7 @@ class tests extends CompilerTest { implicit val defaultOptions = noCheckOptions ++ List( "-Yno-deep-subtypes", - "-Ycheck:patternMatcher,gettersSetters,lambdaLift" + "-Ycheck:patternMatcher,gettersSetters,flatten" ) val twice = List("#runs", "2", "-YnoDoubleBindings") From 252b6d9f3a80bdfc789e2f5b463ee7dc7a10b659 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Oct 2014 16:21:06 +0100 Subject: [PATCH 3/8] Generalize lift behavior between Flatten and LambdaLift To be combinable with follow-up mini-phases the lift operation needs to handle Thickets specially. This commit factors out the behavior from LambdaLift, so that Flatten can do the same thing. --- src/dotty/tools/dotc/ast/Trees.scala | 7 +++++++ src/dotty/tools/dotc/transform/Flatten.scala | 2 +- src/dotty/tools/dotc/transform/LambdaLift.scala | 5 +---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 71026a4499f3..648f19a4fbb2 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -347,6 +347,11 @@ object Trees { s } + /** If this is a thicket, gerform `op` on each of its trees + * otherwise, perform `op` ion tree itself. + */ + def foreachInThicket(op: Tree[T] => Unit): Unit = op(this) + override def toText(printer: Printer) = printer.toText(this) override def hashCode(): Int = System.identityHashCode(this) @@ -809,6 +814,8 @@ object Trees { val newTrees = trees.map(_.withPos(pos)) new Thicket[T](newTrees).asInstanceOf[this.type] } + override def foreachInThicket(op: Tree[T] => Unit): Unit = + trees foreach (_.foreachInThicket(op)) } class EmptyValDef[T >: Untyped] extends ValDef[T]( diff --git a/src/dotty/tools/dotc/transform/Flatten.scala b/src/dotty/tools/dotc/transform/Flatten.scala index 769503f9d6ef..dceefc0bc90b 100644 --- a/src/dotty/tools/dotc/transform/Flatten.scala +++ b/src/dotty/tools/dotc/transform/Flatten.scala @@ -32,7 +32,7 @@ class Flatten extends MiniPhaseTransform with SymTransformer { thisTransform => private def liftIfNested(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = if (ctx.owner is Package) tree else { - liftedDefs += transformFollowing(tree) + transformFollowing(tree).foreachInThicket(liftedDefs += _) EmptyTree } diff --git a/src/dotty/tools/dotc/transform/LambdaLift.scala b/src/dotty/tools/dotc/transform/LambdaLift.scala index 051c6065eeb8..f36ff6247a3a 100644 --- a/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -357,10 +357,7 @@ class LambdaLift extends MiniPhaseTransform with IdentityDenotTransformer { this private def liftDef(tree: MemberDef)(implicit ctx: Context, info: TransformerInfo): Tree = { val buf = liftedDefs(tree.symbol.owner) - transformFollowing(rename(tree, tree.symbol.name)) match { - case Thicket(trees) => buf ++= trees - case tree => buf += tree - } + transformFollowing(rename(tree, tree.symbol.name)).foreachInThicket(buf += _) EmptyTree } From 936e83f3617e7dd1b9141cf20b1dc8ec3482df97 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Oct 2014 11:52:43 +0100 Subject: [PATCH 4/8] New phase: RestoreScopes Cleans up after LambdaLift and Flatten. RestoreScopes exhibited a problem (double definition) when compiling Unpickler. The root of the problem was in Applications.scala. The effect was that arguments woulkd be lifted out, but then the argument expression would be used anyway. That caused a closure to be present twice which caused the double def error much later. -Ycheck did not catch it because the two closure expressions were in non-overlapping scopes. --- src/dotty/tools/dotc/Compiler.scala | 3 +- .../tools/dotc/transform/RestoreScopes.scala | 36 +++++++++++++++++++ src/dotty/tools/dotc/typer/Applications.scala | 2 +- test/dotc/tests.scala | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/dotty/tools/dotc/transform/RestoreScopes.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index cb70480ce7c9..d4fa7e671104 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -56,7 +56,8 @@ class Compiler { List(new CapturedVars, new Constructors), List(new LambdaLift, - new Flatten) + new Flatten, + new RestoreScopes) ) var runId = 1 diff --git a/src/dotty/tools/dotc/transform/RestoreScopes.scala b/src/dotty/tools/dotc/transform/RestoreScopes.scala new file mode 100644 index 000000000000..4a42523266ec --- /dev/null +++ b/src/dotty/tools/dotc/transform/RestoreScopes.scala @@ -0,0 +1,36 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.IdentityDenotTransformer +import Contexts.Context +import Symbols._ +import Scopes._ +import collection.mutable +import TreeTransforms.MiniPhaseTransform +import ast.Trees._ +import TreeTransforms.TransformerInfo + +/** The preceding lambda lift and flatten phases move symbols to different scopes + * and rename them. This miniphase cleans up afterwards and makes sure that all + * class scopes contain the symbols defined in them. + */ +class RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform => + import ast.tpd._ + override def phaseName = "restoreScopes" + + override def treeTransformPhase = thisTransform.next + + override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = { + val TypeDef(_, _, Template(constr, _, _, body)) = tree + val restoredDecls = newScope + for (stat <- constr :: body) + if (stat.isInstanceOf[MemberDef] && stat.symbol.exists) + restoredDecls.enter(stat.symbol) + val cinfo = tree.symbol.asClass.classInfo + tree.symbol.copySymDenotation( + info = cinfo.derivedClassInfo( // Dotty deviation: Cannot expand cinfo inline without a type error + decls = restoredDecls: Scope)).installAfter(thisTransform) + tree + } +} diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 035f19028d7c..a237e7781822 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -461,7 +461,7 @@ trait Applications extends Compatibility { self: Typer => val result = { var typedArgs = typedArgBuf.toList - val app0 = cpy.Apply(app)(normalizedFun, typedArgs) + def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later val app1 = if (!success) app0.withType(ErrorType) else { diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index ac1fbe735d60..a52f79abd0ba 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -15,7 +15,7 @@ class tests extends CompilerTest { implicit val defaultOptions = noCheckOptions ++ List( "-Yno-deep-subtypes", - "-Ycheck:patternMatcher,gettersSetters,flatten" + "-Ycheck:patternMatcher,gettersSetters,restoreScopes" ) val twice = List("#runs", "2", "-YnoDoubleBindings") From d907f26da9f0d3625a4c35021993f04a553bd354 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Oct 2014 17:07:40 +0100 Subject: [PATCH 5/8] Bugfix for superaccessors Threw away list of constructed statements. --- src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 7cb4c5825b10..b11658efb7b6 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -295,7 +295,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this val body1 = forwardParamAccessors(transformStats(impl.body, tree.symbol)) accDefs -= currentClass ownStats ++= body1 - cpy.Template(impl)(body = body1) + cpy.Template(impl)(body = ownStats.toList) } transformTemplate From 250418e830bc7ccacf13cb0d3a9121238d99632a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 30 Oct 2014 17:09:34 +0100 Subject: [PATCH 6/8] New phase: PrivateToStatic Make private methods in traits static, so that we do not need to give a default for them. --- src/dotty/tools/dotc/Compiler.scala | 3 +- src/dotty/tools/dotc/ast/tpd.scala | 2 +- src/dotty/tools/dotc/core/Flags.scala | 3 + .../tools/dotc/printing/RefinedPrinter.scala | 6 +- .../dotc/transform/PrivateToStatic.scala | 90 +++++++++++++++++++ tests/pos/CoderTrait.scala | 63 +++++++++++++ tests/pos/privates.scala | 9 ++ tests/pos/traits.scala | 25 ++++++ 8 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 src/dotty/tools/dotc/transform/PrivateToStatic.scala create mode 100644 tests/pos/CoderTrait.scala create mode 100644 tests/pos/privates.scala create mode 100644 tests/pos/traits.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index d4fa7e671104..f4690df08987 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -57,7 +57,8 @@ class Compiler { new Constructors), List(new LambdaLift, new Flatten, - new RestoreScopes) + new RestoreScopes), + List(new PrivateToStatic) ) var runId = 1 diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index d0f64f5a7b24..74ba79176ea8 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -263,7 +263,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { case _ => false } - try test + try test || tp.symbol.is(JavaStatic) catch { // See remark in SymDenotations#accessWithin case ex: NotDefinedHere => test(ctx.addMode(Mode.FutureDefsOK)) } diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index e5bf27eaeb00..804f6af1a3f0 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -512,6 +512,9 @@ object Flags { /** Labeled `private` or `final` */ final val PrivateOrFinal = Private | Final + /** A private method */ + final val PrivateMethod = allOf(Private, Method) + /** A type parameter with synthesized name */ final val ExpandedTypeParam = allOf(ExpandedName, TypeParam) diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index f0d55882403b..e43aaa24fbec 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -36,7 +36,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def nameString(name: Name): String = name.decode.toString override protected def simpleNameString(sym: Symbol): String = - sym.originalName.decode.toString + sym.name.decode.toString override protected def fullNameOwner(sym: Symbol) = { val owner = super.fullNameOwner(sym) @@ -222,7 +222,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { "`" ~ toText(id.name) ~ "`" case Ident(name) => tree.typeOpt match { - case tp: NamedType if name != nme.WILDCARD => toTextPrefix(tp.prefix) ~ selectionString(tp) + case tp: NamedType if name != nme.WILDCARD => + val pre = if (tp.symbol is JavaStatic) tp.prefix.widen else tp.prefix + toTextPrefix(pre) ~ selectionString(tp) case _ => toText(name) } case tree @ Select(qual, name) => diff --git a/src/dotty/tools/dotc/transform/PrivateToStatic.scala b/src/dotty/tools/dotc/transform/PrivateToStatic.scala new file mode 100644 index 000000000000..17f17685568f --- /dev/null +++ b/src/dotty/tools/dotc/transform/PrivateToStatic.scala @@ -0,0 +1,90 @@ +package dotty.tools.dotc +package transform + +import core._ +import DenotTransformers.SymTransformer +import Contexts.Context +import Symbols._ +import Scopes._ +import Flags._ +import StdNames._ +import SymDenotations._ +import Types._ +import collection.mutable +import TreeTransforms._ +import Decorators._ +import ast.Trees._ +import TreeTransforms.TransformerInfo + +/** The preceding lambda lift and flatten phases move symbols to different scopes + * and rename them. This miniphase cleans up afterwards and makes sure that all + * class scopes contain the symbols defined in them. + */ +class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform => + import ast.tpd._ + override def phaseName = "privateToStatic" + override def relaxedTyping = true + + private val Immovable = Deferred | Accessor | JavaStatic + + def shouldBeStatic(sd: SymDenotation)(implicit ctx: Context) = + sd.current(ctx.withPhase(thisTransform)).asInstanceOf[SymDenotation] + .is(PrivateMethod, butNot = Immovable) && + (sd.owner.is(Trait) || sd.is(NotJavaPrivate)) + + override def transformSym(sd: SymDenotation)(implicit ctx: Context): SymDenotation = + if (shouldBeStatic(sd)) { + val mt @ MethodType(pnames, ptypes) = sd.info + sd.copySymDenotation( + initFlags = sd.flags | JavaStatic, + info = MethodType(nme.SELF :: pnames, sd.owner.thisType :: ptypes, mt.resultType)) + } + else sd + + val treeTransform = new Transform(NoSymbol) + + class Transform(thisParam: Symbol) extends TreeTransform { + def phase = thisTransform + override def treeTransformPhase = thisTransform.next + + override def prepareForDefDef(tree: DefDef)(implicit ctx: Context) = + if (shouldBeStatic(tree.symbol)) { + val selfParam = ctx.newSymbol(tree.symbol, nme.SELF, Param, tree.symbol.owner.thisType, coord = tree.pos) + new Transform(selfParam) + } + else this + + override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo) = + if (shouldBeStatic(tree.symbol)) { + val thisParamDef = ValDef(thisParam.asTerm) + val vparams :: Nil = tree.vparamss + cpy.DefDef(tree)( + mods = tree.mods | JavaStatic, + vparamss = (thisParamDef :: vparams) :: Nil) + } + else tree + + override def transformThis(tree: This)(implicit ctx: Context, info: TransformerInfo) = + if (shouldBeStatic(ctx.owner.enclosingMethod)) ref(thisParam).withPos(tree.pos) + else tree + + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) = + tree.fun match { + case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) => + println(i"mapping $tree to ${cpy.Ident(fun)(name)} (${qual :: tree.args}%, %)") + cpy.Apply(tree)(ref(fun.symbol).withPos(fun.pos), qual :: tree.args) + case _ => + tree + } + + override def transformClosure(tree: Closure)(implicit ctx: Context, info: TransformerInfo) = + tree.meth match { + case meth @ Select(qual, name) if shouldBeStatic(meth.symbol) => + cpy.Closure(tree)( + env = qual :: tree.env, + meth = ref(meth.symbol).withPos(meth.pos)) + case _ => + tree + } + } +} diff --git a/tests/pos/CoderTrait.scala b/tests/pos/CoderTrait.scala new file mode 100644 index 000000000000..1eba60097fae --- /dev/null +++ b/tests/pos/CoderTrait.scala @@ -0,0 +1,63 @@ +import collection.mutable.HashMap + +trait CoderTrait { + + val words: List[String] + + (2 -> "ABC", new ArrowAssoc('3') -> "DEF") + + private val mnemonics = Map( + '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", + '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ") + + + ('1', "1") match { + case (digit, str) => true + case _ => false + } + + /** Invert the mnemonics map to give a map from chars 'A' ... 'Z' to '2' ... '9' */ + private val charCode0: Map[Char, Char] = mnemonics withFilter { + case (digit, str) => true + case _ => false + } flatMap { x$1 => + x$1 match { + case (digit, str) => str map (ltr => ltr -> digit) + } + } + + private val charCode: Map[Char, Char] = + for ((digit, str) <- mnemonics; ltr <- str) yield ltr -> digit + + /** Maps a word to the digit string it can represent */ + private def wordCode(word: String): String = word map charCode + + /** A map from digit strings to the words that represent them */ + private val wordsForNum: Map[String, List[String]] = + words groupBy wordCode withDefaultValue Nil + + /** All ways to encode a number as a list of words */ + def encode(number: String): Set[List[String]] = + if (number.isEmpty) Set(Nil) + else { + for { + splitPoint <- 1 to number.length + word <- wordsForNum(number take splitPoint) + rest <- encode(number drop splitPoint) + } yield word :: rest + }.toSet + + /** Maps a number to a list of all word phrases that can represent it */ + def translate(number: String): Set[String] = encode(number) map (_ mkString " ") + +} + +object Coder { + def main(args : Array[String]) : Unit = { + val coder = new CoderTrait { + val words = List("Scala", "sobls", "Python", "Ruby", "C", "A", "rocks", "sucks", "works", "Racka") + } +// println(coder.wordsForNum) + println(coder.translate("7225276257")) + } +} diff --git a/tests/pos/privates.scala b/tests/pos/privates.scala new file mode 100644 index 000000000000..edaa10cb6b1a --- /dev/null +++ b/tests/pos/privates.scala @@ -0,0 +1,9 @@ +trait Test { + + private val x = 2 + + private def foo() = x * x + + private def bar() = foo() + +} diff --git a/tests/pos/traits.scala b/tests/pos/traits.scala new file mode 100644 index 000000000000..15310d5a4e60 --- /dev/null +++ b/tests/pos/traits.scala @@ -0,0 +1,25 @@ +trait B { + + val z: Int + +} + +trait T { + + var x = 2 + + private var xp = 2 + + val y = 3 + + private val yp = 3 + + val z = 4 + + x = 4 + + xp = 4 + +} + +class C extends T From 74ec1885c527decd8eb7f35a31b641571652969b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Nov 2014 18:45:44 +0100 Subject: [PATCH 7/8] Fixes to documentation. --- .../tools/dotc/transform/PrivateToStatic.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/dotty/tools/dotc/transform/PrivateToStatic.scala b/src/dotty/tools/dotc/transform/PrivateToStatic.scala index 17f17685568f..14fa45a6ff30 100644 --- a/src/dotty/tools/dotc/transform/PrivateToStatic.scala +++ b/src/dotty/tools/dotc/transform/PrivateToStatic.scala @@ -16,9 +16,12 @@ import Decorators._ import ast.Trees._ import TreeTransforms.TransformerInfo -/** The preceding lambda lift and flatten phases move symbols to different scopes - * and rename them. This miniphase cleans up afterwards and makes sure that all - * class scopes contain the symbols defined in them. +/** Makes private methods static, provided they not deferred, accessors, or static, + * by rewriting a method `m` in class `C` as follows: + * + * private def m(ps) = e + * + * --> private static def($this: C, ps) = [this -> $this] e */ class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform => import ast.tpd._ @@ -28,7 +31,7 @@ class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform => private val Immovable = Deferred | Accessor | JavaStatic def shouldBeStatic(sd: SymDenotation)(implicit ctx: Context) = - sd.current(ctx.withPhase(thisTransform)).asInstanceOf[SymDenotation] + sd.current(ctx.withPhase(thisTransform)).asSymDenotation .is(PrivateMethod, butNot = Immovable) && (sd.owner.is(Trait) || sd.is(NotJavaPrivate)) @@ -68,6 +71,10 @@ class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform => if (shouldBeStatic(ctx.owner.enclosingMethod)) ref(thisParam).withPos(tree.pos) else tree + /** Rwrites a call to a method `m` which is made static as folows: + * + * qual.m(args) --> m(qual, args) + */ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) = tree.fun match { case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) => From 3da54484efe76e578da17c447086f894869b9140 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Nov 2014 18:57:13 +0100 Subject: [PATCH 8/8] Making print statement a debuglog --- src/dotty/tools/dotc/transform/PrivateToStatic.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/PrivateToStatic.scala b/src/dotty/tools/dotc/transform/PrivateToStatic.scala index 14fa45a6ff30..5562fc6b2c05 100644 --- a/src/dotty/tools/dotc/transform/PrivateToStatic.scala +++ b/src/dotty/tools/dotc/transform/PrivateToStatic.scala @@ -78,7 +78,7 @@ class PrivateToStatic extends MiniPhase with SymTransformer { thisTransform => override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) = tree.fun match { case fun @ Select(qual, name) if shouldBeStatic(fun.symbol) => - println(i"mapping $tree to ${cpy.Ident(fun)(name)} (${qual :: tree.args}%, %)") + ctx.debuglog(i"mapping $tree to ${cpy.Ident(fun)(name)} (${qual :: tree.args}%, %)") cpy.Apply(tree)(ref(fun.symbol).withPos(fun.pos), qual :: tree.args) case _ => tree