-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2399 from dotty-staging/implement-phantom-types-p…
…art-2 Erase arguments of phantom type
- Loading branch information
Showing
21 changed files
with
455 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
compiler/src/dotty/tools/dotc/transform/PhantomArgLift.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package dotty.tools.dotc.transform | ||
|
||
import dotty.tools.dotc.ast.tpd | ||
import dotty.tools.dotc.core.Contexts._ | ||
import dotty.tools.dotc.core.NameKinds._ | ||
import dotty.tools.dotc.core.Types._ | ||
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo} | ||
import dotty.tools.dotc.typer.EtaExpansion | ||
|
||
import scala.collection.mutable.ListBuffer | ||
|
||
/** This phase extracts the arguments of phantom type before the application to avoid losing any | ||
* effects in the argument tree. This trivializes the removal of parameter in the Erasure phase. | ||
* | ||
* `f(x1,...)(y1,...)...(...)` with at least one phantom argument | ||
* | ||
* --> | ||
* | ||
* `val ev$f = f` // if `f` is some expression that needs evaluation | ||
* `val ev$x1 = x1` | ||
* ... | ||
* `val ev$y1 = y1` | ||
* ... | ||
* `ev$f(ev$x1,...)(ev$y1,...)...(...)` | ||
* | ||
*/ | ||
class PhantomArgLift extends MiniPhaseTransform { | ||
import tpd._ | ||
|
||
override def phaseName: String = "phantomArgLift" | ||
|
||
/** Check what the phase achieves, to be called at any point after it is finished. */ | ||
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match { | ||
case tree: Apply => | ||
tree.args.foreach { arg => | ||
assert(!arg.tpe.isPhantom || isPureExpr(arg)) | ||
} | ||
case _ => | ||
} | ||
|
||
/* Tree transform */ | ||
|
||
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = tree.tpe.widen match { | ||
case _: MethodType => tree // Do the transformation higher in the tree if needed | ||
case _ => | ||
if (!hasImpurePhantomArgs(tree)) tree | ||
else { | ||
val buffer = ListBuffer.empty[Tree] | ||
val app = EtaExpansion.liftApp(buffer, tree) | ||
if (buffer.isEmpty) app | ||
else Block(buffer.result(), app) | ||
} | ||
} | ||
|
||
/* private methods */ | ||
|
||
/** Returns true if at least on of the arguments is an impure phantom. | ||
* Inner applies are also checked in case of multiple parameter list. | ||
*/ | ||
private def hasImpurePhantomArgs(tree: Apply)(implicit ctx: Context): Boolean = { | ||
tree.args.exists(arg => arg.tpe.isPhantom && !isPureExpr(arg)) || { | ||
tree.fun match { | ||
case fun: Apply => hasImpurePhantomArgs(fun) | ||
case _ => false | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
class phantomOverload2 { | ||
import Boo._ | ||
|
||
def foo1() = ??? | ||
def foo1(x: A) = ??? // error | ||
def foo1(x1: B)(x2: N) = ??? // error | ||
|
||
def foo2(x1: Int, x2: A) = ??? | ||
def foo2(x1: A)(x2: Int) = ??? // error | ||
def foo2(x1: N)(x2: A)(x3: Int) = ??? // error | ||
|
||
def foo3(x1: Int, x2: A) = ??? | ||
def foo3(x1: Int, x2: A)(x3: A) = ??? // error | ||
} | ||
|
||
object Boo extends Phantom { | ||
type A <: this.Any | ||
type B <: this.Any | ||
type N = this.Nothing | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
object PhantomInValueClass { | ||
import BooUtil._ | ||
new VC("ghi").foo(boo) | ||
} | ||
|
||
object BooUtil extends Phantom { | ||
|
||
type Boo <: this.Any | ||
def boo: Boo = assume | ||
|
||
class VC[T](val x: T) extends AnyVal { | ||
def foo(b: Boo) = println(x) | ||
} | ||
|
||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import dotty.runtime.ErasedPhantom | ||
|
||
/* Run this test with | ||
* `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomTermErasure,phantomTypeErasure,erasure` | ||
* to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. | ||
*/ | ||
|
||
object Test { | ||
import Boo._ | ||
|
||
def main(args: Array[String]): Unit = { | ||
val foo = new Foo | ||
|
||
// check that parameters have been removed from the functions | ||
// (would fail with NoSuchMethodException if not erased) | ||
foo.getClass.getDeclaredMethod("fun1") | ||
foo.getClass.getDeclaredMethod("fun2", classOf[String]) | ||
|
||
assert(foo.getClass.getDeclaredMethod("fun3").getReturnType == classOf[ErasedPhantom]) | ||
} | ||
} | ||
|
||
class Foo { | ||
import Boo._ | ||
def fun1(b: BooAny): Unit = () | ||
def fun2(b: BooAny, s: String): Unit = () | ||
def fun3(): BooAny = boo | ||
} | ||
|
||
object Boo extends Phantom { | ||
type BooAny = Boo.Any | ||
def boo: BooAny = assume | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
x1 | ||
x2 | ||
x3 | ||
x4 | ||
x5 | ||
fun | ||
y1 | ||
y2 | ||
y3 | ||
y4 | ||
y5 | ||
Fun | ||
Fun2 | ||
z1 | ||
z2 | ||
z3 | ||
z4 | ||
z5 | ||
Fun2fun | ||
Fun2 | ||
w1 | ||
w2 | ||
w3 | ||
w4 | ||
w5 | ||
Fun2fun2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* Run this test with | ||
* `run tests/run/xyz.scala -Xprint-diff-del -Xprint:arrayConstructors,phantomRefErasure,phantomErasure,erasure` | ||
* to see the the diffs after PhantomRefErasure, PhantomDeclErasure and Erasure. | ||
*/ | ||
|
||
object Test { | ||
import Boo._ | ||
|
||
def main(args: Array[String]): Unit = { | ||
fun( | ||
{ println("x1"); boo }, | ||
{ println("x2"); boo } | ||
)( | ||
{ println("x3"); boo } | ||
)( | ||
{ println("x4"); boo }, | ||
{ println("x5"); boo } | ||
) | ||
|
||
new Fun( | ||
{ println("y1"); boo }, | ||
{ println("y2"); boo } | ||
)( | ||
{ println("y3"); boo } | ||
)( | ||
{ println("y4"); boo }, | ||
{ println("y5"); boo } | ||
) | ||
|
||
(new Fun2().fun)( | ||
{ println("z1"); boo }, | ||
{ println("z2"); boo } | ||
)( | ||
{ println("z3"); boo } | ||
)( | ||
{ println("z4"); boo }, | ||
{ println("z5"); boo } | ||
) | ||
|
||
(new Fun2().fun2)( | ||
{ println("w1"); boo }, | ||
{ println("w2"); boo } | ||
)( | ||
{ println("w3"); boo } | ||
)( | ||
{ println("w4"); boo }, | ||
{ println("w5"); boo } | ||
) | ||
} | ||
|
||
def fun(x1: Inky, x2: Inky)(x3: Inky)(x4: Inky, x5: Inky) = { | ||
println("fun") | ||
} | ||
|
||
class Fun(y1: Inky, y2: Inky)(y3: Inky)(y4: Inky, y5: Inky) { | ||
println("Fun") | ||
} | ||
|
||
class Fun2 { | ||
println("Fun2") | ||
def fun(z1: Inky, z2: Inky)(z3: Inky)(z4: Inky, z5: Inky) = { | ||
println("Fun2fun") | ||
} | ||
|
||
def fun2[T](z1: Inky, z2: Inky)(z3: Inky)(z4: Inky, z5: Inky) = { | ||
println("Fun2fun2") | ||
} | ||
} | ||
} | ||
|
||
object Boo extends Phantom { | ||
type Inky <: this.Any | ||
def boo: Inky = assume | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
x1 | ||
x2 | ||
x3 | ||
x4 | ||
x5 | ||
fun1 | ||
y1 | ||
y2 | ||
y3 | ||
y4 | ||
y5 | ||
fun2 | ||
z1 | ||
z2 | ||
z3 | ||
z4 | ||
z5 | ||
fun3 |
Oops, something went wrong.