Skip to content

Commit fc859b6

Browse files
committed
Disallow Phantom types in casts
1 parent d02bf3b commit fc859b6

File tree

4 files changed

+101
-0
lines changed

4 files changed

+101
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Compiler {
4949
List(new FirstTransform, // Some transformations to put trees into a canonical form
5050
new CheckReentrant), // Internal use only: Check that compiled program has no data races involving global vars
5151
List(new CheckStatic, // Check restrictions that apply to @static members
52+
new CheckPhantomCast, // Checks that no Phantom types in are in casts
5253
new ElimRepeated, // Rewrite vararg parameters and arguments
5354
new RefChecks, // Various checks mostly related to abstract members and overriding
5455
new NormalizeFlags, // Rewrite some definition flags
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
6+
import Types._
7+
import Contexts.Context
8+
import Symbols._
9+
import Decorators._
10+
import dotty.tools.dotc.ast.tpd
11+
12+
13+
/** A no-op transform that checks whether the compiled sources have no Phantom types in casts */
14+
class CheckPhantomCast extends MiniPhaseTransform { thisTransformer =>
15+
16+
override def phaseName = "checkPhantomCast"
17+
18+
override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
19+
if (tree.fun.symbol eq defn.Any_asInstanceOf)
20+
checkNoPhantoms(tree.args.head)
21+
tree
22+
}
23+
24+
private def checkNoPhantoms(tpTree: tpd.Tree)(implicit ctx: Context): Unit = {
25+
val checker = new TypeMap {
26+
override def apply(tp: Type): Type = {
27+
if (tp.isPhantom) {
28+
ctx.error("Cannot cast type containing a phantom type", tpTree.pos)
29+
tp
30+
} else mapOver(tp)
31+
}
32+
}
33+
34+
checker(tpTree.tpe)
35+
}
36+
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Boo._
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
val a = new Bar()
6+
foo(a.asInstanceOf[Foo{type T = BooNothing}].y) // error
7+
8+
val b = new Baz
9+
b.asInstanceOf[Foo{type T = BooAny}].z(any) // error
10+
}
11+
12+
def foo(x: BooNothing) = println("foo")
13+
14+
}
15+
16+
abstract class Foo {
17+
type T <: BooAny
18+
def y: T
19+
def z(z: T) = ()
20+
}
21+
22+
class Bar {
23+
type T = BooAny
24+
def y: T = any
25+
def z(z: T) = ()
26+
}
27+
28+
class Baz {
29+
type T = BooNothing
30+
def z(z: T) = ()
31+
}
32+
33+
object Boo extends Phantom {
34+
type BooAny = this.Any
35+
type BooNothing = this.Nothing
36+
def any: BooAny = assume
37+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Boo._
2+
3+
object Test {
4+
def main(args: Array[String]): Unit = {
5+
val a = new Foo[BooAny](any)
6+
foo(a.asInstanceOf[Foo[BooNothing]].x) // error
7+
foo(a.asInstanceOf[Foo[BooNothing]].y) // error
8+
9+
val b = new Foo[BooNothing](a.asInstanceOf[Foo[BooNothing]].x) // error
10+
b.asInstanceOf[Foo[BooAny]].z(any) // error
11+
}
12+
13+
def foo(x: BooNothing) = println("foo")
14+
15+
}
16+
17+
class Foo[T <: BooAny](val x: T) {
18+
def y: T = x
19+
def z(z: T) = ()
20+
}
21+
22+
object Boo extends Phantom {
23+
type BooAny = this.Any
24+
type BooNothing = this.Nothing
25+
def any: BooAny = assume
26+
}

0 commit comments

Comments
 (0)