diff options
author | Martin Odersky <odersky@gmail.com> | 2014-11-01 18:33:56 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-11-09 19:08:58 +0100 |
commit | 43075bb832c3b4fe080c24a20ecf8c4737d5cdd2 (patch) | |
tree | 680cc886c536c34b4c3718663386d1cb13be4924 | |
parent | 0119ffd3e285e43b63fb9c43c1c8b009174a1987 (diff) | |
download | dotty-43075bb832c3b4fe080c24a20ecf8c4737d5cdd2.tar.gz dotty-43075bb832c3b4fe080c24a20ecf8c4737d5cdd2.tar.bz2 dotty-43075bb832c3b4fe080c24a20ecf8c4737d5cdd2.zip |
Improved version of mixin.
Now also handles all supercalls. Seems to do the right thing on pos/traits.scala.
But does not pass most tests because the sym transformer forces too many things.
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Constructors.scala | 36 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/GettersSetters.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Mixin.scala | 84 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/SymUtils.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/TypeAssigner.scala | 5 | ||||
-rw-r--r-- | test/dotc/tests.scala | 2 | ||||
-rw-r--r-- | tests/pos/traits.scala | 4 |
9 files changed, 79 insertions, 71 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index f4690df08..62759ba09 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -50,8 +50,9 @@ class Compiler { new Splitter), List(new ElimByName, new InterceptedMethods, - new Literalize, - new GettersSetters), + new Literalize), + List(new Mixin), + List(new GettersSetters), List(new Erasure), List(new CapturedVars, new Constructors), diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 74ba79176..8c300c231 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -39,8 +39,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def This(cls: ClassSymbol)(implicit ctx: Context): This = untpd.This(cls.name).withType(cls.thisType) - def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super = - ta.assignType(untpd.Super(qual, mix), qual, inConstrCall) + def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super = + ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass) def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = ta.assignType(untpd.Apply(fn, args), fn, args) diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala index 7bde1ba4f..c966e2678 100644 --- a/src/dotty/tools/dotc/transform/Constructors.scala +++ b/src/dotty/tools/dotc/transform/Constructors.scala @@ -109,32 +109,6 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor } } - val superCalls = new mutable.ListBuffer[Tree] - - // If parent is a constructor call, pull out the call into a separate - // supercall constructor, which gets appended to `superCalls`, and keep - // only the type. - def normalizeParent(tree: Tree) = tree match { - case superApp @ Apply( - superSel @ Select( - superNew @ New(superType), - nme.CONSTRUCTOR), - superArgs) => - val toClass = !superType.symbol.is(Trait) - val mappedArgs = superArgs.map(intoConstr(_, inSuperCall = toClass)) - val receiver = - if (toClass) Super(This(cls), tpnme.EMPTY, inConstrCall = true) - else This(cls) - superCalls += - cpy.Apply(superApp)( - receiver.withPos(superNew.pos) - .select(superSel.symbol).withPos(superSel.pos), - mappedArgs) - superType - case tree: TypeTree => tree - } - val parentTypeTrees = tree.parents.map(normalizeParent) - // Collect all private parameter accessors and value definitions that need // to be retained. There are several reasons why a parameter accessor or // definition might need to be retained: @@ -172,7 +146,7 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor traverse(stat) } } - usage.collect(superCalls.toList ++ tree.body) + usage.collect(tree.body) def isRetained(acc: Symbol) = !mightBeDropped(acc) || usage.retained(acc) @@ -226,10 +200,14 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor decls = clsInfo.decls.filteredScope(!dropped.contains(_)))) } + val (superCalls, followConstrStats) = constrStats.toList match { + case (sc: Apply) :: rest if sc.symbol.isConstructor => (sc :: Nil, rest) + case stats => (Nil, stats) + } + cpy.Template(tree)( constr = cpy.DefDef(constr)( - rhs = Block(superCalls.toList ::: copyParams ::: constrStats.toList, unitLiteral)), - parents = parentTypeTrees, + rhs = Block(superCalls ::: copyParams ::: followConstrStats, unitLiteral)), body = clsStats.toList) } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/transform/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala index b0f6c15c8..b5933cc48 100644 --- a/src/dotty/tools/dotc/transform/GettersSetters.scala +++ b/src/dotty/tools/dotc/transform/GettersSetters.scala @@ -105,6 +105,7 @@ import Decorators._ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = if (tree.symbol.isSetter && !tree.symbol.is(Deferred | ParamAccessor)) { val Literal(Constant(())) = tree.rhs + assert(tree.symbol.field.exists, i"no field for ${tree.symbol.showLocated}") val initializer = Assign(ref(tree.symbol.field), ref(tree.vparamss.head.head.symbol)) assert(initializer.hasType) cpy.DefDef(tree)(rhs = initializer) diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index 515ac9c10..8116c723a 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -11,7 +11,10 @@ import SymDenotations._ import Types._ import Decorators._ import DenotTransformers._ +import StdNames._ import NameOps._ +import ast.Trees._ +import util.Positions._ import collection.mutable /** This phase performs the following transformations: @@ -155,22 +158,21 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => private def superAccessors(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList) - yield polyDefDef(implementation(cls, superAcc), forwarder(cls, rebindSuper(cls, superAcc))) + yield polyDefDef(implementation(cls, superAcc.asTerm), forwarder(cls, rebindSuper(cls, superAcc))) private def traitInits(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = for (field <- mixin.decls.filter(fld => fld.isField && !wasDeferred(fld)).toList) - yield DefDef(implementation(cls, field), ref(field.initializer).withPos(cls.pos)) + yield ValDef(implementation(cls, field.asTerm), superRef(cls, field.initializer, cls.pos)) private def setters(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList) - yield DefDef(implementation(cls, setter), unitLiteral.withPos(cls.pos)) + yield DefDef(implementation(cls, setter.asTerm), unitLiteral.withPos(cls.pos)) - private def implementation(cls: ClassSymbol, member: Symbol)(implicit ctx: Context): TermSymbol = - member.copy(owner = cls, flags = member.flags &~ Deferred) - .enteredAfter(thisTransform).asTerm - - private def constrCall(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context) = - mixinSuperRef(cls, mixin.primaryConstructor) + private def implementation(cls: ClassSymbol, member: TermSymbol)(implicit ctx: Context): TermSymbol = + member.copy( + owner = cls, + name = member.name.stripScala2LocalSuffix, + flags = member.flags &~ Deferred).enteredAfter(thisTransform).asTerm private def methodOverrides(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = { def isOverridden(meth: Symbol) = meth.overridingSymbol(cls).is(Method, butNot = Deferred) @@ -179,32 +181,66 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => !isOverridden(meth) && !meth.allOverriddenSymbols.forall(_ is Deferred) for (meth <- mixin.decls.toList if needsDisambiguation(meth)) - yield polyDefDef(implementation(cls, meth), forwarder(cls, meth)) + yield polyDefDef(implementation(cls, meth.asTerm), forwarder(cls, meth)) } private def wasDeferred(sym: Symbol)(implicit ctx: Context) = ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred } - private def mixinSuperRef(cls: ClassSymbol, target: Symbol)(implicit ctx: Context) = - Super(ref(cls), target.owner.name.asTypeName, inConstrCall = false).select(target) + private def superRef(cls: ClassSymbol, target: Symbol, pos: Position)(implicit ctx: Context) = { + val inTrait = target.owner is Trait + Super( + qual = This(cls), + mix = if (inTrait) target.owner.name.asTypeName else tpnme.EMPTY, + inConstrCall = target.isConstructor && !target.owner.is(Trait), + mixinClass = if (inTrait) target.owner else NoSymbol + ).select(target) + } private def forwarder(cls: ClassSymbol, target: Symbol)(implicit ctx: Context) = (targs: List[Type]) => (vrefss: List[List[Tree]]) => - mixinSuperRef(cls, target).appliedToTypes(targs).appliedToArgss(vrefss).withPos(cls.pos) + superRef(cls, target, cls.pos).appliedToTypes(targs).appliedToArgss(vrefss) override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo) = { val cls = tree.symbol.owner.asClass val stats = tree.body - cpy.Template(tree)(body = - if (cls is Trait) traitDefs(cls, stats) - else - cls.mixins.flatMap { mixin => - assert(mixin is Trait) - traitInits(cls, mixin) ::: - constrCall(cls, mixin) :: - setters(cls, mixin) - superAccessors(cls, mixin) ::: - methodOverrides(cls, mixin) - } ::: stats) + val superCls = cls.classInfo.parents.head.symbol + val mixins = cls.baseClasses.tail.takeWhile(_ ne superCls) + + // If parent is a constructor call, pull out the call into a separate + // supercall constructor, which gets added to `superCalls`, and keep + // only the type. + val superCalls = new mutable.HashMap[Symbol, Tree] + def normalizeParent(tree: Tree) = tree match { + case superApp @ Apply(superSel @ Select(New(superType), nme.CONSTRUCTOR), superArgs) => + val constr = superSel.symbol + superCalls(constr.owner) = superRef(cls, constr, superSel.pos).appliedToArgs(superArgs) + superType + case tree: TypeTree => tree + } + val parentTypeTrees = tree.parents.map(normalizeParent) + + def supCalls(baseCls: Symbol): List[Tree] = superCalls.remove(baseCls) match { + case Some(call) => call :: Nil + case None => + if (baseCls is Interface) Nil + else superRef(cls, baseCls.primaryConstructor, cls.pos).appliedToNone :: Nil + } + + cpy.Template(tree)( + parents = parentTypeTrees, + body = + if (cls is Trait) traitDefs(cls, stats) + else { + val mixInits = mixins.flatMap { mixin => + assert(mixin is Trait) + traitInits(cls, mixin) ::: + supCalls(mixin) ::: + setters(cls, mixin) ::: + superAccessors(cls, mixin) ::: + methodOverrides(cls, mixin) + } + supCalls(superCls) ::: mixInits ::: stats + }) } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/transform/SymUtils.scala b/src/dotty/tools/dotc/transform/SymUtils.scala index 06882f1c6..449affb9e 100644 --- a/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/src/dotty/tools/dotc/transform/SymUtils.scala @@ -69,15 +69,6 @@ class SymUtils(val self: Symbol) extends AnyVal { /** `fullName` where `$' is the separator character */ def flatName(implicit ctx: Context): Name = self.fullNameSeparated('$') - /** The traits mixed into this class in linearization order. - * These are all inherited traits that are not also inherited by the superclass - */ - def mixins(implicit ctx: Context): List[ClassSymbol] = { - val cls = self.asClass - val superCls = cls.classInfo.parents.head.symbol - cls.baseClasses.tail.takeWhile(_ ne superCls) - } - def initializer(implicit ctx: Context): TermSymbol = self.owner.info.decl(InitializerName(self.asTerm.name)).symbol.asTerm diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index bb488bdc5..ed10c7644 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -236,7 +236,7 @@ trait TypeAssigner { tree.withType(cls.thisType) } - def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean)(implicit ctx: Context) = { + def assignType(tree: untpd.Super, qual: Tree, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context) = { val mix = tree.mix val cls = qual.tpe.widen.typeSymbol @@ -249,7 +249,8 @@ trait TypeAssigner { errorType("ambiguous parent class qualifier", tree.pos) } val owntype = - if (!mix.isEmpty) findMixinSuper(cls.info) + if (mixinClass.exists) mixinClass.typeRef + else if (!mix.isEmpty) findMixinSuper(cls.info) else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent else { val ps = cls.info.parents diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index a52f79abd..2b0d7eb08 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,restoreScopes" + "-Ycheck:patternMatcher,mixin,gettersSetters,restoreScopes" ) val twice = List("#runs", "2", "-YnoDoubleBindings") diff --git a/tests/pos/traits.scala b/tests/pos/traits.scala index 15310d5a4..db611eeb5 100644 --- a/tests/pos/traits.scala +++ b/tests/pos/traits.scala @@ -1,10 +1,10 @@ -trait B { +trait B extends Object { val z: Int } -trait T { +trait T extends B { var x = 2 |