Skip to content

Commit 228b232

Browse files
authored
Merge pull request #4603 from dotty-staging/change-accessors
More changes to protected accessors
2 parents 868d199 + 266a696 commit 228b232

File tree

7 files changed

+93
-80
lines changed

7 files changed

+93
-80
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -836,19 +836,23 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
836836
tree.select(defn.Boolean_||).appliedTo(that)
837837

838838
/** The translation of `tree = rhs`.
839-
* This is either the tree as an assignment, to a setter call.
839+
* This is either the tree as an assignment, or a setter call.
840840
*/
841-
def becomes(rhs: Tree)(implicit ctx: Context): Tree =
842-
if (tree.symbol is Method) {
843-
val setter = tree.symbol.setter
844-
assert(setter.exists, tree.symbol.showLocated)
841+
def becomes(rhs: Tree)(implicit ctx: Context): Tree = {
842+
val sym = tree.symbol
843+
if (sym is Method) {
844+
val setter = sym.setter.orElse {
845+
assert(sym.name.isSetterName && sym.info.firstParamTypes.nonEmpty)
846+
sym
847+
}
845848
val qual = tree match {
846849
case id: Ident => desugarIdentPrefix(id)
847850
case Select(qual, _) => qual
848851
}
849852
qual.select(setter).appliedTo(rhs)
850853
}
851854
else Assign(tree, rhs)
855+
}
852856

853857
/** A synthetic select with that will be turned into an outer path by ExplicitOuter.
854858
* @param levels How many outer levels to select

compiler/src/dotty/tools/dotc/core/NameKinds.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,8 @@ object NameKinds {
354354

355355
val SuperAccessorName = new PrefixNameKind(SUPERACCESSOR, "super$")
356356
val InitializerName = new PrefixNameKind(INITIALIZER, "initial$")
357-
val ProtectedGetterName = new PrefixNameKind(PROTECTEDGETTER, "protected_get$")
358-
val ProtectedSetterName = new PrefixNameKind(PROTECTEDSETTER, "protected_set$")
359-
val InlineGetterName = new PrefixNameKind(INLINEGETTER, "inline_get$")
360-
val InlineSetterName = new PrefixNameKind(INLINESETTER, "inline_set$")
357+
val ProtectedAccessorName = new PrefixNameKind(PROTECTEDACCESSOR, "protected$")
358+
val InlineAccessorName = new PrefixNameKind(INLINEACCESSOR, "inline$")
361359

362360
val AvoidClashName = new SuffixNameKind(AVOIDCLASH, "$_avoid_name_clash_$")
363361
val DirectMethodName = new SuffixNameKind(DIRECT, "$direct") { override def definesNewName = true }

compiler/src/dotty/tools/dotc/core/NameTags.scala

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ object NameTags extends TastyFormat.NameTags {
1515
// outer accessor that will be filled in by ExplicitOuter.
1616
// <num> indicates the number of hops needed to select the outer field.
1717

18-
final val PROTECTEDGETTER = 24 // The name of a protected getter `protected_get$<name>` created by ProtectedAccessors.
19-
20-
final val PROTECTEDSETTER = 25 // The name of a protected setter `protected_set$<name>` created by ProtectedAccessors.
18+
final val PROTECTEDACCESSOR = 24 // The name of a protected accesor `protected$<name>` created by ProtectedAccessors.
2119

2220
final val INITIALIZER = 26 // A mixin initializer method
2321

@@ -51,10 +49,8 @@ object NameTags extends TastyFormat.NameTags {
5149
case OUTERSELECT => "OUTERSELECT"
5250

5351
case SUPERACCESSOR => "SUPERACCESSOR"
54-
case INLINEGETTER => "INLINEGETTER"
55-
case INLINESETTER => "INLINESETTER"
56-
case PROTECTEDGETTER => "PROTECTEDGETTER"
57-
case PROTECTEDSETTER => "PROTECTEDSETTER"
52+
case INLINEACCESSOR => "INLINEACCESSOR"
53+
case PROTECTEDACCESSOR => "PROTECTEDACCESSOR"
5854
case INITIALIZER => "INITIALIZER"
5955
case AVOIDCLASH => "AVOIDCLASH"
6056
case DIRECT => "DIRECT"

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ Macro-format:
3939
VARIANT Length underlying_NameRef variance_Nat // 0: Contravariant, 1: Covariant
4040
4141
SUPERACCESSOR Length underlying_NameRef
42-
INLINEGETTER Length underlying_NameRef
43-
INLINESETTER Length underlying_NameRef
42+
INLINEACCESSOR Length underlying_NameRef
4443
OBJECTCLASS Length underlying_NameRef
4544
4645
SIGNED Length original_NameRef resultSig_NameRef paramSig_NameRef*
@@ -252,9 +251,7 @@ object TastyFormat {
252251

253252
final val SUPERACCESSOR = 20 // The name of a super accessor `super$name` created by SuperAccesors.
254253

255-
final val INLINEGETTER = 21 // The name of an inline getter `inline_get$name`
256-
257-
final val INLINESETTER = 22 // The name of an inline setter `inline_set$name`
254+
final val INLINEACCESSOR = 21 // The name of an inline accessor `inline$name`
258255

259256
final val OBJECTCLASS = 23 // The name of an object class (or: module class) `<name>$`.
260257

compiler/src/dotty/tools/dotc/transform/AccessProxies.scala

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Contexts.Context
66
import Symbols._
77
import Flags._
88
import Names._
9+
import NameOps._
910
import Decorators._
1011
import TypeUtils._
1112
import 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
}
126132
object 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+
}

compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import core.Flags._
88
import core.Decorators._
99
import MegaPhase.MiniPhase
1010
import ast.Trees._
11-
import util.Property
1211

1312
/** Add accessors for all protected accesses. An accessor is needed if
1413
* according to the rules of the JVM a protected class member is not accesissible
@@ -18,8 +17,6 @@ import util.Property
1817
object ProtectedAccessors {
1918
val name = "protectedAccessors"
2019

21-
private val LHS = new Property.StickyKey[Unit]
22-
2320
/** Is the current context's owner inside the access boundary established by `sym`? */
2421
def insideBoundaryOf(sym: Symbol)(implicit ctx: Context): Boolean = {
2522
if (sym.is(JavaDefined)) {
@@ -56,32 +53,30 @@ class ProtectedAccessors extends MiniPhase {
5653
override def phaseName = ProtectedAccessors.name
5754

5855
object Accessors extends AccessProxies {
59-
def getterName = ProtectedGetterName
60-
def setterName = ProtectedSetterName
61-
6256
val insert = new Insert {
57+
def accessorNameKind = ProtectedAccessorName
6358
def needsAccessor(sym: Symbol)(implicit ctx: Context) = ProtectedAccessors.needsAccessor(sym)
6459
}
6560
}
6661

67-
override def prepareForAssign(tree: Assign)(implicit ctx: Context) = {
68-
tree.lhs match {
69-
case lhs: RefTree if needsAccessor(lhs.symbol) => lhs.putAttachment(LHS, ())
70-
case _ =>
71-
}
72-
ctx
73-
}
74-
75-
private def isLHS(tree: RefTree) = tree.removeAttachment(LHS).isDefined
76-
7762
override def transformIdent(tree: Ident)(implicit ctx: Context): Tree =
78-
if (isLHS(tree)) tree else Accessors.insert.accessorIfNeeded(tree)
63+
Accessors.insert.accessorIfNeeded(tree)
7964

8065
override def transformSelect(tree: Select)(implicit ctx: Context): Tree =
81-
if (isLHS(tree)) tree else Accessors.insert.accessorIfNeeded(tree)
66+
Accessors.insert.accessorIfNeeded(tree)
8267

8368
override def transformAssign(tree: Assign)(implicit ctx: Context): Tree =
84-
Accessors.insert.accessorIfNeeded(tree)
69+
tree.lhs match {
70+
case lhs: RefTree =>
71+
lhs.name match {
72+
case ProtectedAccessorName(name) =>
73+
cpy.Apply(tree)(Accessors.insert.useSetter(lhs), tree.rhs :: Nil)
74+
case _ =>
75+
tree
76+
}
77+
case _ =>
78+
tree
79+
}
8580

8681
override def transformTemplate(tree: Template)(implicit ctx: Context): Tree =
8782
cpy.Template(tree)(body = Accessors.addAccessorDefs(tree.symbol.owner, tree.body))

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import StdNames.nme
1515
import Contexts.Context
1616
import Names.{Name, TermName, EmptyTermName}
1717
import NameOps._
18-
import NameKinds.{ClassifiedNameKind, InlineGetterName, InlineSetterName}
18+
import NameKinds.{ClassifiedNameKind, InlineAccessorName}
1919
import ProtoTypes.selectionProto
2020
import SymDenotations.SymDenotation
2121
import Annotations._
@@ -32,13 +32,12 @@ object Inliner {
3232
import tpd._
3333

3434
class InlineAccessors extends AccessProxies {
35-
def getterName = InlineGetterName
36-
def setterName = InlineSetterName
3735

3836
/** A tree map which inserts accessors for all non-public term members accessed
3937
* from inlined code. Accessors are collected in the `accessors` buffer.
4038
*/
4139
class MakeInlineable(inlineSym: Symbol) extends TreeMap with Insert {
40+
def accessorNameKind = InlineAccessorName
4241

4342
/** A definition needs an accessor if it is private, protected, or qualified private
4443
* and it is not part of the tree that gets inlined. The latter test is implemented
@@ -54,8 +53,23 @@ object Inliner {
5453
// This is quite tricky, as such types can appear anywhere, including as parts
5554
// of types of other things. For the moment we do nothing and complain
5655
// at the implicit expansion site if there's a reference to an inaccessible type.
57-
override def transform(tree: Tree)(implicit ctx: Context): Tree =
58-
super.transform(accessorIfNeeded(tree))
56+
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
57+
case tree: Assign =>
58+
transform(tree.lhs) match {
59+
case lhs1: RefTree =>
60+
lhs1.name match {
61+
case InlineAccessorName(name) =>
62+
cpy.Apply(tree)(useSetter(lhs1), transform(tree.rhs) :: Nil)
63+
case _ =>
64+
super.transform(tree)
65+
}
66+
case _ =>
67+
super.transform(tree)
68+
}
69+
case _ =>
70+
super.transform(accessorIfNeeded(tree))
71+
}
72+
5973
}
6074

6175
/** Adds accessors for all non-public term members accessed

0 commit comments

Comments
 (0)