@@ -19,7 +19,7 @@ import NameKinds.{ClassifiedNameKind, InlineGetterName, InlineSetterName}
19
19
import ProtoTypes .selectionProto
20
20
import SymDenotations .SymDenotation
21
21
import Annotations ._
22
- import transform .ExplicitOuter
22
+ import transform .{ ExplicitOuter , AccessProxies }
23
23
import Inferencing .fullyDefinedType
24
24
import config .Printers .inlining
25
25
import ErrorReporting .errorTree
@@ -31,119 +31,51 @@ import util.Positions.Position
31
31
object Inliner {
32
32
import tpd ._
33
33
34
- /** Adds accessors for all non-public term members accessed
35
- * from `tree`. Non-public type members are currently left as they are.
36
- * This means that references to a private type will lead to typing failures
37
- * on the code when it is inlined. Less than ideal, but hard to do better (see below).
38
- *
39
- * @return If there are accessors generated, a thicket consisting of the rewritten `tree`
40
- * and all accessors, otherwise the original tree.
41
- */
42
- private def makeInlineable (tree : Tree )(implicit ctx : Context ) = {
43
-
44
- val inlineMethod = ctx.owner
34
+ object InlineAccessors extends AccessProxies {
35
+ def getterName = InlineGetterName
36
+ def setterName = InlineSetterName
45
37
46
38
/** A tree map which inserts accessors for all non-public term members accessed
47
- * from inlined code. Accessors are collected in the `accessors` buffer.
48
- */
49
- object addAccessors extends TreeMap {
39
+ * from inlined code. Accessors are collected in the `accessors` buffer.
40
+ */
41
+ class MakeInlineable ( inlineSym : Symbol ) extends TreeMap with Insert {
50
42
51
43
/** A definition needs an accessor if it is private, protected, or qualified private
52
- * and it is not part of the tree that gets inlined. The latter test is implemented
53
- * by excluding all symbols properly contained in the inlined method.
54
- */
44
+ * and it is not part of the tree that gets inlined. The latter test is implemented
45
+ * by excluding all symbols properly contained in the inlined method.
46
+ */
55
47
def needsAccessor (sym : Symbol )(implicit ctx : Context ) =
56
48
sym.isTerm &&
57
49
(sym.is(AccessFlags ) || sym.privateWithin.exists) &&
58
- ! sym.owner.isContainedIn(inlineMethod)
59
-
60
- /** A fresh accessor symbol.
61
- *
62
- * @param tree The tree representing the original access to the non-public member
63
- */
64
- def newAccessorSymbol (accessed : TermSymbol , name : TermName , info : Type )(implicit ctx : Context ): TermSymbol =
65
- ctx.newSymbol(accessed.owner, name, Synthetic | Method , info, coord = accessed.pos).entered
66
-
67
- /** Create an inline accessor unless one exists already, and replace the original
68
- * access with a reference to the accessor.
69
- *
70
- * @param reference The original reference to the non-public symbol
71
- * @param onLHS The reference is on the left-hand side of an assignment
72
- */
73
- def useAccessor (reference : RefTree , onLHS : Boolean )(implicit ctx : Context ): Tree = {
74
-
75
- def nameKind = if (onLHS) InlineSetterName else InlineGetterName
76
- val accessed = reference.symbol.asTerm
77
-
78
- def refersToAccessed (sym : Symbol ) = sym.getAnnotation(defn.AccessedAnnot ) match {
79
- case Some (Annotation .Accessed (sym)) => sym `eq` accessed
80
- case _ => false
81
- }
50
+ ! sym.isContainedIn(inlineSym)
82
51
83
- val accessorInfo =
84
- if (onLHS) MethodType (accessed.info :: Nil , defn.UnitType )
85
- else accessed.info.ensureMethodic
86
- val accessorName = nameKind(accessed.name)
87
- val accessorSymbol =
88
- accessed.owner.info.decl(accessorName).suchThat(refersToAccessed).symbol
89
- .orElse {
90
- val acc = newAccessorSymbol(accessed, accessorName, accessorInfo)
91
- acc.addAnnotation(Annotation .Accessed (accessed))
92
- acc
93
- }
94
-
95
- { reference match {
96
- case Select (qual, _) => qual.select(accessorSymbol)
97
- case Ident (name) => ref(accessorSymbol)
98
- }
99
- }.withPos(reference.pos)
100
- }
101
52
102
53
// TODO: Also handle references to non-public types.
103
54
// This is quite tricky, as such types can appear anywhere, including as parts
104
55
// of types of other things. For the moment we do nothing and complain
105
56
// at the implicit expansion site if there's a reference to an inaccessible type.
106
- override def transform (tree : Tree )(implicit ctx : Context ): Tree = super .transform {
107
- tree match {
108
- case tree : RefTree if needsAccessor(tree.symbol) =>
109
- if (tree.symbol.isConstructor) {
110
- ctx.error(" Implementation restriction: cannot use private constructors in inline methods" , tree.pos)
111
- tree // TODO: create a proper accessor for the private constructor
112
- }
113
- else useAccessor(tree, onLHS = false )
114
- case Assign (lhs : RefTree , rhs) if needsAccessor(lhs.symbol) =>
115
- cpy.Apply (tree)(useAccessor(lhs, onLHS = true ), List (rhs))
116
- case _ =>
117
- tree
118
- }
119
- }
57
+ override def transform (tree : Tree )(implicit ctx : Context ): Tree =
58
+ super .transform(accessorIfNeeded(tree))
120
59
}
121
60
122
- if (inlineMethod.owner.isTerm)
123
- // Inline methods in local scopes can only be called in the scope they are defined,
124
- // so no accessors are needed for them.
125
- tree
126
- else addAccessors.transform(tree)
61
+ /** Adds accessors for all non-public term members accessed
62
+ * from `tree`. Non-public type members are currently left as they are.
63
+ * This means that references to a private type will lead to typing failures
64
+ * on the code when it is inlined. Less than ideal, but hard to do better (see below).
65
+ *
66
+ * @return If there are accessors generated, a thicket consisting of the rewritten `tree`
67
+ * and all accessors, otherwise the original tree.
68
+ */
69
+ def makeInlineable (tree : Tree )(implicit ctx : Context ) = {
70
+ val inlineSym = ctx.owner
71
+ if (inlineSym.owner.isTerm)
72
+ // Inline methods in local scopes can only be called in the scope they are defined,
73
+ // so no accessors are needed for them.
74
+ tree
75
+ else new MakeInlineable (inlineSym).transform(tree)
76
+ }
127
77
}
128
78
129
- /** The inline accessor definitions that need to be added to class `cls`
130
- * As a side-effect, this method removes the `Accessed` annotations from
131
- * the accessor symbols. So a second call of the same method will yield the empty list.
132
- */
133
- def accessorDefs (cls : Symbol )(implicit ctx : Context ): List [DefDef ] =
134
- for (accessor <- cls.info.decls.filter(sym => sym.name.is(InlineGetterName ) || sym.name.is(InlineSetterName )))
135
- yield polyDefDef(accessor.asTerm, tps => argss => {
136
- val Annotation .Accessed (accessed) = accessor.getAnnotation(defn.AccessedAnnot ).get
137
- accessor.removeAnnotation(defn.AccessedAnnot )
138
- val rhs =
139
- if (accessor.name.is(InlineSetterName ) &&
140
- argss.nonEmpty && argss.head.nonEmpty) // defensive conditions
141
- ref(accessed).becomes(argss.head.head)
142
- else
143
- ref(accessed).appliedToTypes(tps).appliedToArgss(argss)
144
- rhs.withPos(accessed.pos)
145
- })
146
-
147
79
/** Register inline info for given inline method `sym`.
148
80
*
149
81
* @param sym The symbol denotatioon of the inline method for which info is registered
@@ -163,7 +95,7 @@ object Inliner {
163
95
sym.updateAnnotation(LazyBodyAnnotation { _ =>
164
96
implicit val ctx = inlineCtx
165
97
val body = treeExpr(ctx)
166
- if (ctx.reporter.hasErrors) body else makeInlineable(body)
98
+ if (ctx.reporter.hasErrors) body else InlineAccessors . makeInlineable(body)
167
99
})
168
100
}
169
101
}
0 commit comments