Skip to content

Commit 36a4048

Browse files
committed
WIP: split phantom erasure into reference and declaration erasure.
1 parent 5beafb8 commit 36a4048

File tree

7 files changed

+107
-56
lines changed

7 files changed

+107
-56
lines changed

src/dotty/tools/dotc/Compiler.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class Compiler {
7272
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
7373
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
7474
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
75-
List(new PhantomErasure), // Rewrite trees erasing all values of phantom types.
75+
List(new PhantomRefErasure), // Rewrite trees erasing all value references of phantom types.
76+
List(new PhantomDeclErasure), // Rewrite trees erasing all phantom types declarations.
7677
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
7778
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types
7879
new VCElideAllocations, // Peep-hole optimization to eliminate unnecessary value class allocations

src/dotty/tools/dotc/core/Phases.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ object Phases {
302302

303303
private var myPeriod: Period = Periods.InvalidPeriod
304304
private var myBase: ContextBase = null
305-
private var myErasedPhantoms = false
305+
private var myErasedRefPhantoms = false
306306
private var myErasedTypes = false
307307
private var myFlatClasses = false
308308
private var myRefChecked = false
@@ -320,7 +320,7 @@ object Phases {
320320
def start = myPeriod.firstPhaseId
321321
def end = myPeriod.lastPhaseId
322322

323-
final def erasedPhantoms = myErasedPhantoms // Phase is after phantom erasure
323+
final def erasedRefPhantoms = myErasedRefPhantoms // Phase is after phantom reference erasure
324324
final def erasedTypes = myErasedTypes // Phase is after erasure
325325
final def flatClasses = myFlatClasses // Phase is after flatten
326326
final def refChecked = myRefChecked // Phase is after RefChecks
@@ -332,7 +332,7 @@ object Phases {
332332
assert(myPeriod == Periods.InvalidPeriod, s"phase $this has already been used once; cannot be reused")
333333
myBase = base
334334
myPeriod = Period(NoRunId, start, end)
335-
myErasedPhantoms = prev.getClass == classOf[PhantomErasure] || prev.erasedPhantoms
335+
myErasedRefPhantoms = prev.getClass == classOf[PhantomRefErasure] || prev.erasedRefPhantoms
336336
myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes
337337
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
338338
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked

src/dotty/tools/dotc/transform/Erasure.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
3232
override def phaseName: String = "erasure"
3333

3434
/** List of names of phases that should precede this phase */
35-
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[PhantomErasure], classOf[InterceptedMethods], classOf[Splitter], classOf[ElimRepeated])
35+
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[PhantomDeclErasure], classOf[InterceptedMethods], classOf[Splitter], classOf[ElimRepeated])
3636

3737
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
3838
case ref: SymDenotation =>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core.Phases._
5+
import core.DenotTransformers._
6+
import core.Symbols._
7+
import core.Contexts._
8+
import core.Types._
9+
import core.Decorators._
10+
import dotty.tools.dotc.ast.{Trees, tpd}
11+
import ast.Trees._
12+
13+
import dotty.tools.dotc.core.Flags
14+
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo, TreeTransform}
15+
16+
import scala.annotation.tailrec
17+
18+
class PhantomDeclErasure extends MiniPhaseTransform with InfoTransformer {
19+
thisTransformer =>
20+
21+
import dotty.tools.dotc.ast.tpd._
22+
23+
override def phaseName: String = "phantomDeclErasure"
24+
25+
/** List of names of phases that should precede this phase */
26+
override def runsAfter: Set[Class[_ <: Phase]] =
27+
Set(classOf[PhantomRefErasure])
28+
29+
/** Check what the phase achieves, to be called at any point after it is finished.
30+
*/
31+
override def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = {
32+
def assertNotPhantom(tpe: Type): Unit =
33+
assert(!tpe.derivesFrom(defn.PhantomAnyClass), "All phantom type values should be erased in " + tree)
34+
35+
tree match {
36+
case _: TypeTree =>
37+
case _: Trees.TypeDef[_] =>
38+
case tree: TypeDef => tree.symbol.asClass.classInfo.decls // TODO check decls
39+
case ValDef(_, tpt, _) => assertNotPhantom(tpt.typeOpt)
40+
case DefDef(_, _, _, tpt, _) => assertNotPhantom(tpt.typeOpt)
41+
case _ =>
42+
}
43+
super.checkPostCondition(tree)
44+
}
45+
46+
// Transform trees
47+
48+
override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
49+
val newTrees = trees.filter {
50+
case ValDef(_, tpt, _) =>
51+
!tpt.tpe.derivesFrom(defn.PhantomAnyClass)
52+
53+
case tree @ DefDef(_, _, _, tpt, _) =>
54+
val isPhantom = tpt.tpe.derivesFrom(defn.PhantomAnyClass)
55+
if (isPhantom && tree.symbol.flags.is(Flags.Accessor)) {
56+
if (tree.symbol.flags.is(Flags.Mutable))
57+
ctx.error("Can not define var with phantom type.", tree.pos)
58+
else if (tree.symbol.flags.is(Flags.Lazy))
59+
ctx.error("Can not define lazy var with phantom type.", tree.pos)
60+
}
61+
!isPhantom
62+
63+
case _ =>
64+
true
65+
}
66+
super.transformStats(newTrees)
67+
}
68+
69+
// Transform symbols
70+
71+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = erasedPhantoms(tp)
72+
73+
private def erasedPhantoms(tp: Type)(implicit ctx: Context): Type = {
74+
val flags = tp.typeSymbol.flags
75+
tp match {
76+
case tp: ClassInfo if !flags.is(Flags.Package) =>
77+
val newDecls = tp.decls.filteredScope(sym => !isPhantomMethodType(sym.info))
78+
ClassInfo(tp.prefix, tp.cls, tp.classParents, newDecls, tp.selfInfo)
79+
80+
case _ => tp
81+
}
82+
}
83+
84+
@tailrec private def isPhantomMethodType(tpe: Type)(implicit ctx: Context): Boolean = tpe match {
85+
case tpe: MethodicType => tpe.resultType.derivesFrom(defn.PhantomAnyClass) || isPhantomMethodType(tpe.resultType)
86+
case _ => false
87+
}
88+
}

src/dotty/tools/dotc/transform/PhantomErasure.scala renamed to src/dotty/tools/dotc/transform/PhantomRefErasure.scala

+11-49
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, Transforme
1515

1616
import scala.annotation.tailrec
1717

18-
class PhantomErasure extends MiniPhaseTransform with InfoTransformer {
18+
class PhantomRefErasure extends MiniPhaseTransform with InfoTransformer {
1919
thisTransformer =>
2020

2121
import dotty.tools.dotc.ast.tpd._
2222

23-
override def phaseName: String = "phantomErasure"
23+
override def phaseName: String = "phantomRefErasure"
2424

2525
/** List of names of phases that should precede this phase */
2626
override def runsAfter: Set[Class[_ <: Phase]] =
@@ -35,9 +35,6 @@ class PhantomErasure extends MiniPhaseTransform with InfoTransformer {
3535
tree match {
3636
case _: TypeTree =>
3737
case _: Trees.TypeDef[_] =>
38-
case tree: TypeDef => tree.symbol.asClass.classInfo.decls // TODO check decls
39-
case ValDef(_, tpt, _) => assertNotPhantom(tpt.typeOpt)
40-
case DefDef(_, _, _, tpt, _) => assertNotPhantom(tpt.typeOpt)
4138
case _ => assertNotPhantom(tree.tpe)
4239
}
4340
super.checkPostCondition(tree)
@@ -46,34 +43,16 @@ class PhantomErasure extends MiniPhaseTransform with InfoTransformer {
4643
// Transform trees
4744

4845
override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
49-
val newTrees = trees.filter {
50-
case ValDef(_, tpt, _) =>
51-
!tpt.tpe.derivesFrom(defn.PhantomAnyClass)
52-
53-
case tree @ DefDef(_, _, _, tpt, _) =>
54-
val isPhantom = tpt.tpe.derivesFrom(defn.PhantomAnyClass)
55-
if (isPhantom && tree.symbol.flags.is(Flags.Accessor)) {
56-
if (tree.symbol.flags.is(Flags.Mutable))
57-
ctx.error("Can not define var with phantom type.", tree.pos)
58-
else if (tree.symbol.flags.is(Flags.Lazy))
59-
ctx.error("Can not define lazy var with phantom type.", tree.pos)
60-
}
61-
!isPhantom
62-
46+
trees.foreach {
6347
case tree @ Apply(fun, _) if tree.tpe.derivesFrom(defn.PhantomAnyClass) =>
6448
ctx.error(s"Functions returning a phantom type can not be in statement position.", fun.pos)
65-
false
6649
case tree @ TypeApply(fun, _) if tree.tpe.derivesFrom(defn.PhantomAnyClass) =>
6750
ctx.error(s"Functions returning a phantom type can not be in statement position.", fun.pos)
68-
false
6951
case tree: Select if tree.tpe.derivesFrom(defn.PhantomAnyClass) =>
7052
ctx.error(s"Fields containing a phantom type can not be accessed in statement position.", tree.pos)
71-
false
72-
7353
case _ =>
74-
true
7554
}
76-
super.transformStats(newTrees)
55+
super.transformStats(trees)
7756
}
7857

7958
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
@@ -117,21 +96,11 @@ class PhantomErasure extends MiniPhaseTransform with InfoTransformer {
11796

11897
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = erasedPhantoms(tp)
11998

120-
private def erasedPhantoms(tp: Type)(implicit ctx: Context): Type = {
121-
val flags = tp.typeSymbol.flags
122-
tp match {
123-
case tp: ClassInfo if !flags.is(Flags.Package) =>
124-
val newDecls = tp.decls.filteredScope(sym => !isPhantomMethodType(sym.info))
125-
ClassInfo(tp.prefix, tp.cls, tp.classParents, newDecls, tp.selfInfo)
126-
127-
case tp: JavaMethodType => tp
128-
case tp: MethodType => erasedMethodPhantoms(tp)
129-
130-
case tp: PolyType =>
131-
PolyType(tp.paramNames)(_ => tp.paramBounds, _ => erasedPhantoms(tp.resType))
132-
133-
case _ => tp
134-
}
99+
private def erasedPhantoms(tp: Type)(implicit ctx: Context): Type = tp match {
100+
case tp: JavaMethodType => tp
101+
case tp: MethodType => erasedMethodPhantoms(tp)
102+
case tp: PolyType => PolyType(tp.paramNames)(_ => tp.paramBounds, _ => erasedPhantoms(tp.resType))
103+
case _ => tp
135104
}
136105

137106
private def erasedMethodPhantoms(tp: MethodType)(implicit ctx: Context): MethodType = {
@@ -140,15 +109,8 @@ class PhantomErasure extends MiniPhaseTransform with InfoTransformer {
140109
else (tp.paramNames, tp.paramTypes)
141110
val erasedResultType = erasedPhantoms(tp.resultType)
142111
tp match {
143-
case _: ImplicitMethodType =>
144-
ImplicitMethodType(erasedParamNames, erasedParamTypes, erasedResultType)
145-
case _ =>
146-
MethodType(erasedParamNames, erasedParamTypes, erasedResultType)
112+
case _: ImplicitMethodType => ImplicitMethodType(erasedParamNames, erasedParamTypes, erasedResultType)
113+
case _ => MethodType(erasedParamNames, erasedParamTypes, erasedResultType)
147114
}
148115
}
149-
150-
@tailrec private def isPhantomMethodType(tpe: Type)(implicit ctx: Context): Boolean = tpe match {
151-
case tpe: MethodicType => tpe.resultType.derivesFrom(defn.PhantomAnyClass) || isPhantomMethodType(tpe.resultType)
152-
case _ => false
153-
}
154116
}

src/dotty/tools/dotc/transform/TreeChecker.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ class TreeChecker extends Phase with SymTransformer {
304304
mapOver(tp)
305305
definedBinders -= tp
306306
case tp: ParamType =>
307-
assert(definedBinders.contains(tp.binder) || (tp.derivesFrom(defn.PhantomAnyClass) && ctx.phase.erasedPhantoms), s"orphan param: $tp")
307+
assert(definedBinders.contains(tp.binder) || (tp.derivesFrom(defn.PhantomAnyClass) && ctx.phase.erasedRefPhantoms), s"orphan param: $tp")
308308
case tp: TypeVar =>
309309
apply(tp.underlying)
310310
case _ =>

src/dotty/tools/dotc/typer/TypeAssigner.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ trait TypeAssigner {
304304
val ownType = fn.tpe.widen match {
305305
case fntpe @ MethodType(_, ptypes) =>
306306
if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping ||
307-
(ctx.phase.erasedPhantoms && sameLength(ptypes, args.filterNot(_.typeOpt.derivesFrom(defn.PhantomAnyClass))))) {
307+
(ctx.phase.erasedRefPhantoms && sameLength(ptypes, args.filterNot(_.typeOpt.derivesFrom(defn.PhantomAnyClass))))) {
308308
fntpe.instantiate(args.tpes)
309309
} else {
310310
errorType(i"wrong number of parameters for ${fn.tpe}; expected: ${ptypes.length}", tree.pos)

0 commit comments

Comments
 (0)