diff options
-rw-r--r-- | src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 31 | ||||
-rw-r--r-- | tests/run/i1354.check | 6 | ||||
-rw-r--r-- | tests/run/i1354.scala | 27 |
3 files changed, 56 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index c57d6fd1a..6de2bf44c 100644 --- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -1,16 +1,12 @@ package dotty.tools.dotc package transform -import TreeTransforms._ -import core.Denotations._ -import core.SymDenotations._ import core.Contexts._ import core.Symbols._ import core.Types._ import core.Constants._ import core.StdNames._ import core.TypeErasure.isUnboundedGeneric -import typer.ErrorReporting._ import ast.Trees._ import Erasure.Boxing._ import core.TypeErasure._ @@ -92,14 +88,33 @@ trait TypeTestsCasts { unbox(qual.ensureConforms(defn.ObjectType), argType) else if (isDerivedValueClass(argCls)) { qual // adaptToType in Erasure will do the necessary type adaptation - } else + } + else derivedTree(qual, defn.Any_asInstanceOf, argType) } - def erasedArg = erasure(tree.args.head.tpe) + + /** Transform isInstanceOf OrType + * + * expr.isInstanceOf[A | B] ~~> expr.isInstanceOf[A] | expr.isInstanceOf[B] + * + * The transform happens before erasure of `argType`, thus cannot be merged + * with `transformIsInstanceOf`, which depends on erased type of `argType`. + */ + def transformOrTypeTest(qual: Tree, argType: Type): Tree = argType match { + case OrType(tp1, tp2) => + evalOnce(qual) { fun => + transformOrTypeTest(fun, tp1) + .select(nme.OR) + .appliedTo(transformOrTypeTest(fun, tp2)) + } + case _ => + transformIsInstanceOf(qual, erasure(argType)) + } + if (sym eq defn.Any_isInstanceOf) - transformIsInstanceOf(qual, erasedArg) + transformOrTypeTest(qual, tree.args.head.tpe) else if (sym eq defn.Any_asInstanceOf) - transformAsInstanceOf(erasedArg) + transformAsInstanceOf(erasure(tree.args.head.tpe)) else tree case _ => diff --git a/tests/run/i1354.check b/tests/run/i1354.check new file mode 100644 index 000000000..ce686866d --- /dev/null +++ b/tests/run/i1354.check @@ -0,0 +1,6 @@ +0 +false +5 +1 +true +true diff --git a/tests/run/i1354.scala b/tests/run/i1354.scala new file mode 100644 index 000000000..08b129e4e --- /dev/null +++ b/tests/run/i1354.scala @@ -0,0 +1,27 @@ +object Test { + def foo(a: Int | Double) = a match { + case a: (Float | Boolean) => 1 + case _ => 0 + } + + def typeTest(a: Int | Double) = a.isInstanceOf[Float | Boolean] // false + + def typeCast(a: Int | Double) = a.asInstanceOf[Float | Boolean] // no error + + def main(args: Array[String]): Unit = { + println(foo(4)) + + println(typeTest(4)) + + println(typeCast(5)) + + Boolean.box(true) match { + case a: (Float | Boolean) => println(1) + case _ => println(0) + } + + println(Boolean.box(true).isInstanceOf[Float | Boolean]) + + println(Boolean.box(true).asInstanceOf[Float | Boolean]) + } +} |