Skip to content

Commit 1146d31

Browse files
committed
Add support for non pure methods returning phantoms.
1 parent a555852 commit 1146d31

8 files changed

+148
-1
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ class Compiler {
7474
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
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
77-
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
77+
new ArrayConstructors, // Intercept creation of (non-generic) arrays and intrinsify.
78+
new PhantomTermEval), // Extracts the evaluation of phantom arguments placing them before the call.
7879
List(new PhantomTermErasure), // Erases phantom parameters and arguments
7980
List(new PhantomTypeErasure), // Erases phantom types to ErasedPhantom
8081
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dotty.tools.dotc.transform.phantom
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts._
5+
import dotty.tools.dotc.core.Decorators._
6+
import dotty.tools.dotc.core.Types._
7+
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
8+
9+
class PhantomTermEval extends MiniPhaseTransform {
10+
import tpd._
11+
12+
override def phaseName: String = "phantomTermEval"
13+
14+
/** Check what the phase achieves, to be called at any point after it is finished. */
15+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
16+
// TODO
17+
}
18+
19+
/* Tree transform */
20+
21+
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = tree.tpe match {
22+
case _: MethodType => tree
23+
case _ if tree.args.forall(!_.tpe.isPhantom) => tree
24+
case _ =>
25+
val argsVals = tree.args.map(toSynthVal)
26+
27+
def evalArgsInBlock() = Block(argsVals, cpy.Apply(tree)(tree.fun, refs(argsVals)))
28+
def evalFunAndArgsInBlock(fun: Select) = {
29+
val qualVal = toSynthVal(fun.qualifier)
30+
val app = cpy.Apply(tree)(Select(ref(qualVal.symbol), fun.name), refs(argsVals))
31+
Block(qualVal :: argsVals, app)
32+
}
33+
34+
tree.fun match {
35+
case fun: Select =>
36+
if (fun.qualifier.isInstanceOf[New]) evalArgsInBlock()
37+
else evalFunAndArgsInBlock(fun)
38+
case _ => evalArgsInBlock()
39+
}
40+
}
41+
42+
/* private methods */
43+
44+
private def toSynthVal(t: Tree)(implicit ctx: Context) =
45+
SyntheticValDef(ctx.freshName("ev$").toTermName, t)
46+
47+
private def refs(vals: List[Tree])(implicit ctx: Context) =
48+
vals.map(x => ref(x.symbol))
49+
50+
}

tests/run/phantom-methods-10.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fun
2+
inky
3+
pacFun4

tests/run/phantom-methods-10.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* Run this test with
2+
* `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure`
3+
* to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure.
4+
*/
5+
6+
object Test {
7+
import Boo._
8+
9+
def main(args: Array[String]): Unit = {
10+
fun2.pacFun4(inky)
11+
}
12+
13+
def pacFun4(clyde: Inky) = {
14+
println("pacFun4")
15+
}
16+
17+
def inky: Inky = {
18+
println("inky")
19+
boo[Inky]
20+
}
21+
22+
def fun2 = {
23+
println("fun")
24+
this
25+
}
26+
}
27+
28+
object Boo extends Phantom {
29+
type Inky <: this.Any
30+
def boo[B <: this.Any]: B = assume[B]
31+
}

tests/run/phantom-methods-8.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
inky
2+
pacFun4

tests/run/phantom-methods-8.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* Run this test with
2+
* `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure`
3+
* to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure.
4+
*/
5+
6+
object Test {
7+
import Boo._
8+
9+
def main(args: Array[String]): Unit = {
10+
pacFun4(inky)
11+
}
12+
13+
def pacFun4(clyde: Inky) = {
14+
println("pacFun4")
15+
}
16+
17+
def inky: Inky = {
18+
println("inky")
19+
Boo.boo[Inky]
20+
}
21+
}
22+
23+
object Boo extends Phantom {
24+
type Inky <: Boo.Any
25+
def boo[B <: Boo.Any]: B = assume[B]
26+
}

tests/run/phantom-methods-9.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fun
2+
inky
3+
pacFun4

tests/run/phantom-methods-9.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* Run this test with
2+
* `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure`
3+
* to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure.
4+
*/
5+
6+
object Test {
7+
import Boo._
8+
9+
def main(args: Array[String]): Unit = {
10+
fun1().pacFun4(inky)
11+
}
12+
13+
def pacFun4(clyde: Inky) = {
14+
println("pacFun4")
15+
}
16+
17+
def inky: Inky = {
18+
println("inky")
19+
boo[Inky]
20+
}
21+
22+
def fun1() = {
23+
println("fun")
24+
this
25+
}
26+
}
27+
28+
object Boo extends Phantom {
29+
type Inky <: Boo.Any
30+
def boo[B <: Boo.Any]: B = assume[B]
31+
}

0 commit comments

Comments
 (0)