diff options
author | Martin Odersky <odersky@gmail.com> | 2015-04-22 12:10:05 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2015-04-22 17:19:35 +0200 |
commit | 158c9632e9138a91a47ce13386bce0ab41db434b (patch) | |
tree | 1fdb4b470da02363650e03ca3fddd9578fc2b7a0 /src/dotty/tools/dotc/transform/ParamForwarding.scala | |
parent | ed160675ddfc4410d1dcaa55ecbd2dec7f842013 (diff) | |
download | dotty-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.scala | 71 |
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 |