@@ -12,17 +12,19 @@ import core.Types._
1212import core .Names ._
1313import core .StdNames ._
1414import core .NameOps ._
15- import core .NameKinds .AdaptedClosureName
15+ import core .NameKinds .{ AdaptedClosureName , BodyRetainerName }
1616import core .Decorators ._
1717import core .Constants ._
1818import core .Definitions ._
19+ import core .Annotations .BodyAnnotation
1920import typer .{NoChecking , LiftErased }
2021import typer .Inliner
2122import typer .ProtoTypes ._
2223import core .TypeErasure ._
2324import core .Decorators ._
2425import dotty .tools .dotc .ast .{tpd , untpd }
2526import ast .Trees ._
27+ import ast .TreeTypeMap
2628import dotty .tools .dotc .core .{Constants , Flags }
2729import ValueClasses ._
2830import TypeUtils ._
@@ -78,17 +80,32 @@ class Erasure extends Phase with DenotTransformer {
7880 val oldInfo = ref.info
7981 val newInfo = transformInfo(oldSymbol, oldInfo)
8082 val oldFlags = ref.flags
81- val newFlags =
83+ var newFlags =
8284 if (oldSymbol.is(Flags .TermParam ) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags .Param
8385 else oldFlags &~ Flags .HasDefaultParamsFlags // HasDefaultParamsFlags needs to be dropped because overriding might become overloading
84-
86+ val oldAnnotations = ref.annotations
87+ var newAnnotations = oldAnnotations
88+ if oldSymbol.isRetainedInlineMethod then
89+ newFlags = newFlags &~ Flags .Inline
90+ newAnnotations = newAnnotations.filterConserve(! _.isInstanceOf [BodyAnnotation ])
8591 // TODO: define derivedSymDenotation?
86- if ((oldSymbol eq newSymbol) && (oldOwner eq newOwner) && (oldName eq newName) && (oldInfo eq newInfo) && (oldFlags == newFlags))
92+ if (oldSymbol eq newSymbol)
93+ && (oldOwner eq newOwner)
94+ && (oldName eq newName)
95+ && (oldInfo eq newInfo)
96+ && (oldFlags == newFlags)
97+ && (oldAnnotations eq newAnnotations)
98+ then
8799 ref
88- else {
100+ else
89101 assert(! ref.is(Flags .PackageClass ), s " trans $ref @ ${ctx.phase} oldOwner = $oldOwner, newOwner = $newOwner, oldInfo = $oldInfo, newInfo = $newInfo ${oldOwner eq newOwner} ${oldInfo eq newInfo}" )
90- ref.copySymDenotation(symbol = newSymbol, owner = newOwner, name = newName, initFlags = newFlags, info = newInfo)
91- }
102+ ref.copySymDenotation(
103+ symbol = newSymbol,
104+ owner = newOwner,
105+ name = newName,
106+ initFlags = newFlags,
107+ info = newInfo,
108+ annotations = newAnnotations)
92109 }
93110 case ref : JointRefDenotation =>
94111 new UniqueRefDenotation (
@@ -813,7 +830,8 @@ object Erasure {
813830 * parameter of type `[]Object`.
814831 */
815832 override def typedDefDef (ddef : untpd.DefDef , sym : Symbol )(implicit ctx : Context ): Tree =
816- if (sym.isEffectivelyErased) erasedDef(sym)
833+ if sym.isEffectivelyErased || sym.name.is(BodyRetainerName ) then
834+ erasedDef(sym)
817835 else
818836 val restpe = if sym.isConstructor then defn.UnitType else sym.info.resultType
819837 var vparams = outerParamDefs(sym)
@@ -874,6 +892,50 @@ object Erasure {
874892 outerParamDefs(constr)
875893 else Nil
876894
895+ /** For all statements in stats: given a retained inline method and
896+ * its retainedBody method such as
897+ *
898+ * inline override def f(x: T) = body1
899+ * private def f$retainedBody(x: T) = body2
900+ *
901+ * return the runtime version of `f` as
902+ *
903+ * override def f(x: T) = body2
904+ *
905+ * Here, the owner of body2 is changed to f and all references
906+ * to parameters of f$retainedBody are changed to references of
907+ * corresponding parameters in f.
908+ *
909+ * `f$retainedBody` is subseqently mapped to the empty tree in `typedDefDef`
910+ * which is then dropped in `typedStats`.
911+ */
912+ private def addRetainedInlineBodies (stats : List [untpd.Tree ])(using ctx : Context ): List [untpd.Tree ] =
913+ lazy val retainerDef : Map [Symbol , DefDef ] = stats.collect {
914+ case stat : DefDef if stat.symbol.name.is(BodyRetainerName ) =>
915+ val retainer = stat.symbol
916+ val origName = retainer.name.asTermName.exclude(BodyRetainerName )
917+ val inlineMeth = ctx.atPhase(ctx.typerPhase) {
918+ retainer.owner.info.decl(origName)
919+ .matchingDenotation(retainer.owner.thisType, stat.symbol.info)
920+ .symbol
921+ }
922+ (inlineMeth, stat)
923+ }.toMap
924+ stats.mapConserve {
925+ case stat : DefDef if stat.symbol.isRetainedInlineMethod =>
926+ val rdef = retainerDef(stat.symbol)
927+ val fromParams = untpd.allParamSyms(rdef)
928+ val toParams = untpd.allParamSyms(stat)
929+ assert(fromParams.hasSameLengthAs(toParams))
930+ val mapBody = TreeTypeMap (
931+ oldOwners = rdef.symbol :: Nil ,
932+ newOwners = stat.symbol :: Nil ,
933+ substFrom = fromParams,
934+ substTo = toParams)
935+ cpy.DefDef (stat)(rhs = mapBody.transform(rdef.rhs))
936+ case stat => stat
937+ }
938+
877939 override def typedClosure (tree : untpd.Closure , pt : Type )(implicit ctx : Context ): Tree = {
878940 val xxl = defn.isXXLFunctionClass(tree.typeOpt.typeSymbol)
879941 var implClosure = super .typedClosure(tree, pt).asInstanceOf [Closure ]
@@ -888,9 +950,10 @@ object Erasure {
888950 typed(tree.arg, pt)
889951
890952 override def typedStats (stats : List [untpd.Tree ], exprOwner : Symbol )(implicit ctx : Context ): (List [Tree ], Context ) = {
953+ val stats0 = addRetainedInlineBodies(stats)(using preErasureCtx)
891954 val stats1 =
892- if (takesBridges(ctx.owner)) new Bridges (ctx.owner.asClass, erasurePhase).add(stats )
893- else stats
955+ if (takesBridges(ctx.owner)) new Bridges (ctx.owner.asClass, erasurePhase).add(stats0 )
956+ else stats0
894957 val (stats2, finalCtx) = super .typedStats(stats1, exprOwner)
895958 (stats2.filter(! _.isEmpty), finalCtx)
896959 }
0 commit comments