@@ -47,6 +47,8 @@ object Inliner {
47
47
*/
48
48
object addAccessors extends TreeMap {
49
49
val accessors = new mutable.ListBuffer [MemberDef ]
50
+ private val getters = mutable.Map [Symbol , Tree ]()
51
+ private val setters = mutable.Map [Symbol , Tree ]()
50
52
51
53
/** A definition needs an accessor if it is private, protected, or qualified private
52
54
* and it is not part of the tree that gets inlined. The latter test is implemented
@@ -89,66 +91,71 @@ object Inliner {
89
91
def addAccessor (tree : Tree , refPart : Tree , targs : List [Tree ], argss : List [List [Tree ]],
90
92
accessedType : Type , rhs : (Tree , List [Type ], List [List [Tree ]]) => Tree )(implicit ctx : Context ): Tree = {
91
93
val qual = qualifier(refPart)
94
+
92
95
def refIsLocal = qual match {
93
96
case qual : This => qual.symbol == refPart.symbol.owner
94
97
case _ => false
95
98
}
96
- val (accessorDef, accessorRef) =
97
- if (refPart.symbol.isStatic || refIsLocal) {
98
- // Easy case: Reference to a static symbol or a symbol referenced via `this.`
99
- val accessorType = accessedType.ensureMethodic
100
- val accessor = accessorSymbol(tree, accessorType).asTerm
101
- val accessorDef = polyDefDef(accessor, tps => argss =>
102
- rhs(refPart, tps, argss).withPos(tree.pos.focus))
103
- val accessorRef = ref(accessor).appliedToTypeTrees(targs).appliedToArgss(argss).withPos(tree.pos)
104
- (accessorDef, accessorRef)
105
- } else {
106
- // Hard case: Reference needs to go via a dynamic prefix
107
- inlining.println(i " adding inline accessor for $tree -> ( ${qual.tpe}, $refPart: ${refPart.getClass}, [ $targs%, %], ( $argss%, %)) " )
108
-
109
- // Need to dealias in order to catch all possible references to abstracted over types in
110
- // substitutions
111
- val dealiasMap = new TypeMap {
112
- def apply (t : Type ) = mapOver(t.dealias)
113
- }
99
+
100
+ def addAcc (accessorDef : MemberDef ) = {
101
+ accessors += accessorDef
102
+ inlining.println(i " added inline accessor: $accessorDef" )
103
+ }
104
+
105
+ if (refPart.symbol.isStatic || refIsLocal) {
106
+ // Easy case: Reference to a static symbol or a symbol referenced via `this.`
107
+ val accessorType = accessedType.ensureMethodic
108
+ val accessor = accessorSymbol(tree, accessorType).asTerm
109
+
110
+ addAcc(
111
+ polyDefDef(accessor, tps => argss =>
112
+ rhs(refPart, tps, argss).withPos(tree.pos.focus)))
113
+
114
+ ref(accessor).appliedToTypeTrees(targs).appliedToArgss(argss).withPos(tree.pos)
115
+ }
116
+ else {
117
+ // Hard case: Reference needs to go via a dynamic prefix
118
+ inlining.println(i " adding inline accessor for $tree -> ( ${qual.tpe}, $refPart: ${refPart.getClass}, [ $targs%, %], ( $argss%, %)) " )
119
+
120
+ // Need to dealias in order to catch all possible references to abstracted over types in
121
+ // substitutions
122
+ val dealiasMap = new TypeMap {
123
+ def apply (t : Type ) = mapOver(t.dealias)
124
+ }
114
125
115
- val qualType = dealiasMap(qual.tpe.widen)
126
+ val qualType = dealiasMap(qual.tpe.widen)
116
127
117
- // Add qualifier type as leading method argument to argument `tp`
118
- def addQualType (tp : Type ): Type = tp match {
119
- case tp : PolyType => tp.derivedLambdaType(tp.paramNames, tp.paramInfos, addQualType(tp.resultType))
120
- case tp : ExprType => addQualType(tp.resultType)
121
- case tp => MethodType (qualType :: Nil , tp)
122
- }
128
+ // Add qualifier type as leading method argument to argument `tp`
129
+ def addQualType (tp : Type ): Type = tp match {
130
+ case tp : PolyType => tp.derivedLambdaType(tp.paramNames, tp.paramInfos, addQualType(tp.resultType))
131
+ case tp : ExprType => addQualType(tp.resultType)
132
+ case tp => MethodType (qualType :: Nil , tp)
133
+ }
123
134
124
- // The types that are local to the inlined method, and that therefore have
125
- // to be abstracted out in the accessor, which is external to the inlined method
126
- val localRefs = qualType.namedPartsWith(ref =>
127
- ref.isType && ref.symbol.isContainedIn(inlineMethod)).toList
135
+ // The types that are local to the inlined method, and that therefore have
136
+ // to be abstracted out in the accessor, which is external to the inlined method
137
+ val localRefs = qualType.namedPartsWith(ref =>
138
+ ref.isType && ref.symbol.isContainedIn(inlineMethod)).toList
128
139
129
- // Abstract accessed type over local refs
130
- def abstractQualType (mtpe : Type ): Type =
131
- if (localRefs.isEmpty) mtpe
132
- else PolyType .fromParams(localRefs.map(_.symbol.asType), mtpe)
133
- .asInstanceOf [PolyType ].flatten
140
+ // Abstract accessed type over local refs
141
+ def abstractQualType (mtpe : Type ): Type =
142
+ if (localRefs.isEmpty) mtpe
143
+ else PolyType .fromParams(localRefs.map(_.symbol.asType), mtpe)
144
+ .asInstanceOf [PolyType ].flatten
134
145
135
- val accessorType = abstractQualType(addQualType(dealiasMap(accessedType)))
136
- val accessor = accessorSymbol(tree, accessorType).asTerm
146
+ val accessorType = abstractQualType(addQualType(dealiasMap(accessedType)))
147
+ val accessor = accessorSymbol(tree, accessorType).asTerm
137
148
138
- val accessorDef = polyDefDef(accessor, tps => argss =>
149
+ addAcc(
150
+ polyDefDef(accessor, tps => argss =>
139
151
rhs(argss.head.head.select(refPart.symbol), tps.drop(localRefs.length), argss.tail)
140
- .withPos(tree.pos.focus)
141
- )
142
-
143
- val accessorRef = ref(accessor)
144
- .appliedToTypeTrees(localRefs.map(TypeTree (_)) ++ targs)
145
- .appliedToArgss((qual :: Nil ) :: argss)
146
- .withPos(tree.pos)
147
- (accessorDef, accessorRef)
148
- }
149
- accessors += accessorDef
150
- inlining.println(i " added inline accessor: $accessorDef" )
151
- accessorRef
152
+ .withPos(tree.pos.focus)))
153
+
154
+ ref(accessor)
155
+ .appliedToTypeTrees(localRefs.map(TypeTree (_)) ++ targs)
156
+ .appliedToArgss((qual :: Nil ) :: argss)
157
+ .withPos(tree.pos)
158
+ }
152
159
}
153
160
154
161
override def transform (tree : Tree )(implicit ctx : Context ): Tree = super .transform {
@@ -160,9 +167,10 @@ object Inliner {
160
167
ctx.error(" Cannot use private constructors in inline methods" , tree.pos)
161
168
tree // TODO: create a proper accessor for the private constructor
162
169
} else {
163
- addAccessor(tree, methPart, targs, argss,
170
+ getters.getOrElseUpdate(methPart.symbol,
171
+ addAccessor(tree, methPart, targs, argss,
164
172
accessedType = methPart.tpe.widen,
165
- rhs = (qual, tps, argss) => qual.appliedToTypes(tps).appliedToArgss(argss))
173
+ rhs = (qual, tps, argss) => qual.appliedToTypes(tps).appliedToArgss(argss)))
166
174
}
167
175
} else {
168
176
// TODO: Handle references to non-public types.
@@ -178,9 +186,10 @@ object Inliner {
178
186
tree
179
187
}
180
188
case Assign (lhs : RefTree , rhs) if needsAccessor(lhs.symbol) =>
181
- addAccessor(tree, lhs, Nil , (rhs :: Nil ) :: Nil ,
189
+ setters.getOrElseUpdate(lhs.symbol,
190
+ addAccessor(tree, lhs, Nil , (rhs :: Nil ) :: Nil ,
182
191
accessedType = MethodType (rhs.tpe.widen :: Nil , defn.UnitType ),
183
- rhs = (lhs, tps, argss) => lhs.becomes(argss.head.head))
192
+ rhs = (lhs, tps, argss) => lhs.becomes(argss.head.head)))
184
193
case _ => tree
185
194
}
186
195
}
0 commit comments