@@ -19,7 +19,7 @@ import NameKinds.{ClassifiedNameKind, InlineGetterName, InlineSetterName}
1919import ProtoTypes .selectionProto
2020import SymDenotations .SymDenotation
2121import Annotations ._
22- import transform .ExplicitOuter
22+ import transform .{ ExplicitOuter , AccessProxies }
2323import Inferencing .fullyDefinedType
2424import config .Printers .inlining
2525import ErrorReporting .errorTree
@@ -31,119 +31,51 @@ import util.Positions.Position
3131object Inliner {
3232 import tpd ._
3333
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
4537
4638 /** 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 {
5042
5143 /** 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+ */
5547 def needsAccessor (sym : Symbol )(implicit ctx : Context ) =
5648 sym.isTerm &&
5749 (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)
8251
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- }
10152
10253 // TODO: Also handle references to non-public types.
10354 // This is quite tricky, as such types can appear anywhere, including as parts
10455 // of types of other things. For the moment we do nothing and complain
10556 // 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))
12059 }
12160
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+ }
12777 }
12878
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-
14779 /** Register inline info for given inline method `sym`.
14880 *
14981 * @param sym The symbol denotatioon of the inline method for which info is registered
@@ -163,7 +95,7 @@ object Inliner {
16395 sym.updateAnnotation(LazyBodyAnnotation { _ =>
16496 implicit val ctx = inlineCtx
16597 val body = treeExpr(ctx)
166- if (ctx.reporter.hasErrors) body else makeInlineable(body)
98+ if (ctx.reporter.hasErrors) body else InlineAccessors . makeInlineable(body)
16799 })
168100 }
169101 }
0 commit comments