@@ -182,32 +182,47 @@ abstract class Dependencies(root: ast.tpd.Tree, @constructorOnly rootContext: Co
182
182
if enclClass.isContainedIn(thisClass) then thisClass
183
183
else enclClass) // unknown this reference, play it safe and assume the narrowest possible owner
184
184
185
+ /** Set the first owner of a local method or class that's nested inside a term.
186
+ * This is either the enclosing package or the enclosing class. If the former,
187
+ * the method will be be translated to a static method of its toplevel class.
188
+ * In that case, we might later re-adjust the owner to a nested class via
189
+ * `narrowTo` when we see that the method refers to the this-type of that class.
190
+ * We choose the enclosing package when there's something potentially to gain from this
191
+ * and when it is safe to do so
192
+ */
185
193
def setLogicOwner (local : Symbol ) =
186
194
val encClass = local.owner.enclosingClass
195
+ // When to [efer enclosing class over enclosing package:
187
196
val preferEncClass =
188
197
encClass.isStatic
189
- // non-static classes can capture owners, so should be avoided
198
+ // If class is not static, we try to hoist the method out of
199
+ // the class to avoid the outer pointer.
190
200
&& (encClass.isProperlyContainedIn(local.topLevelClass)
191
- // can be false for symbols which are defined in some weird combination of supercalls.
201
+ // If class is nested in an outer object, we prefer to leave the method in the class,
202
+ // since putting it in the outer object makes access more complicated
192
203
|| encClass.is(ModuleClass , butNot = Package )
193
- // needed to not cause deadlocks in classloader. see t5375.scala
204
+ // If class is an outermost object we also want to avoid making the
205
+ // method static since that could cause deadlocks in interacting
206
+ // with class initialization. See deadlock.scala
194
207
)
195
208
&& (! sym.isAnonymousFunction || sym.owner.ownersIterator.exists(_.isConstructor))
196
- // For anonymous functions in static objects, we prefer them to be static because
197
- // that means lambdas are memoized and can be serialized even if the enclosing object
209
+ // The previous conditions mean methods in static objects and nested static classes
210
+ // don't get lifted out to be static. In general it is prudent to do that. However,
211
+ // for anonymous functions, we prefer them to be static because that means lambdas
212
+ // are memoized and can be serialized even if the enclosing object or class
198
213
// is not serializable. See run/lambda-serialization-gc.scala and run/i19224.scala.
199
214
// On the other hand, we don't want to lift anonymous functions from inside the
200
- // object constructor to be static since that can cause deadlocks by its interaction
201
- // with class initialization. See run/deadlock.scala, which works in Scala 3
202
- // but deadlocks in Scala 2.
215
+ // object or class constructor to be static since that can cause again deadlocks
216
+ // by its interaction with class initialization. See run/deadlock.scala, which works
217
+ // in Scala 3 but deadlocks in Scala 2.
203
218
||
204
219
/* Scala.js: Never move any member beyond the boundary of a DynamicImportThunk.
205
220
* DynamicImportThunk subclasses are boundaries between the eventual ES modules
206
221
* that can be dynamically loaded. Moving members across that boundary changes
207
222
* the dynamic and static dependencies between ES modules, which is forbidden.
208
223
*/
209
224
ctx.settings.scalajs.value && encClass.isSubClass(jsdefn.DynamicImportThunkClass )
210
-
225
+
211
226
logicOwner(sym) = if preferEncClass then encClass else local.enclosingPackageClass
212
227
213
228
tree match
0 commit comments