@@ -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 = new mutable.HashMap [(Symbol , List [Tree ], List [List [Tree ]]), Tree ]
51
+ private val setters = new mutable.HashMap [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,70 @@ 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
- }
114
99
115
- val qualType = dealiasMap(qual.tpe.widen)
100
+ def addAcc (accessorDef : MemberDef ) = {
101
+ accessors += accessorDef
102
+ inlining.println(i " added inline accessor: $accessorDef" )
103
+ }
116
104
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
- }
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
+ }
125
+
126
+ val qualType = dealiasMap(qual.tpe.widen)
123
127
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
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
+ }
134
+
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
- )
152
+ .withPos(tree.pos.focus)))
142
153
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
154
+ ref(accessor)
155
+ .appliedToTypeTrees(localRefs.map(TypeTree (_)) ++ targs)
156
+ .appliedToArgss((qual :: Nil ) :: argss)
157
+ }
152
158
}
153
159
154
160
override def transform (tree : Tree )(implicit ctx : Context ): Tree = super .transform {
@@ -159,12 +165,15 @@ object Inliner {
159
165
if (methPart.symbol.isConstructor && needsAccessor(methPart.symbol)) {
160
166
ctx.error(" Cannot use private constructors in inline methods" , tree.pos)
161
167
tree // TODO: create a proper accessor for the private constructor
162
- } else {
163
- addAccessor(tree, methPart, targs, argss,
164
- accessedType = methPart.tpe.widen,
165
- rhs = (qual, tps, argss) => qual.appliedToTypes(tps).appliedToArgss(argss))
166
168
}
167
- } else {
169
+ else
170
+ getters.getOrElseUpdate((methPart.symbol, targs, argss),
171
+ addAccessor(tree, methPart, targs, argss,
172
+ accessedType = methPart.tpe.widen,
173
+ rhs = (qual, tps, argss) => qual.appliedToTypes(tps).appliedToArgss(argss)))
174
+ .withPos(tree.pos)
175
+ }
176
+ else {
168
177
// TODO: Handle references to non-public types.
169
178
// This is quite tricky, as such types can appear anywhere, including as parts
170
179
// of types of other things. For the moment we do nothing and complain
@@ -178,9 +187,11 @@ object Inliner {
178
187
tree
179
188
}
180
189
case Assign (lhs : RefTree , rhs) if needsAccessor(lhs.symbol) =>
181
- addAccessor(tree, lhs, Nil , (rhs :: Nil ) :: Nil ,
190
+ setters.getOrElseUpdate(lhs.symbol,
191
+ addAccessor(tree, lhs, Nil , (rhs :: Nil ) :: Nil ,
182
192
accessedType = MethodType (rhs.tpe.widen :: Nil , defn.UnitType ),
183
- rhs = (lhs, tps, argss) => lhs.becomes(argss.head.head))
193
+ rhs = (lhs, tps, argss) => lhs.becomes(argss.head.head)))
194
+ .withPos(tree.pos)
184
195
case _ => tree
185
196
}
186
197
}
0 commit comments