@@ -411,6 +411,70 @@ object Inliner {
411
411
412
412
}
413
413
414
+ /** Very similar to TreeInfo.isPureExpr, but with the following inliner-only exceptions:
415
+ * - synthetic case class apply methods, when the case class constructor is empty, are
416
+ * elideable but not pure. Elsewhere, accessing the apply method might cause the initialization
417
+ * of a containing object so they are merely idempotent.
418
+ */
419
+ object isElideableExpr {
420
+ def isStatElideable (tree : Tree )(using Context ): Boolean = unsplice(tree) match {
421
+ case EmptyTree
422
+ | TypeDef (_, _)
423
+ | Import (_, _)
424
+ | DefDef (_, _, _, _) =>
425
+ true
426
+ case vdef @ ValDef (_, _, _) =>
427
+ if (vdef.symbol.flags is Mutable ) false else apply(vdef.rhs)
428
+ case _ =>
429
+ false
430
+ }
431
+
432
+ def apply (tree : Tree )(using Context ): Boolean = unsplice(tree) match {
433
+ case EmptyTree
434
+ | This (_)
435
+ | Super (_, _)
436
+ | Literal (_) =>
437
+ true
438
+ case Ident (_) =>
439
+ isPureRef(tree) || tree.symbol.isAllOf(Inline | Param )
440
+ case Select (qual, _) =>
441
+ if (tree.symbol.is(Erased )) true
442
+ else isPureRef(tree) && apply(qual)
443
+ case New (_) | Closure (_, _, _) =>
444
+ true
445
+ case TypeApply (fn, _) =>
446
+ if (fn.symbol.is(Erased ) || fn.symbol == defn.QuotedTypeModule_of ) true else apply(fn)
447
+ case Apply (fn, args) =>
448
+ val isCaseClassApply = {
449
+ val cls = tree.tpe.classSymbol
450
+ val meth = fn.symbol
451
+ meth.name == nme.apply &&
452
+ meth.flags.is(Synthetic ) &&
453
+ meth.owner.linkedClass.is(Case ) &&
454
+ cls.isNoInitsRealClass &&
455
+ funPart(fn).match
456
+ case Select (qual, _) => qual.symbol.is(Synthetic ) // e.g: disallow `{ ..; Foo }.apply(..)`
457
+ case meth @ Ident (_) => meth.symbol.is(Synthetic ) // e.g: allow `import Foo.{ apply => foo }; foo(..)`
458
+ case _ => false
459
+ }
460
+ if isPureApply(tree, fn) then
461
+ apply(fn) && args.forall(apply)
462
+ else if (isCaseClassApply)
463
+ args.forall(apply)
464
+ else if (fn.symbol.is(Erased )) true
465
+ else false
466
+ case Typed (expr, _) =>
467
+ apply(expr)
468
+ case Block (stats, expr) =>
469
+ apply(expr) && stats.forall(isStatElideable)
470
+ case Inlined (_, bindings, expr) =>
471
+ apply(expr) && bindings.forall(isStatElideable)
472
+ case NamedArg (_, expr) =>
473
+ apply(expr)
474
+ case _ =>
475
+ false
476
+ }
477
+ }
414
478
}
415
479
416
480
/** Produces an inlined version of `call` via its `inlined` method.
@@ -691,67 +755,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
691
755
|| tpe.cls.is(Package )
692
756
|| tpe.cls.isStaticOwner && ! (tpe.cls.seesOpaques && inlinedMethod.isContainedIn(tpe.cls))
693
757
694
- /** Very similar to TreeInfo.isPureExpr, but with the following inliner-only exceptions:
695
- * - synthetic case class apply methods, when the case class constructor is empty, are
696
- * elideable but not pure. Elsewhere, accessing the apply method might cause the initialization
697
- * of a containing object so they are merely idempotent.
698
- */
699
- object isElideableExpr {
700
- def isStatElideable (tree : Tree )(using Context ): Boolean = unsplice(tree) match {
701
- case EmptyTree
702
- | TypeDef (_, _)
703
- | Import (_, _)
704
- | DefDef (_, _, _, _) =>
705
- true
706
- case vdef @ ValDef (_, _, _) =>
707
- if (vdef.symbol.flags is Mutable ) false else apply(vdef.rhs)
708
- case _ =>
709
- false
710
- }
711
-
712
- def apply (tree : Tree ): Boolean = unsplice(tree) match {
713
- case EmptyTree
714
- | This (_)
715
- | Super (_, _)
716
- | Literal (_) =>
717
- true
718
- case Ident (_) =>
719
- isPureRef(tree) || tree.symbol.isAllOf(Inline | Param )
720
- case Select (qual, _) =>
721
- if (tree.symbol.is(Erased )) true
722
- else isPureRef(tree) && apply(qual)
723
- case New (_) | Closure (_, _, _) =>
724
- true
725
- case TypeApply (fn, _) =>
726
- if (fn.symbol.is(Erased ) || fn.symbol == defn.QuotedTypeModule_of ) true else apply(fn)
727
- case Apply (fn, args) =>
728
- val isCaseClassApply = {
729
- val cls = tree.tpe.classSymbol
730
- val meth = fn.symbol
731
- meth.name == nme.apply &&
732
- meth.flags.is(Synthetic ) &&
733
- meth.owner.linkedClass.is(Case ) &&
734
- cls.isNoInitsRealClass
735
- }
736
- if isPureApply(tree, fn) then
737
- apply(fn) && args.forall(apply)
738
- else if (isCaseClassApply)
739
- args.forall(apply)
740
- else if (fn.symbol.is(Erased )) true
741
- else false
742
- case Typed (expr, _) =>
743
- apply(expr)
744
- case Block (stats, expr) =>
745
- apply(expr) && stats.forall(isStatElideable)
746
- case Inlined (_, bindings, expr) =>
747
- apply(expr) && bindings.forall(isStatElideable)
748
- case NamedArg (_, expr) =>
749
- apply(expr)
750
- case _ =>
751
- false
752
- }
753
- }
754
-
755
758
/** Populate `thisProxy` and `paramProxy` as follows:
756
759
*
757
760
* 1a. If given type refers to a static this, thisProxy binds it to corresponding global reference,
0 commit comments