aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
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
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')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala2
-rw-r--r--src/dotty/tools/dotc/transform/ParamForwarding.scala (renamed from src/dotty/tools/dotc/transform/ForwardParamAccessors.scala)4
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala78
-rw-r--r--src/dotty/tools/dotc/transform/SuperAccessors.scala353
4 files changed, 254 insertions, 183 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index c67fb124a..536a04c22 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -38,10 +38,10 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
+ List(new PostTyper),
List(new InstChecks),
List(new FirstTransform,
new SyntheticMethods),
- List(new SuperAccessors),
List(new Pickler), // Pickler needs to come last in a group since it should not pickle trees generated later
List(new RefChecks,
new ElimRepeated,
diff --git a/src/dotty/tools/dotc/transform/ForwardParamAccessors.scala b/src/dotty/tools/dotc/transform/ParamForwarding.scala
index ff4dc2652..883a33ff2 100644
--- a/src/dotty/tools/dotc/transform/ForwardParamAccessors.scala
+++ b/src/dotty/tools/dotc/transform/ParamForwarding.scala
@@ -19,11 +19,9 @@ import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._
* Do the same also if there are intermediate inaccessible parameter accessor forwarders.
* The aim of this transformation is to avoid redundant parameter accessor fields.
*/
-trait ForwardParamAccessors extends DenotTransformer { thisTransformer: MacroTransform =>
+class ParamForwarding(thisTransformer: DenotTransformer) {
import ast.tpd._
- def currentClass(implicit ctx: Context) = ctx.owner.enclosingClass.asClass
-
def forwardParamAccessors(impl: Template)(implicit ctx: Context): Template = {
def fwd(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
val (superArgs, superParamNames) = impl.parents match {
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
new file mode 100644
index 000000000..4ad2cef01
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -0,0 +1,78 @@
+package dotty.tools.dotc
+package transform
+
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import dotty.tools.dotc.ast.{Trees, tpd}
+import scala.collection.{ mutable, immutable }
+import ValueClasses._
+import scala.annotation.tailrec
+import core._
+import typer.InstChecks
+import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
+import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
+import util.Positions._
+import Decorators._
+import Symbols._, TypeUtils._
+
+/** A macro transform that runs immediately after typer and that performs the following functions:
+ *
+ * (1) Add super accessors and protected accessors (@see SuperAccessors)
+ *
+ * (2) Convert parameter fields that have the same name as a corresponding
+ * public parameter field in a superclass to a forwarder to the superclass
+ * field (corresponding = super class field is initialized with subclass field)
+ * (@see ForwardParamAccessors)
+ *
+ * The reason for making this a macro transform is that some functions (in particular
+ * super and protected accessors and instantiation checks) are naturally top-down and
+ * don't lend themselves to the bottom-up approach of a mini phase. The other two functions
+ * (forwarding param accessors and synthetic methods) only apply to templates and fit
+ * mini-phase or subfunction of a macro phase equally well. But taken by themselves
+ * they do not warrant their own group of miniphases before pickling.
+ */
+class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTransformer =>
+
+ import tpd._
+
+ /** the following two members override abstract members in Transform */
+ override def phaseName: String = "posttyper"
+
+ override def transformPhase(implicit ctx: Context) = thisTransformer.next
+
+ protected def newTransformer(implicit ctx: Context): Transformer =
+ new PostTyperTransformer
+
+ val superAcc = new SuperAccessors(thisTransformer)
+ val paramFwd = new ParamForwarding(thisTransformer)
+// val instChecks = new InstChecks
+
+ class PostTyperTransformer extends Transformer {
+
+ override def transform(tree: Tree)(implicit ctx: Context): Tree =
+ try tree match {
+ case impl: Template =>
+ def trans(impl: Template) =
+ cpy.Template(impl)(body = transformStats(impl.body, impl.symbol))
+ paramFwd.forwardParamAccessors(superAcc.wrapTemplate(impl)(trans))
+ case tree @ TypeApply(sel: Select, args) =>
+ val sel1 = superAcc.transformSelect(super.transform(sel), args)
+ if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree)(sel1, args)
+ case sel: Select =>
+ superAcc.transformSelect(super.transform(sel), Nil)
+ case tree: DefDef =>
+ superAcc.wrapDefDef(tree)(cpy.DefDef(tree)(rhs = transform(tree.rhs)))
+ case tree: Assign =>
+ superAcc.transformAssign(super.transform(tree))
+// case tree: Apply if tree.symbol.isConstructor =>
+// instChecks.checkInstantiable(tree)
+// super.transform(tree)
+ case _ =>
+ super.transform(tree)
+ }
+ catch {
+ case ex : AssertionError =>
+ println(i"error while transforming $tree")
+ throw ex
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala
index ffad534b4..a0069878d 100644
--- a/src/dotty/tools/dotc/transform/SuperAccessors.scala
+++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala
@@ -5,7 +5,6 @@ import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform
import dotty.tools.dotc.ast.{Trees, tpd}
import scala.collection.{ mutable, immutable }
import ValueClasses._
-import mutable.ListBuffer
import scala.annotation.tailrec
import core._
import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
@@ -14,23 +13,14 @@ import util.Positions._
import Decorators._
import Symbols._, TypeUtils._
-/** This phase performs the following functions, each of which could be split out in a
- * mini-phase:
+/** This class performs the following functions:
*
* (1) Adds super accessors for all super calls that either
* appear in a trait or have as a target a member of some outer class.
*
- * (2) Converts parameter fields that have the same name as a corresponding
- * public parameter field in a superclass to a forwarder to the superclass
- * field (corresponding = super class field is initialized with subclass field)
- *
- * (3) Adds protected accessors if the access to the protected member happens
+ * (2) Adds protected accessors if the access to the protected member happens
* in a class which is not a subclass of the member's owner.
*
- * (4) Finally, the phase used to mangle the names of class-members which are
- * private up to an enclosing non-package class, in order to avoid overriding conflicts.
- * This is currently disabled, and class-qualified private is deprecated.
- *
* It also checks that:
*
* (1) Symbols accessed from super are not abstract, or are overridden by
@@ -43,24 +33,11 @@ import Symbols._, TypeUtils._
* (3) Super calls do not go to some synthetic members of Any (see isDisallowed)
*
* (4) Super calls do not go to synthetic field accessors
- *
- * TODO: Rename phase to "Accessors" because it handles more than just super accessors
*/
-class SuperAccessors extends MacroTransform
- with IdentityDenotTransformer
- with ForwardParamAccessors { thisTransformer =>
+class SuperAccessors(thisTransformer: DenotTransformer) {
import tpd._
- /** the following two members override abstract members in Transform */
- override def phaseName: String = "superaccessors"
-
- override def transformPhase(implicit ctx: Context) = thisTransformer.next
-
- protected def newTransformer(implicit ctx: Context): Transformer =
- new SuperAccTransformer
-
- class SuperAccTransformer extends Transformer {
/** Some parts of trees will get a new owner in subsequent phases.
* These are value class methods, which will become extension methods.
@@ -85,14 +62,16 @@ class SuperAccessors extends MacroTransform
private def validCurrentClass(implicit ctx: Context): Boolean =
ctx.owner.enclosingClass != invalidEnclClass
+
+ /** List buffers for new accessor definitions, indexed by class */
+ private val accDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]()
- private val accDefs = mutable.Map[Symbol, ListBuffer[Tree]]()
-
- private def ensureAccessor(sel: Select)(implicit ctx: Context) = {
+ /** A super accessor call corresponding to `sel` */
+ private def superAccessorCall(sel: Select)(implicit ctx: Context) = {
val Select(qual, name) = sel
- val sym = sel.symbol
- val clazz = qual.symbol.asClass
- val supername = name.superName
+ val sym = sel.symbol
+ val clazz = qual.symbol.asClass
+ val supername = name.superName
val superAcc = clazz.info.decl(supername).suchThat(_.signature == sym.signature).symbol orElse {
ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz")
@@ -110,13 +89,20 @@ class SuperAccessors extends MacroTransform
This(clazz).select(superAcc).withPos(sel.pos)
}
- private def transformSuperSelect(sel: Select)(implicit ctx: Context): Tree = {
+ /** Check selection `super.f` for conforming to rules. If necessary,
+ * replace by a super accessor call.
+ */
+ private def transformSuperSelect(sel: Select)(implicit ctx: Context): Tree = {
val Select(sup @ Super(_, mix), name) = sel
val sym = sel.symbol
assert(sup.symbol.exists, s"missing symbol in $sel: ${sup.tpe}")
val clazz = sup.symbol.asClass
- if (sym is Deferred) {
+ if ((sym.isTerm) && !(sym is Method) || (sym is Accessor))
+ ctx.error(s"super may be not be used on ${sym.underlyingSymbol}", sel.pos)
+ else if (isDisallowed(sym))
+ ctx.error(s"super not allowed here: use this.${sel.name.decode} instead", sel.pos)
+ else if (sym is Deferred) {
val member = sym.overridingSymbol(clazz)
if (mix != tpnme.EMPTY ||
!member.exists ||
@@ -137,12 +123,13 @@ class SuperAccessors extends MacroTransform
}
if (name.isTermName && mix == tpnme.EMPTY &&
((clazz is Trait) || clazz != ctx.owner.enclosingClass || !validCurrentClass))
- ensureAccessor(sel)(ctx.withPhase(thisTransformer.next))
+ superAccessorCall(sel)(ctx.withPhase(thisTransformer.next))
else sel
}
- // Disallow some super.XX calls targeting Any methods which would
- // otherwise lead to either a compiler crash or runtime failure.
+ /** Disallow some super.XX calls targeting Any methods which would
+ * otherwise lead to either a compiler crash or runtime failure.
+ */
private def isDisallowed(sym: Symbol)(implicit ctx: Context) = {
val d = defn
import d._
@@ -153,158 +140,41 @@ class SuperAccessors extends MacroTransform
(sym eq Any_##)
}
- override def transform(tree: Tree)(implicit ctx: Context): Tree = {
- val sym = tree.symbol
-
- def mayNeedProtectedAccessor(sel: Select, targs: List[Tree], goToSuper: Boolean) =
- if (sym.exists && needsProtectedAccessor(sym, tree.pos)) {
- ctx.debuglog("Adding protected accessor for " + tree)
- transform(makeAccessor(sel, targs))
- }
- else if (goToSuper) super.transform(tree)(ctx.withPhase(thisTransformer.next))
- else tree
-
- try tree match {
- case impl: Template =>
-
- def transformTemplate = {
- val ownStats = new ListBuffer[Tree]
- accDefs(currentClass) = ownStats
- // write super accessors after parameters and type aliases (so
- // that order is stable under pickling/unpickling)
- val (params, rest) = impl.body span {
- case td: TypeDef => !td.isClassDef
- case vd: ValOrDefDef => vd.symbol is ParamAccessor
- case _ => false
- }
- ownStats ++= params
- val rest1 = transformStats(rest, tree.symbol)
- accDefs -= currentClass
- ownStats ++= rest1
- cpy.Template(impl)(body = ownStats.toList)
- }
- forwardParamAccessors(transformTemplate)
-
- case TypeApply(sel @ Select(This(_), name), args) =>
- mayNeedProtectedAccessor(sel, args, goToSuper = false)
-
- case sel @ Select(qual, name) =>
- def transformSelect = {
-
- qual match {
- case This(_) =>
- // warn if they are selecting a private[this] member which
- // also exists in a superclass, because they may be surprised
- // to find out that a constructor parameter will shadow a
- // field. See SI-4762.
- /* to be added
- if (settings.lint) {
- if (sym.isPrivateLocal && sym.paramss.isEmpty) {
- qual.symbol.ancestors foreach { parent =>
- parent.info.decls filterNot (x => x.isPrivate || x.isLocalToThis) foreach { m2 =>
- if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) {
- unit.warning(sel.pos,
- sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name
- + " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within "
- + sym.owner + " - you may want to give them distinct names.")
- }
- }
- }
- }
- }
- */
-
- /*
- * A trait which extends a class and accesses a protected member
- * of that class cannot implement the necessary accessor method
- * because its implementation is in an implementation class (e.g.
- * Foo$class) which inherits nothing, and jvm access restrictions
- * require the call site to be in an actual subclass. So non-trait
- * classes inspect their ancestors for any such situations and
- * generate the accessors. See SI-2296.
- */
- // FIXME - this should be unified with needsProtectedAccessor, but some
- // subtlety which presently eludes me is foiling my attempts.
- val shouldEnsureAccessor = (
- (currentClass is Trait)
- && (sym is Protected)
- && sym.enclosingClass != currentClass
- && !(sym.owner is PackageClass) // SI-7091 no accessor needed package owned (ie, top level) symbols
- && !(sym.owner is Trait)
- && sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass
- && qual.symbol.info.member(sym.name).exists
- && !needsProtectedAccessor(sym, tree.pos))
- if (shouldEnsureAccessor) {
- ctx.log("Ensuring accessor for call to protected " + sym.showLocated + " from " + currentClass)
- ensureAccessor(sel)
- } else
- mayNeedProtectedAccessor(sel, Nil, goToSuper = false)
-
- case Super(_, mix) =>
- if ((sym.isTerm) && !(sym is Method) || (sym is Accessor)) {
- ctx.error(s"super may be not be used on ${sym.underlyingSymbol}", tree.pos)
- } else if (isDisallowed(sym)) {
- ctx.error(s"super not allowed here: use this.${name.decode} instead", tree.pos)
- }
- transformSuperSelect(sel)
-
- case _ =>
- mayNeedProtectedAccessor(sel, Nil, goToSuper = true)
- }
- }
- transformSelect
-
- case tree: DefDef =>
- cpy.DefDef(tree)(
- rhs = if (isMethodWithExtension(sym)) withInvalidCurrentClass(transform(tree.rhs)) else transform(tree.rhs))
-
- case TypeApply(sel @ Select(qual, name), args) =>
- mayNeedProtectedAccessor(sel, args, goToSuper = true)
-
- case Assign(lhs @ Select(qual, name), rhs) =>
- def transformAssign = {
- if ((lhs.symbol is Mutable) &&
- (lhs.symbol is JavaDefined) &&
- needsProtectedAccessor(lhs.symbol, tree.pos)) {
- ctx.debuglog("Adding protected setter for " + tree)
- val setter = makeSetter(lhs)
- ctx.debuglog("Replaced " + tree + " with " + setter)
- transform(Apply(setter, qual :: rhs :: Nil))
- } else
- super.transform(tree)
- }
- transformAssign
-
- case _ =>
- super.transform(tree)
- }
- catch {
- case ex : AssertionError =>
- if (sym != null && sym != NoSymbol)
- Console.println("TRANSFORM: " + tree.symbol.sourceFile)
-
- Console.println("TREE: " + tree)
- throw ex
- }
+ /** Replace `sel` (or `sel[targs]` if `targs` is nonempty) with a protected accessor
+ * call, if necessary.
+ */
+ private def ensureProtectedAccessOK(sel: Select, targs: List[Tree])(implicit ctx: Context) = {
+ val sym = sel.symbol
+ if (sym.exists && needsProtectedAccessor(sym, sel.pos)) {
+ ctx.debuglog("Adding protected accessor for " + sel)
+ protectedAccessorCall(sel, targs)
+ } else sel
}
/** Add a protected accessor, if needed, and return a tree that calls
* the accessor and returns the same member. The result is already
* typed.
- * TODO why is targs needed? It looks like we can do without.
*/
- private def makeAccessor(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
- val Select(qual, _) = tree
- val sym = tree.symbol.asTerm
+ private def protectedAccessorCall(sel: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
+ val Select(qual, _) = sel
+ val sym = sel.symbol.asTerm
val clazz = hostForAccessorOf(sym, currentClass)
assert(clazz.exists, sym)
ctx.debuglog("Decided for host class: " + clazz)
- val accName = sym.name.protectedAccessorName
+ val accName = sym.name.protectedAccessorName
+
+ def isThisType(tpe: Type): Boolean = tpe match {
+ case tpe: ThisType => !tpe.cls.is(PackageClass)
+ case tpe: TypeProxy => isThisType(tpe.underlying)
+ case _ => false
+ }
// if the result type depends on the this type of an enclosing class, the accessor
// has to take an object of exactly this type, otherwise it's more general
- val receiverType = if (isThisType(sym.info.finalResultType)) clazz.thisType else clazz.classInfo.selfType
+ val receiverType =
+ if (isThisType(sym.info.finalResultType)) clazz.thisType
+ else clazz.classInfo.selfType
val accType = {
def accTypeOf(tpe: Type): Type = tpe match {
case tpe: PolyType =>
@@ -316,6 +186,57 @@ class SuperAccessors extends MacroTransform
}
val protectedAccessor = clazz.info.decl(accName).suchThat(_.signature == accType.signature).symbol orElse {
val newAcc = ctx.newSymbol(
+ clazz, accName, Artifact, accType, coord = sel.pos).enteredAfter(thisTransformer)
+ val code = polyDefDef(newAcc, trefs => vrefss => {
+ val (receiver :: _) :: tail = vrefss
+ val base = receiver.select(sym).appliedToTypes(trefs)
+ (base /: vrefss)(Apply(_, _))
+ })
+ ctx.debuglog("created protected accessor: " + code)
+ accDefs(clazz) += code
+ newAcc
+ }
+ val res = This(clazz)
+ .select(protectedAccessor)
+ .appliedToTypeTrees(targs)
+ .appliedTo(qual)
+ .withPos(sel.pos)
+ ctx.debuglog(s"Replaced $sel with $res")
+ res
+ }
+
+ def isProtectedAccessor(tree: Tree)(implicit ctx: Context): Boolean = tree match {
+ case Apply(TypeApply(Select(_, name), _), qual :: Nil) => name.isProtectedAccessorName
+ case _ => false
+ }
+
+ /** Add a protected accessor, if needed, and return a tree that calls
+ * the accessor and returns the same member. The result is already
+ * typed.
+ */
+ private def protectedAccessor(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
+ val Select(qual, _) = tree
+ val sym = tree.symbol.asTerm
+ val clazz = hostForAccessorOf(sym, currentClass)
+ assert(clazz.exists, sym)
+ ctx.debuglog("Decided for host class: " + clazz)
+
+ val accName = sym.name.protectedAccessorName
+
+ // if the result type depends on the this type of an enclosing class, the accessor
+ // has to take an object of exactly this type, otherwise it's more general
+ val receiverType =
+ if (isThisType(sym.info.finalResultType)) clazz.thisType
+ else clazz.classInfo.selfType
+ def accTypeOf(tpe: Type): Type = tpe match {
+ case tpe: PolyType =>
+ tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
+ case _ =>
+ MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0)))
+ }
+ val accType = accTypeOf(sym.info)
+ val protectedAccessor = clazz.info.decl(accName).suchThat(_.signature == accType.signature).symbol orElse {
+ val newAcc = ctx.newSymbol(
clazz, accName, Artifact, accType, coord = tree.pos).enteredAfter(thisTransformer)
val code = polyDefDef(newAcc, trefs => vrefss => {
val (receiver :: _) :: tail = vrefss
@@ -338,7 +259,7 @@ class SuperAccessors extends MacroTransform
/** Add an accessor for field, if needed, and return a selection tree for it .
* The result is not typed.
*/
- private def makeSetter(tree: Select)(implicit ctx: Context): Tree = {
+ private def protectedSetter(tree: Select)(implicit ctx: Context): Tree = {
val field = tree.symbol.asTerm
val clazz = hostForAccessorOf(field, currentClass)
assert(clazz.exists, field)
@@ -422,11 +343,85 @@ class SuperAccessors extends MacroTransform
else
referencingClass
- /** Is 'tpe' the type of a member of an enclosing class? */
+ /** Is 'tpe' a ThisType, or a type proxy with a ThisType as transitively underlying type? */
private def isThisType(tpe: Type)(implicit ctx: Context): Boolean = tpe match {
case tpe: ThisType => !tpe.cls.is(PackageClass)
case tpe: TypeProxy => isThisType(tpe.underlying)
case _ => false
}
- }
+
+ /** Transform select node, adding super and protected accessors as needed */
+ def transformSelect(tree: Tree, targs: List[Tree])(implicit ctx: Context) = {
+ val sel @ Select(qual, name) = tree
+ val sym = sel.symbol
+ qual match {
+ case _: This =>
+ /*
+ * A trait which extends a class and accesses a protected member
+ * of that class cannot implement the necessary accessor method
+ * because its implementation is in an implementation class (e.g.
+ * Foo$class) which inherits nothing, and jvm access restrictions
+ * require the call site to be in an actual subclass. So non-trait
+ * classes inspect their ancestors for any such situations and
+ * generate the accessors. See SI-2296.
+ */
+ // FIXME (from scalac's SuperAccessors)
+ // - this should be unified with needsProtectedAccessor, but some
+ // subtlety which presently eludes me is foiling my attempts.
+ val shouldEnsureAccessor = (
+ (currentClass is Trait)
+ && (sym is Protected)
+ && sym.enclosingClass != currentClass
+ && !(sym.owner is PackageClass) // SI-7091 no accessor needed package owned (ie, top level) symbols
+ && !(sym.owner is Trait)
+ && sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass
+ && qual.symbol.info.member(sym.name).exists
+ && !needsProtectedAccessor(sym, sel.pos))
+ if (shouldEnsureAccessor) {
+ ctx.log("Ensuring accessor for call to protected " + sym.showLocated + " from " + currentClass)
+ superAccessorCall(sel)
+ } else
+ ensureProtectedAccessOK(sel, targs)
+
+ case Super(_, mix) =>
+ transformSuperSelect(sel)
+
+ case _ =>
+ ensureProtectedAccessOK(sel, targs)
+ }
+ }
+
+ /** Transform assignment, adding a protected setter if needed */
+ def transformAssign(tree: Tree)(implicit ctx: Context) = {
+ val Assign(lhs @ Select(qual, name), rhs) = tree
+ if ((lhs.symbol is Mutable) &&
+ (lhs.symbol is JavaDefined) &&
+ needsProtectedAccessor(lhs.symbol, tree.pos)) {
+ ctx.debuglog("Adding protected setter for " + tree)
+ val setter = protectedSetter(lhs)
+ ctx.debuglog("Replaced " + tree + " with " + setter)
+ setter.appliedTo(qual, rhs)
+ }
+ else tree
+ }
+
+ /** Wrap template to template transform `op` with needed initialization and finalization */
+ def wrapTemplate(tree: Template)(op: Template => Template)(implicit ctx: Context) = {
+ accDefs(currentClass) = new mutable.ListBuffer[Tree]
+ val impl = op(tree)
+ val accessors = accDefs.remove(currentClass).get
+ if (accessors.isEmpty) impl
+ else {
+ val (params, rest) = impl.body span {
+ case td: TypeDef => !td.isClassDef
+ case vd: ValOrDefDef => vd.symbol.flags is ParamAccessor
+ case _ => false
+ }
+ cpy.Template(impl)(body = params ++ accessors ++ rest)
+ }
+ }
+
+ /** Wrap `DefDef` producing operation `op`, potentially setting `invalidClass` info */
+ def wrapDefDef(ddef: DefDef)(op: => DefDef)(implicit ctx: Context) =
+ if (isMethodWithExtension(ddef.symbol)) withInvalidCurrentClass(op) else op
}