@@ -72,9 +72,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase =>
72
72
override def transformTemplate (impl : Template )(using Context ): Tree = {
73
73
val cls = ctx.owner.asClass
74
74
val isTrait = cls.is(Trait )
75
- if (needsOuterIfReferenced(cls) &&
76
- ! needsOuterAlways(cls) &&
77
- impl.existsSubTree(referencesOuter(cls, _)))
75
+ if needsOuterIfReferenced(cls) && ! needsOuterAlways(cls) && referencesOuter(cls, impl) then
78
76
ensureOuterAccessors(cls)
79
77
80
78
val clsHasOuter = hasOuter(cls)
@@ -255,55 +253,83 @@ object ExplicitOuter {
255
253
256
254
/** Tree references an outer class of `cls` which is not a static owner.
257
255
*/
258
- def referencesOuter (cls : Symbol , tree : Tree )(using Context ): Boolean = {
259
- def isOuterSym (sym : Symbol ) =
260
- ! sym.isStaticOwner && cls.isProperlyContainedIn(sym)
261
- def isOuterRef (ref : Type ): Boolean = ref match {
262
- case ref : ThisType =>
263
- isOuterSym(ref.cls)
264
- case ref : TermRef =>
265
- if (ref.prefix ne NoPrefix )
266
- ! ref.symbol.isStatic && isOuterRef(ref.prefix)
267
- else (
268
- ref.symbol.isOneOf(HoistableFlags ) &&
269
- // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need
270
- // an outer path then.
271
- isOuterSym(ref.symbol.owner.enclosingClass)
272
- ||
273
- // If not hoistable, ref.symbol will get a proxy in immediately enclosing class. If this properly
274
- // contains the current class, it needs an outer path.
275
- // If the symbol is hoistable, it might have free variables for which the same
276
- // reasoning applies. See pos/i1664.scala
277
- ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner)
278
- )
279
- case _ => false
280
- }
281
- def hasOuterPrefix (tp : Type ): Boolean = tp.stripped match {
282
- case AppliedType (tycon, _) => hasOuterPrefix(tycon)
283
- case TypeRef (prefix, _) => isOuterRef(prefix)
284
- case _ => false
285
- }
286
- def containsOuterRefs (tp : Type ): Boolean = tp match
287
- case tp : SingletonType => isOuterRef(tp)
288
- case tp : AndOrType => containsOuterRefs(tp.tp1) || containsOuterRefs(tp.tp2)
289
- case _ => false
290
- tree match {
291
- case _ : This | _ : Ident => isOuterRef(tree.tpe)
292
- case nw : New =>
293
- val newCls = nw.tpe.classSymbol
294
- isOuterSym(newCls.owner.enclosingClass) ||
295
- hasOuterPrefix(nw.tpe) ||
296
- newCls.owner.isTerm && cls.isProperlyContainedIn(newCls)
297
- // newCls might get proxies for free variables. If current class is
298
- // properly contained in newCls, it needs an outer path to newCls access the
299
- // proxies and forward them to the new instance.
300
- case app : TypeApply if app.symbol.isTypeTest =>
301
- // Type tests of singletons translate to `eq` tests with references, which might require outer pointers
302
- containsOuterRefs(app.args.head.tpe)
303
- case _ =>
304
- false
305
- }
306
- }
256
+ def referencesOuter (cls : Symbol , tree : Tree )(using Context ): Boolean =
257
+
258
+
259
+ val test = new TreeAccumulator [Boolean ]:
260
+ private var inInline = false
261
+
262
+ def isOuterSym (sym : Symbol ) =
263
+ ! sym.isStaticOwner && cls.isProperlyContainedIn(sym)
264
+
265
+ def isOuterRef (ref : Type ): Boolean = ref match
266
+ case ref : ThisType =>
267
+ isOuterSym(ref.cls)
268
+ case ref : TermRef =>
269
+ if (ref.prefix ne NoPrefix )
270
+ ! ref.symbol.isStatic && isOuterRef(ref.prefix)
271
+ else (
272
+ ref.symbol.isOneOf(HoistableFlags ) &&
273
+ // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need
274
+ // an outer path then.
275
+ isOuterSym(ref.symbol.owner.enclosingClass)
276
+ ||
277
+ // If not hoistable, ref.symbol will get a proxy in immediately enclosing class. If this properly
278
+ // contains the current class, it needs an outer path.
279
+ // If the symbol is hoistable, it might have free variables for which the same
280
+ // reasoning applies. See pos/i1664.scala
281
+ ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner)
282
+ )
283
+ case _ => false
284
+
285
+ def hasOuterPrefix (tp : Type ): Boolean = tp.stripped match
286
+ case AppliedType (tycon, _) => hasOuterPrefix(tycon)
287
+ case TypeRef (prefix, _) => isOuterRef(prefix)
288
+ case _ => false
289
+
290
+ def containsOuterRefsAtTopLevel (tp : Type ): Boolean = tp match
291
+ case tp : SingletonType => isOuterRef(tp)
292
+ case tp : AndOrType => containsOuterRefsAtTopLevel(tp.tp1) || containsOuterRefsAtTopLevel(tp.tp2)
293
+ case _ => false
294
+
295
+ def containsOuterRefsAnywhere (tp : Type ): Boolean =
296
+ tp.existsPart({
297
+ case t : SingletonType => isOuterRef(t)
298
+ case _ => false
299
+ }, StopAt .Static )
300
+
301
+ def containsOuterRefs (t : Tree ): Boolean = t match
302
+ case _ : This | _ : Ident => isOuterRef(t.tpe)
303
+ case nw : New =>
304
+ val newCls = nw.tpe.classSymbol
305
+ isOuterSym(newCls.owner.enclosingClass) ||
306
+ hasOuterPrefix(nw.tpe) ||
307
+ newCls.owner.isTerm && cls.isProperlyContainedIn(newCls)
308
+ // newCls might get proxies for free variables. If current class is
309
+ // properly contained in newCls, it needs an outer path to newCls access the
310
+ // proxies and forward them to the new instance.
311
+ case app : TypeApply if app.symbol.isTypeTest =>
312
+ // Type tests of singletons translate to `eq` tests with references, which might require outer pointers
313
+ containsOuterRefsAtTopLevel(app.args.head.tpe)
314
+ case t : TypeTree if inInline =>
315
+ // Expansions of inline methods must be able to address outer types
316
+ containsOuterRefsAnywhere(t.tpe)
317
+ case _ =>
318
+ false
319
+
320
+ def apply (x : Boolean , t : Tree )(using Context ) =
321
+ if x || containsOuterRefs(t) then true
322
+ else t match
323
+ case t : DefDef if t.symbol.isInlineMethod =>
324
+ val saved = inInline
325
+ inInline = true
326
+ try foldOver(x, t)
327
+ finally inInline = saved
328
+ case _ =>
329
+ foldOver(x, t)
330
+
331
+ test(false , tree)
332
+ end referencesOuter
307
333
308
334
private final val HoistableFlags = Method | Lazy | Module
309
335
0 commit comments