From 5b8327b807c40cab867065cf695191a36c9210ee Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 7 May 2013 23:29:02 +0200 Subject: SI-7459 Handle pattern binders used as prefixes in TypeTrees. Match translation was incorrect for: case t => new t.C case D(t) => new d.C We would end up with Types in TypeTrees referring to the wrong symbols, e.g: // t7459a.scala ((x0$1: this.LM) => { case val x1: this.LM = x0$1; case4(){ matchEnd3(new tttt.Node[Any]()) }; matchEnd3(x: Any){ x } Or: // t7459b.scala ((x0$1: CC) => { case val x1: CC = x0$1; case4(){ if (x1.ne(null)) matchEnd3(new tttt.Node[Any]()) else case5() }; This commit: - Changes `bindSubPats` to traverse types, as well as terms, in search of references to bound symbols - Changes `Substitution` to reuse `Tree#substituteSymbols` rather than the home-brew substitution from `Tree`s to `Tree`s, if the `to` trees are all `Ident`s - extends `substIdentsForTrees` to substitute selections like `x1.caseField` into types. I had to dance around the awkward handling of "swatches" (exception handlers that can be implemented with JVM native type switches) by duplicating trees to avoid seeing the results of `substituteSymbols` in `caseDefs` after we abandon that approach if we detect the patterns are too complex late in the game. I also had to add an escape hatch for the "type selection from volatile type" check in the type checker. Without this, the translation of `pos/t7459c.scala`: case val x1: _$1 = (null: Test.Mirror[_]).universe; case5(){ if (x1.isInstanceOf[Test.JavaUniverse]) { val x2: _$1 with Test.JavaUniverse = (x1.asInstanceOf[_$1 with Test.JavaUniverse]: _$1 with Test.JavaUniverse); matchEnd4({ val ju1: Test.JavaUniverse = x2; val f: () => x2.Type = (() => (null: x2.TypeTag[Nothing]).tpe); .. triggers that error at `x2.TypeTag`. --- test/files/pos/t7459a.scala | 18 ++++++++++++++++++ test/files/pos/t7459b.scala | 12 ++++++++++++ test/files/pos/t7459c.scala | 18 ++++++++++++++++++ test/files/pos/t7459d.scala | 8 ++++++++ test/files/pos/t7704.scala | 10 ++++++++++ test/files/run/t7459a.scala | 14 ++++++++++++++ test/files/run/t7459b-optimize.flags | 1 + test/files/run/t7459b-optimize.scala | 21 +++++++++++++++++++++ test/files/run/t7459b.scala | 21 +++++++++++++++++++++ test/files/run/t7459c.scala | 16 ++++++++++++++++ test/files/run/t7459d.scala | 15 +++++++++++++++ test/files/run/t7459f.scala | 12 ++++++++++++ 12 files changed, 166 insertions(+) create mode 100644 test/files/pos/t7459a.scala create mode 100644 test/files/pos/t7459b.scala create mode 100644 test/files/pos/t7459c.scala create mode 100644 test/files/pos/t7459d.scala create mode 100644 test/files/pos/t7704.scala create mode 100644 test/files/run/t7459a.scala create mode 100644 test/files/run/t7459b-optimize.flags create mode 100644 test/files/run/t7459b-optimize.scala create mode 100644 test/files/run/t7459b.scala create mode 100644 test/files/run/t7459c.scala create mode 100644 test/files/run/t7459d.scala create mode 100644 test/files/run/t7459f.scala (limited to 'test') diff --git a/test/files/pos/t7459a.scala b/test/files/pos/t7459a.scala new file mode 100644 index 0000000000..5107715e06 --- /dev/null +++ b/test/files/pos/t7459a.scala @@ -0,0 +1,18 @@ +trait SpecialException extends Throwable + +object Test { + def run() { + try { + ??? + } catch { + case e: SpecialException => e.isInstanceOf[SpecialException] + case e => + } + + // OKAY + // (null: Throwable) match { + // case e: SpecialException => e.isInstanceOf[SpecialException] + // case e => + // } + } +} \ No newline at end of file diff --git a/test/files/pos/t7459b.scala b/test/files/pos/t7459b.scala new file mode 100644 index 0000000000..a4b4fd07a9 --- /dev/null +++ b/test/files/pos/t7459b.scala @@ -0,0 +1,12 @@ +import scala.concurrent._ +import scala.util._ + + +class Test { + (null: Any) match { + case s @ Some(_) => ??? + case f @ _ => + () => f + ??? + } +} \ No newline at end of file diff --git a/test/files/pos/t7459c.scala b/test/files/pos/t7459c.scala new file mode 100644 index 0000000000..dc2605abe6 --- /dev/null +++ b/test/files/pos/t7459c.scala @@ -0,0 +1,18 @@ +object Test { + trait Universe { + type Type + type TypeTag[A] >: Null <: TypeTagApi[A] + trait TypeTagApi[A] { def tpe: Type } + } + trait JavaUniverse extends Universe + + trait Mirror[U <: Universe] { + def universe: U + } + (null: Mirror[_]).universe match { + case ju: JavaUniverse => + val ju1 = ju + val f = {() => (null: ju.TypeTag[Nothing]).tpe } + } + trait M[A] +} diff --git a/test/files/pos/t7459d.scala b/test/files/pos/t7459d.scala new file mode 100644 index 0000000000..7843156885 --- /dev/null +++ b/test/files/pos/t7459d.scala @@ -0,0 +1,8 @@ +class Test { + (null: Any) match { + case s @ Some(_) => ??? + case f @ _ => + () => f + ??? + } +} diff --git a/test/files/pos/t7704.scala b/test/files/pos/t7704.scala new file mode 100644 index 0000000000..cae88d3324 --- /dev/null +++ b/test/files/pos/t7704.scala @@ -0,0 +1,10 @@ +class Attr { type V ; class Val } +class StrAttr extends Attr { type V = String } +class BoolAttr extends Attr { type V = Boolean } + +object Main { + def f(x: Attr) = x match { + case v: StrAttr => new v.Val + case v: BoolAttr => new v.Val + } +} diff --git a/test/files/run/t7459a.scala b/test/files/run/t7459a.scala new file mode 100644 index 0000000000..e9653c6e79 --- /dev/null +++ b/test/files/run/t7459a.scala @@ -0,0 +1,14 @@ +class LM { + class Node[B1] + case class CC(n: LM) + + // crash + val f: (LM => Any) = { + case tttt => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().f(new LM()) +} diff --git a/test/files/run/t7459b-optimize.flags b/test/files/run/t7459b-optimize.flags new file mode 100644 index 0000000000..49d036a887 --- /dev/null +++ b/test/files/run/t7459b-optimize.flags @@ -0,0 +1 @@ +-optimize diff --git a/test/files/run/t7459b-optimize.scala b/test/files/run/t7459b-optimize.scala new file mode 100644 index 0000000000..605890962c --- /dev/null +++ b/test/files/run/t7459b-optimize.scala @@ -0,0 +1,21 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + new tttt.Node[Any]() + } + + val h: (Some[CC] => Any) = { + case Some(CC(tttt)) => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) + new LM().h(Some(new CC(new LM()))) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459b.scala b/test/files/run/t7459b.scala new file mode 100644 index 0000000000..605890962c --- /dev/null +++ b/test/files/run/t7459b.scala @@ -0,0 +1,21 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + new tttt.Node[Any]() + } + + val h: (Some[CC] => Any) = { + case Some(CC(tttt)) => + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) + new LM().h(Some(new CC(new LM()))) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459c.scala b/test/files/run/t7459c.scala new file mode 100644 index 0000000000..144c5d793b --- /dev/null +++ b/test/files/run/t7459c.scala @@ -0,0 +1,16 @@ +class LM { + class Node[B1] + + // crash + val g: (CC => Any) = { + case CC(tttt) => + tttt.## // no crash + new tttt.Node[Any]() + } +} + +object Test extends App { + new LM().g(new CC(new LM())) +} +case class CC(n: LM) + diff --git a/test/files/run/t7459d.scala b/test/files/run/t7459d.scala new file mode 100644 index 0000000000..3263701f9d --- /dev/null +++ b/test/files/run/t7459d.scala @@ -0,0 +1,15 @@ +class LM { + class Node[B1] + case class CC(n: LM) + + // crash + val f: (LM => Any) = { + case tttt => + val uuuu: (tttt.type, Any) = (tttt, 0) + new uuuu._1.Node[Any]() + } +} + +object Test extends App { + new LM().f(new LM()) +} diff --git a/test/files/run/t7459f.scala b/test/files/run/t7459f.scala new file mode 100644 index 0000000000..63e2109560 --- /dev/null +++ b/test/files/run/t7459f.scala @@ -0,0 +1,12 @@ +object Test extends App { + class C + + case class FooSeq(x: Int, y: String, z: C*) + + FooSeq(1, "a", new C()) match { + case FooSeq(1, "a", x@_* ) => + //println(x.toList) + x.asInstanceOf[x.type] + assert(x.isInstanceOf[x.type]) + } +} -- cgit v1.2.3