@@ -12,17 +12,19 @@ import core.Types._
12
12
import core .Names ._
13
13
import core .StdNames ._
14
14
import core .NameOps ._
15
- import core .NameKinds .AdaptedClosureName
15
+ import core .NameKinds .{ AdaptedClosureName , BodyRetainerName }
16
16
import core .Decorators ._
17
17
import core .Constants ._
18
18
import core .Definitions ._
19
+ import core .Annotations .BodyAnnotation
19
20
import typer .{NoChecking , LiftErased }
20
21
import typer .Inliner
21
22
import typer .ProtoTypes ._
22
23
import core .TypeErasure ._
23
24
import core .Decorators ._
24
25
import dotty .tools .dotc .ast .{tpd , untpd }
25
26
import ast .Trees ._
27
+ import ast .TreeTypeMap
26
28
import dotty .tools .dotc .core .{Constants , Flags }
27
29
import ValueClasses ._
28
30
import TypeUtils ._
@@ -78,17 +80,32 @@ class Erasure extends Phase with DenotTransformer {
78
80
val oldInfo = ref.info
79
81
val newInfo = transformInfo(oldSymbol, oldInfo)
80
82
val oldFlags = ref.flags
81
- val newFlags =
83
+ var newFlags =
82
84
if (oldSymbol.is(Flags .TermParam ) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags .Param
83
85
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 ])
85
91
// 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
87
99
ref
88
- else {
100
+ else
89
101
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)
92
109
}
93
110
case ref : JointRefDenotation =>
94
111
new UniqueRefDenotation (
@@ -813,7 +830,8 @@ object Erasure {
813
830
* parameter of type `[]Object`.
814
831
*/
815
832
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)
817
835
else
818
836
val restpe = if sym.isConstructor then defn.UnitType else sym.info.resultType
819
837
var vparams = outerParamDefs(sym)
@@ -874,6 +892,50 @@ object Erasure {
874
892
outerParamDefs(constr)
875
893
else Nil
876
894
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
+
877
939
override def typedClosure (tree : untpd.Closure , pt : Type )(implicit ctx : Context ): Tree = {
878
940
val xxl = defn.isXXLFunctionClass(tree.typeOpt.typeSymbol)
879
941
var implClosure = super .typedClosure(tree, pt).asInstanceOf [Closure ]
@@ -888,9 +950,10 @@ object Erasure {
888
950
typed(tree.arg, pt)
889
951
890
952
override def typedStats (stats : List [untpd.Tree ], exprOwner : Symbol )(implicit ctx : Context ): (List [Tree ], Context ) = {
953
+ val stats0 = addRetainedInlineBodies(stats)(using preErasureCtx)
891
954
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
894
957
val (stats2, finalCtx) = super .typedStats(stats1, exprOwner)
895
958
(stats2.filter(! _.isEmpty), finalCtx)
896
959
}
0 commit comments