@@ -13,6 +13,7 @@ import core.Names._
1313import core .StdNames ._
1414import core .NameOps ._
1515import core .NameKinds .{AdaptedClosureName , BodyRetainerName }
16+ import core .Scopes .newScopeWith
1617import core .Decorators ._
1718import core .Constants ._
1819import core .Definitions ._
@@ -81,16 +82,22 @@ class Erasure extends Phase with DenotTransformer {
8182 val oldName = ref.name
8283 val newName = ref.targetName
8384 val oldInfo = ref.info
84- val newInfo = transformInfo(oldSymbol, oldInfo)
85+ var newInfo = transformInfo(oldSymbol, oldInfo)
8586 val oldFlags = ref.flags
8687 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
8889 else oldFlags
8990 val oldAnnotations = ref.annotations
9091 var newAnnotations = oldAnnotations
9192 if oldSymbol.isRetainedInlineMethod then
9293 newFlags = newFlags &~ Flags .Inline
9394 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 _ =>
94101 // TODO: define derivedSymDenotation?
95102 if ref.is(Flags .PackageClass )
96103 || ! ref.isClass // non-package classes are always copied since their base types change
@@ -125,6 +132,12 @@ class Erasure extends Phase with DenotTransformer {
125132 unit.tpdTree = eraser.typedExpr(unit.tpdTree)(using ctx.fresh.setTyper(eraser).setPhase(this .next))
126133 }
127134
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+
128141 override def checkPostCondition (tree : tpd.Tree )(using Context ): Unit = {
129142 assertErased(tree)
130143 tree match {
@@ -587,15 +600,30 @@ object Erasure {
587600 checkNotErasedClass(tree)
588601 }
589602
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+
590614 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)
593616 tree
594617
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
599627
600628 def erasedType (tree : untpd.Tree )(using Context ): Type = {
601629 val tp = tree.typeOpt
@@ -874,6 +902,7 @@ object Erasure {
874902 override def typedValDef (vdef : untpd.ValDef , sym : Symbol )(using Context ): Tree =
875903 if (sym.isEffectivelyErased) erasedDef(sym)
876904 else
905+ checkNotErasedClass(sym.info, vdef)
877906 super .typedValDef(untpd.cpy.ValDef (vdef)(
878907 tpt = untpd.TypedSplice (TypeTree (sym.info).withSpan(vdef.tpt.span))), sym)
879908
@@ -885,6 +914,7 @@ object Erasure {
885914 if sym.isEffectivelyErased || sym.name.is(BodyRetainerName ) then
886915 erasedDef(sym)
887916 else
917+ checkNotErasedClass(sym.info.finalResultType, ddef)
888918 val restpe = if sym.isConstructor then defn.UnitType else sym.info.resultType
889919 var vparams = outerParamDefs(sym)
890920 ::: ddef.paramss.collect {
@@ -1021,8 +1051,10 @@ object Erasure {
10211051 if mbr.is(ConstructorProxy ) then mbr.dropAfter(erasurePhase)
10221052
10231053 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)
10261058
10271059 override def typedAnnotated (tree : untpd.Annotated , pt : Type )(using Context ): Tree =
10281060 typed(tree.arg, pt)
0 commit comments