@@ -411,6 +411,70 @@ object Inliner {
411411
412412 }
413413
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+ }
414478}
415479
416480/** Produces an inlined version of `call` via its `inlined` method.
@@ -691,67 +755,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
691755 || tpe.cls.is(Package )
692756 || tpe.cls.isStaticOwner && ! (tpe.cls.seesOpaques && inlinedMethod.isContainedIn(tpe.cls))
693757
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-
755758 /** Populate `thisProxy` and `paramProxy` as follows:
756759 *
757760 * 1a. If given type refers to a static this, thisProxy binds it to corresponding global reference,
0 commit comments