1
+ package dotty .tools .dotc
2
+ package transform
3
+
4
+ import core ._
5
+ import Contexts .Context
6
+ import Symbols ._
7
+ import Flags ._
8
+ import Names ._
9
+ import Decorators ._
10
+ import TypeUtils ._
11
+ import Annotations .Annotation
12
+ import Types ._
13
+ import NameKinds .ClassifiedNameKind
14
+ import ast .Trees ._
15
+ import util .Property
16
+ import util .Positions .Position
17
+
18
+ /** A utility class for generating access proxies. Currently used for
19
+ * inline accessors and protected accessors.
20
+ */
21
+ abstract class AccessProxies {
22
+ import ast .tpd ._
23
+
24
+ def getterName : ClassifiedNameKind
25
+ def setterName : ClassifiedNameKind
26
+
27
+ /** accessor -> accessed */
28
+ private val accessedBy = newMutableSymbolMap[Symbol ]
29
+
30
+ /** The accessor definitions that need to be added to class `cls`
31
+ * As a side-effect, this method removes entries from the `accessedBy` map.
32
+ * So a second call of the same method will yield the empty list.
33
+ */
34
+ private def accessorDefs (cls : Symbol )(implicit ctx : Context ): Iterator [DefDef ] =
35
+ for (accessor <- cls.info.decls.iterator; accessed <- accessedBy.remove(accessor)) yield
36
+ polyDefDef(accessor.asTerm, tps => argss => {
37
+ val accessRef = ref(TermRef (cls.thisType, accessed))
38
+ val rhs =
39
+ if (accessor.name.is(setterName) &&
40
+ argss.nonEmpty && argss.head.nonEmpty) // defensive conditions
41
+ accessRef.becomes(argss.head.head)
42
+ else
43
+ accessRef.appliedToTypes(tps).appliedToArgss(argss)
44
+ rhs.withPos(accessed.pos)
45
+ })
46
+
47
+ /** Add all needed accessors to the `body` of class `cls` */
48
+ def addAccessorDefs (cls : Symbol , body : List [Tree ])(implicit ctx : Context ): List [Tree ] = {
49
+ val accDefs = accessorDefs(cls)
50
+ if (accDefs.isEmpty) body else body ++ accDefs
51
+ }
52
+
53
+ trait Insert {
54
+ import ast .tpd ._
55
+
56
+ def needsAccessor (sym : Symbol )(implicit ctx : Context ): Boolean
57
+
58
+ /** A fresh accessor symbol */
59
+ def newAccessorSymbol (accessed : Symbol , name : TermName , info : Type )(implicit ctx : Context ): TermSymbol =
60
+ ctx.newSymbol(accessed.owner.enclosingSubClass, name, Synthetic | Method ,
61
+ info, coord = accessed.pos).entered
62
+
63
+ /** Create an accessor unless one exists already, and replace the original
64
+ * access with a reference to the accessor.
65
+ *
66
+ * @param reference The original reference to the non-public symbol
67
+ * @param onLHS The reference is on the left-hand side of an assignment
68
+ */
69
+ def useAccessor (reference : RefTree , onLHS : Boolean )(implicit ctx : Context ): Tree = {
70
+
71
+ def nameKind = if (onLHS) setterName else getterName
72
+ val accessed = reference.symbol.asTerm
73
+
74
+ def refersToAccessed (sym : Symbol ) = accessedBy.get(sym) == Some (accessed)
75
+
76
+ val accessorInfo =
77
+ if (onLHS) MethodType (accessed.info :: Nil , defn.UnitType )
78
+ else accessed.info.ensureMethodic
79
+ val accessorName = nameKind(accessed.name)
80
+ val accessorSymbol =
81
+ accessed.owner.info.decl(accessorName).suchThat(refersToAccessed).symbol
82
+ .orElse {
83
+ val acc = newAccessorSymbol(accessed, accessorName, accessorInfo)
84
+ accessedBy(acc) = accessed
85
+ acc
86
+ }
87
+
88
+ { reference match {
89
+ case Select (qual, _) => qual.select(accessorSymbol)
90
+ case Ident (name) => ref(accessorSymbol)
91
+ }
92
+ }.withPos(reference.pos)
93
+ }
94
+
95
+ /** Replace tree with a reference to an accessor if needed */
96
+ def accessorIfNeeded (tree : Tree )(implicit ctx : Context ): Tree = tree match {
97
+ case tree : RefTree if needsAccessor(tree.symbol) =>
98
+ if (tree.symbol.isConstructor) {
99
+ ctx.error(" Implementation restriction: cannot use private constructors in inline methods" , tree.pos)
100
+ tree // TODO: create a proper accessor for the private constructor
101
+ }
102
+ else useAccessor(tree, onLHS = false )
103
+ case Assign (lhs : RefTree , rhs) if needsAccessor(lhs.symbol) =>
104
+ cpy.Apply (tree)(useAccessor(lhs, onLHS = true ), List (rhs))
105
+ case _ =>
106
+ tree
107
+ }
108
+ }
109
+ }
0 commit comments