@@ -6,6 +6,7 @@ import Contexts.Context
66import Symbols ._
77import Flags ._
88import Names ._
9+ import NameOps ._
910import Decorators ._
1011import TypeUtils ._
1112import Annotations .Annotation
@@ -23,9 +24,6 @@ abstract class AccessProxies {
2324 import ast .tpd ._
2425 import AccessProxies ._
2526
26- def getterName : ClassifiedNameKind
27- def setterName : ClassifiedNameKind
28-
2927 /** accessor -> accessed */
3028 private val accessedBy = newMutableSymbolMap[Symbol ]
3129
@@ -38,7 +36,7 @@ abstract class AccessProxies {
3836 polyDefDef(accessor.asTerm, tps => argss => {
3937 val accessRef = ref(TermRef (cls.thisType, accessed))
4038 val rhs =
41- if (accessor.name.is(setterName) &&
39+ if (accessor.name.isSetterName &&
4240 argss.nonEmpty && argss.head.nonEmpty) // defensive conditions
4341 accessRef.becomes(argss.head.head)
4442 else
@@ -49,34 +47,60 @@ abstract class AccessProxies {
4947 /** Add all needed accessors to the `body` of class `cls` */
5048 def addAccessorDefs (cls : Symbol , body : List [Tree ])(implicit ctx : Context ): List [Tree ] = {
5149 val accDefs = accessorDefs(cls)
50+ transforms.println(i " add accessors for $cls: $accDefs%, % " )
5251 if (accDefs.isEmpty) body else body ++ accDefs
5352 }
5453
5554 trait Insert {
5655 import ast .tpd ._
5756
57+ def accessorNameKind : ClassifiedNameKind
5858 def needsAccessor (sym : Symbol )(implicit ctx : Context ): Boolean
5959
6060 /** A fresh accessor symbol */
61- def newAccessorSymbol (owner : Symbol , name : TermName , info : Type , pos : Position )(implicit ctx : Context ): TermSymbol = {
61+ private def newAccessorSymbol (owner : Symbol , name : TermName , info : Type , pos : Position )(implicit ctx : Context ): TermSymbol = {
6262 val sym = ctx.newSymbol(owner, name, Synthetic | Method , info, coord = pos).entered
6363 if (sym.allOverriddenSymbols.exists(! _.is(Deferred ))) sym.setFlag(Override )
6464 sym
6565 }
6666
67+ /** An accessor symbol, create a fresh one unless one exists already */
68+ private def accessorSymbol (owner : Symbol , accessorName : TermName , accessorInfo : Type , accessed : Symbol )(implicit ctx : Context ) = {
69+ def refersToAccessed (sym : Symbol ) = accessedBy.get(sym) == Some (accessed)
70+ owner.info.decl(accessorName).suchThat(refersToAccessed).symbol.orElse {
71+ val acc = newAccessorSymbol(owner, accessorName, accessorInfo, accessed.pos)
72+ accessedBy(acc) = accessed
73+ acc
74+ }
75+ }
76+
77+ /** Rewire reference to refer to `accessor` symbol */
78+ private def rewire (reference : RefTree , accessor : Symbol )(implicit ctx : Context ): Tree = {
79+ reference match {
80+ case Select (qual, _) => qual.select(accessor)
81+ case Ident (name) => ref(accessor)
82+ }
83+ }.withPos(reference.pos)
84+
85+ /** Given a reference to a getter accessor, the corresponding setter reference */
86+ def useSetter (getterRef : RefTree )(implicit ctx : Context ): Tree = {
87+ val getter = getterRef.symbol
88+ val accessed = accessedBy(getter)
89+ val accessedName = accessed.name.asTermName
90+ val setterName = accessorNameKind(accessedName.setterName)
91+ val setterInfo = MethodType (getter.info.widenExpr :: Nil , defn.UnitType )
92+ val setter = accessorSymbol(getter.owner, setterName, setterInfo, accessed)
93+ rewire(getterRef, setter)
94+ }
95+
6796 /** Create an accessor unless one exists already, and replace the original
6897 * access with a reference to the accessor.
6998 *
7099 * @param reference The original reference to the non-public symbol
71100 * @param onLHS The reference is on the left-hand side of an assignment
72101 */
73- def useAccessor (reference : RefTree , onLHS : Boolean )(implicit ctx : Context ): Tree = {
74-
75- def nameKind = if (onLHS) setterName else getterName
102+ def useAccessor (reference : RefTree )(implicit ctx : Context ): Tree = {
76103 val accessed = reference.symbol.asTerm
77-
78- def refersToAccessed (sym : Symbol ) = accessedBy.get(sym) == Some (accessed)
79-
80104 var accessorClass = hostForAccessorOf(accessed : Symbol )
81105 if (! accessorClass.exists) {
82106 val curCls = ctx.owner.enclosingClass
@@ -85,27 +109,11 @@ abstract class AccessProxies {
85109 reference.pos)
86110 accessorClass = curCls
87111 }
88-
89- val accessorRawInfo =
90- if (onLHS) MethodType (accessed.info :: Nil , defn.UnitType )
91- else accessed.info.ensureMethodic
112+ val accessorName = accessorNameKind(accessed.name)
92113 val accessorInfo =
93- accessorRawInfo.asSeenFrom(accessorClass.thisType, accessed.owner)
94- val accessorName = nameKind(accessed.name)
95-
96- val accessorSymbol =
97- accessorClass.info.decl(accessorName).suchThat(refersToAccessed).symbol
98- .orElse {
99- val acc = newAccessorSymbol(accessorClass, accessorName, accessorInfo, accessed.pos)
100- accessedBy(acc) = accessed
101- acc
102- }
103-
104- { reference match {
105- case Select (qual, _) => qual.select(accessorSymbol)
106- case Ident (name) => ref(accessorSymbol)
107- }
108- }.withPos(reference.pos)
114+ accessed.info.ensureMethodic.asSeenFrom(accessorClass.thisType, accessed.owner)
115+ val accessor = accessorSymbol(accessorClass, accessorName, accessorInfo, accessed)
116+ rewire(reference, accessor)
109117 }
110118
111119 /** Replace tree with a reference to an accessor if needed */
@@ -115,15 +123,16 @@ abstract class AccessProxies {
115123 ctx.error(" Implementation restriction: cannot use private constructors in inline methods" , tree.pos)
116124 tree // TODO: create a proper accessor for the private constructor
117125 }
118- else useAccessor(tree, onLHS = false )
119- case Assign (lhs : RefTree , rhs) if needsAccessor(lhs.symbol) =>
120- cpy.Apply (tree)(useAccessor(lhs, onLHS = true ), List (rhs))
126+ else useAccessor(tree)
121127 case _ =>
122128 tree
123129 }
124130 }
125131}
126132object AccessProxies {
133+ /** Where an accessor for the `accessed` symbol should be placed.
134+ * This is the closest enclosing class that has `accessed` as a member.
135+ */
127136 def hostForAccessorOf (accessed : Symbol )(implicit ctx : Context ): Symbol =
128137 ctx.owner.ownersIterator.findSymbol(_.derivesFrom(accessed.owner))
129- }
138+ }
0 commit comments