aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/ParamForwarding.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-04-22 12:10:05 +0200
committerMartin Odersky <odersky@gmail.com>2015-04-22 17:19:35 +0200
commit158c9632e9138a91a47ce13386bce0ab41db434b (patch)
tree1fdb4b470da02363650e03ca3fddd9578fc2b7a0 /src/dotty/tools/dotc/transform/ParamForwarding.scala
parented160675ddfc4410d1dcaa55ecbd2dec7f842013 (diff)
downloaddotty-158c9632e9138a91a47ce13386bce0ab41db434b.tar.gz
dotty-158c9632e9138a91a47ce13386bce0ab41db434b.tar.bz2
dotty-158c9632e9138a91a47ce13386bce0ab41db434b.zip
Super accessor refactoring
New phase: PostTransform, runs after Typer. SuperAccessors and ParamForwarders (renamed from ForwardParamAccessors) are helper objects of post transform. Next: Add instChecks as well.
Diffstat (limited to 'src/dotty/tools/dotc/transform/ParamForwarding.scala')
-rw-r--r--src/dotty/tools/dotc/transform/ParamForwarding.scala71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/transform/ParamForwarding.scala b/src/dotty/tools/dotc/transform/ParamForwarding.scala
new file mode 100644
index 000000000..883a33ff2
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ParamForwarding.scala
@@ -0,0 +1,71 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import ast.Trees._
+import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._, StdNames._
+
+/** For all parameter accessors
+ *
+ * val x: T = ...
+ *
+ * if
+ * (1) x is forwarded in the supercall to a parameter that's also named `x`
+ * (2) the superclass parameter accessor for `x` is accessible from the current class to
+ * change the accessor to
+ *
+ * def x: T = super.x.asInstanceOf[T]
+ *
+ * Do the same also if there are intermediate inaccessible parameter accessor forwarders.
+ * The aim of this transformation is to avoid redundant parameter accessor fields.
+ */
+class ParamForwarding(thisTransformer: DenotTransformer) {
+ import ast.tpd._
+
+ def forwardParamAccessors(impl: Template)(implicit ctx: Context): Template = {
+ def fwd(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
+ val (superArgs, superParamNames) = impl.parents match {
+ case superCall @ Apply(fn, args) :: _ =>
+ fn.tpe.widen match {
+ case MethodType(paramNames, _) => (args, paramNames)
+ case _ => (Nil, Nil)
+ }
+ case _ => (Nil, Nil)
+ }
+ def inheritedAccessor(sym: Symbol): Symbol = {
+ val candidate = sym.owner.asClass.superClass
+ .info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = Mutable)).symbol
+ if (candidate.isAccessibleFrom(currentClass.thisType, superAccess = true)) candidate
+ else if (candidate is Method) inheritedAccessor(candidate)
+ else NoSymbol
+ }
+ def forwardParamAccessor(stat: Tree): Tree = {
+ stat match {
+ case stat: ValDef =>
+ val sym = stat.symbol.asTerm
+ if (sym is (PrivateLocalParamAccessor, butNot = Mutable)) {
+ val idx = superArgs.indexWhere(_.symbol == sym)
+ if (idx >= 0 && superParamNames(idx) == stat.name) { // supercall to like-named parameter
+ val alias = inheritedAccessor(sym)
+ if (alias.exists) {
+ def forwarder(implicit ctx: Context) = {
+ sym.copySymDenotation(initFlags = sym.flags | Method, info = sym.info.ensureMethodic)
+ .installAfter(thisTransformer)
+ val superAcc =
+ Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
+ DefDef(sym, superAcc.ensureConforms(sym.info.widen))
+ }
+ return forwarder(ctx.withPhase(thisTransformer.next))
+ }
+ }
+ }
+ case _ =>
+ }
+ stat
+ }
+ stats map forwardParamAccessor
+ }
+
+ cpy.Template(impl)(body = fwd(impl.body)(ctx.withPhase(thisTransformer)))
+ }
+} \ No newline at end of file