Skip to content

Commit a555852

Browse files
committed
Erase arguments of phantom type.
1 parent 7c574fe commit a555852

File tree

5 files changed

+71
-1
lines changed

5 files changed

+71
-1
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Compiler {
7575
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
7676
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
7777
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
78+
List(new PhantomTermErasure), // Erases phantom parameters and arguments
7879
List(new PhantomTypeErasure), // Erases phantom types to ErasedPhantom
7980
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
8081
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import config.Printers.config
1313
import scala.collection.mutable.{ListBuffer, ArrayBuffer}
1414
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform}
1515
import dotty.tools.dotc.transform._
16+
import dotty.tools.dotc.transform.phantom._
1617
import Periods._
1718
import typer.{FrontEnd, RefChecks}
1819
import ast.tpd
@@ -309,6 +310,7 @@ object Phases {
309310

310311
private var myPeriod: Period = Periods.InvalidPeriod
311312
private var myBase: ContextBase = null
313+
private var myErasedPhantomTerms = false
312314
private var myErasedTypes = false
313315
private var myFlatClasses = false
314316
private var myRefChecked = false
@@ -326,6 +328,7 @@ object Phases {
326328
def start = myPeriod.firstPhaseId
327329
def end = myPeriod.lastPhaseId
328330

331+
final def erasedPhantomTerms = myErasedPhantomTerms // Phase is after phantom terms
329332
final def erasedTypes = myErasedTypes // Phase is after erasure
330333
final def flatClasses = myFlatClasses // Phase is after flatten
331334
final def refChecked = myRefChecked // Phase is after RefChecks
@@ -337,6 +340,7 @@ object Phases {
337340
assert(myPeriod == Periods.InvalidPeriod, s"phase $this has already been used once; cannot be reused")
338341
myBase = base
339342
myPeriod = Period(NoRunId, start, end)
343+
myErasedPhantomTerms = prev.getClass == classOf[PhantomTermErasure] || prev.erasedPhantomTerms
340344
myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes
341345
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
342346
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package dotty.tools.dotc.transform.phantom
2+
3+
import dotty.tools.dotc.ast.Trees._
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Constants._
6+
import dotty.tools.dotc.core.Contexts._
7+
import dotty.tools.dotc.core.DenotTransformers._
8+
import dotty.tools.dotc.core.Flags._
9+
import dotty.tools.dotc.core.Symbols._
10+
import dotty.tools.dotc.core.Types._
11+
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
12+
13+
class PhantomTermErasure extends MiniPhaseTransform with InfoTransformer {
14+
import tpd._
15+
16+
override def phaseName: String = "phantomTermErasure"
17+
18+
/** Check what the phase achieves, to be called at any point after it is finished. */
19+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
20+
def assertNotPhantom(tree: Tree): Unit =
21+
assert(!tree.tpe.isPhantom, "All phantom type values should be erased in " + tree)
22+
tree match {
23+
case Apply(_, args) => args.foreach(assertNotPhantom)
24+
case DefDef(_, _, vparamss, tpt, _) => vparamss.foreach(_.foreach(assertNotPhantom))
25+
case _ =>
26+
}
27+
}
28+
29+
/* Tree transform */
30+
31+
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
32+
cpy.Apply(tree)(tree.fun, tree.args.filter(!_.tpe.isPhantom))
33+
34+
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree =
35+
cpy.DefDef(ddef)(vparamss = ddef.vparamss.map(_.filter(!_.tpt.typeOpt.isPhantom)))
36+
37+
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
38+
if (tree.symbol.is(Param) && tree.tpe.isPhantom) Literal(Constant(null)).withType(tree.tpe) else tree
39+
40+
/* Symbol transform */
41+
42+
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = erasedPhantomParameters(tp)
43+
44+
/* private methods */
45+
46+
private def erasedPhantomParameters(tp: Type)(implicit ctx: Context): Type = tp match {
47+
case tp: JavaMethodType => tp
48+
case tp: MethodType =>
49+
val methodType = if (tp.isImplicit) ImplicitMethodType else MethodType
50+
val (erasedParamNames, erasedParamTypes) =
51+
tp.paramNames.zip(tp.paramTypes).filterNot(_._2.isPhantom).unzip
52+
val erasedReturnType = erasedPhantomParameters(tp.resultType)
53+
methodType(erasedParamNames, erasedParamTypes, erasedReturnType)
54+
case tp: PolyType =>
55+
val erasedReturnType = erasedPhantomParameters(tp.resultType)
56+
tp.derivedPolyType(tp.paramNames, tp.paramBounds, erasedReturnType)
57+
case _ => tp
58+
}
59+
}

compiler/src/dotty/tools/dotc/transform/phantom/PhantomTypeErasure.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dotty.tools.dotc.ast.tpd
44
import dotty.tools.dotc.core.Constants.Constant
55
import dotty.tools.dotc.core.Contexts._
66
import dotty.tools.dotc.core.DenotTransformers._
7+
import dotty.tools.dotc.core.Phases._
78
import dotty.tools.dotc.core.Symbols._
89
import dotty.tools.dotc.core.Types._
910
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
@@ -14,6 +15,9 @@ class PhantomTypeErasure extends MiniPhaseTransform with InfoTransformer {
1415

1516
override def phaseName: String = "phantomTypeErasure"
1617

18+
/** List of names of phases that should precede this phase */
19+
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[PhantomTermErasure])
20+
1721
/** Check what the phase achieves, to be called at any point after it is finished. */
1822
override def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = {
1923
assert(!tree.tpe.isPhantom, tree.tpe + " should be erased in " + tree)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,9 @@ trait TypeAssigner {
316316
def assignType(tree: untpd.Apply, fn: Tree, args: List[Tree])(implicit ctx: Context) = {
317317
val ownType = fn.tpe.widen match {
318318
case fntpe @ MethodType(_, ptypes) =>
319-
if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes)
319+
def sameLengthAfterPhantomErasure =
320+
ctx.phase.erasedPhantomTerms && sameLength(ptypes, args.filterNot(arg => arg.typeOpt.isPhantom))
321+
if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping || sameLengthAfterPhantomErasure) fntpe.instantiate(args.tpes)
320322
else
321323
errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${ptypes.length}, found: ${args.length}", tree.pos)
322324
case t =>

0 commit comments

Comments
 (0)