@@ -13,6 +13,7 @@ import core.Names._
13
13
import core .StdNames ._
14
14
import core .NameOps ._
15
15
import core .NameKinds .{AdaptedClosureName , BodyRetainerName }
16
+ import core .Scopes .newScopeWith
16
17
import core .Decorators ._
17
18
import core .Constants ._
18
19
import core .Definitions ._
@@ -81,16 +82,22 @@ class Erasure extends Phase with DenotTransformer {
81
82
val oldName = ref.name
82
83
val newName = ref.targetName
83
84
val oldInfo = ref.info
84
- val newInfo = transformInfo(oldSymbol, oldInfo)
85
+ var newInfo = transformInfo(oldSymbol, oldInfo)
85
86
val oldFlags = ref.flags
86
87
var newFlags =
87
- if ( oldSymbol.is(Flags .TermParam ) && isCompacted(oldSymbol.owner.denot)) oldFlags &~ Flags .Param
88
+ if oldSymbol.is(Flags .TermParam ) && isCompacted(oldSymbol.owner.denot) then oldFlags &~ Flags .Param
88
89
else oldFlags
89
90
val oldAnnotations = ref.annotations
90
91
var newAnnotations = oldAnnotations
91
92
if oldSymbol.isRetainedInlineMethod then
92
93
newFlags = newFlags &~ Flags .Inline
93
94
newAnnotations = newAnnotations.filterConserve(! _.isInstanceOf [BodyAnnotation ])
95
+ oldSymbol match
96
+ case cls : ClassSymbol if cls.is(Flags .Erased ) =>
97
+ newFlags = newFlags | Flags .Trait | Flags .JavaInterface
98
+ newAnnotations = Nil
99
+ newInfo = erasedClassInfo(cls)
100
+ case _ =>
94
101
// TODO: define derivedSymDenotation?
95
102
if ref.is(Flags .PackageClass )
96
103
|| ! ref.isClass // non-package classes are always copied since their base types change
@@ -125,6 +132,12 @@ class Erasure extends Phase with DenotTransformer {
125
132
unit.tpdTree = eraser.typedExpr(unit.tpdTree)(using ctx.fresh.setTyper(eraser).setPhase(this .next))
126
133
}
127
134
135
+ /** erased classes get erased to empty traits with Object as parent and an empty constructor */
136
+ private def erasedClassInfo (cls : ClassSymbol )(using Context ) =
137
+ cls.classInfo.derivedClassInfo(
138
+ declaredParents = defn.ObjectClass .typeRef :: Nil ,
139
+ decls = newScopeWith(newConstructor(cls, Flags .EmptyFlags , Nil , Nil )))
140
+
128
141
override def checkPostCondition (tree : tpd.Tree )(using Context ): Unit = {
129
142
assertErased(tree)
130
143
tree match {
@@ -587,15 +600,30 @@ object Erasure {
587
600
checkNotErasedClass(tree)
588
601
}
589
602
603
+ private def checkNotErasedClass (tp : Type , tree : untpd.Tree )(using Context ): Unit = tp match
604
+ case JavaArrayType (et) =>
605
+ checkNotErasedClass(et, tree)
606
+ case _ =>
607
+ if tp.isErasedClass then
608
+ val (kind, tree1) = tree match
609
+ case tree : untpd.ValOrDefDef => (" definition" , tree.tpt)
610
+ case tree : untpd.DefTree => (" definition" , tree)
611
+ case _ => (" expression" , tree)
612
+ report.error(em " illegal reference to erased ${tp.typeSymbol} in $kind that is not itself erased " , tree1.srcPos)
613
+
590
614
private def checkNotErasedClass (tree : Tree )(using Context ): tree.type =
591
- if tree.tpe.widen.isErasedClass then
592
- report.error(em " illegal reference to erased ${tree.tpe.widen.typeSymbol} in expression that is not itself erased " , tree.srcPos)
615
+ checkNotErasedClass(tree.tpe.widen.finalResultType, tree)
593
616
tree
594
617
595
- def erasedDef (sym : Symbol )(using Context ): Thicket = {
596
- if (sym.owner.isClass) sym.dropAfter(erasurePhase)
597
- tpd.EmptyTree
598
- }
618
+ def erasedDef (sym : Symbol )(using Context ): Tree =
619
+ if sym.isClass then
620
+ // We cannot simply drop erased classes, since then they would not generate classfiles
621
+ // and would not be visible under separate compilation. So we transform them to
622
+ // empty interfaces instead.
623
+ tpd.ClassDef (sym.asClass, DefDef (sym.primaryConstructor.asTerm), Nil )
624
+ else
625
+ if sym.owner.isClass then sym.dropAfter(erasurePhase)
626
+ tpd.EmptyTree
599
627
600
628
def erasedType (tree : untpd.Tree )(using Context ): Type = {
601
629
val tp = tree.typeOpt
@@ -874,6 +902,7 @@ object Erasure {
874
902
override def typedValDef (vdef : untpd.ValDef , sym : Symbol )(using Context ): Tree =
875
903
if (sym.isEffectivelyErased) erasedDef(sym)
876
904
else
905
+ checkNotErasedClass(sym.info, vdef)
877
906
super .typedValDef(untpd.cpy.ValDef (vdef)(
878
907
tpt = untpd.TypedSplice (TypeTree (sym.info).withSpan(vdef.tpt.span))), sym)
879
908
@@ -885,6 +914,7 @@ object Erasure {
885
914
if sym.isEffectivelyErased || sym.name.is(BodyRetainerName ) then
886
915
erasedDef(sym)
887
916
else
917
+ checkNotErasedClass(sym.info.finalResultType, ddef)
888
918
val restpe = if sym.isConstructor then defn.UnitType else sym.info.resultType
889
919
var vparams = outerParamDefs(sym)
890
920
::: ddef.paramss.collect {
@@ -1021,8 +1051,10 @@ object Erasure {
1021
1051
if mbr.is(ConstructorProxy ) then mbr.dropAfter(erasurePhase)
1022
1052
1023
1053
override def typedClassDef (cdef : untpd.TypeDef , cls : ClassSymbol )(using Context ): Tree =
1024
- try super .typedClassDef(cdef, cls)
1025
- finally dropConstructorProxies(cls)
1054
+ if cls.is(Flags .Erased ) then erasedDef(cls)
1055
+ else
1056
+ try super .typedClassDef(cdef, cls)
1057
+ finally dropConstructorProxies(cls)
1026
1058
1027
1059
override def typedAnnotated (tree : untpd.Annotated , pt : Type )(using Context ): Tree =
1028
1060
typed(tree.arg, pt)
0 commit comments