summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2012-07-25 01:59:10 -0700
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-07-25 01:59:10 -0700
commit950c783e31f9cb5d4268cc83d824020c8345d910 (patch)
treeb42a1602fe4c96df1ed963d54443e7c79155f03d
parentb859a58b1ec6a0a44357c45c7d14d4cc18a2fd4a (diff)
parentee93df064b8b48f9e600d5ea99a0ebc5e0848345 (diff)
downloadscala-950c783e31f9cb5d4268cc83d824020c8345d910.tar.gz
scala-950c783e31f9cb5d4268cc83d824020c8345d910.tar.bz2
scala-950c783e31f9cb5d4268cc83d824020c8345d910.zip
Merge pull request #976 from adriaanm/ticket-4440b
SI-4440 workaround: avoid outer accessor that'll vanish
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala50
-rw-r--r--test/files/neg/t4440.check13
-rw-r--r--test/files/neg/t4440.flags1
-rw-r--r--test/files/neg/t4440.scala19
4 files changed, 58 insertions, 25 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index afbe528b1f..1f7c34b8ad 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -377,6 +377,7 @@ abstract class ExplicitOuter extends InfoTransform
}
}
+ // requires settings.XoldPatmat.value
def matchTranslation(tree: Match) = {
val Match(selector, cases) = tree
var nselector = transform(selector)
@@ -519,33 +520,32 @@ abstract class ExplicitOuter extends InfoTransform
super.transform(treeCopy.Apply(tree, sel, outerVal :: args))
// entry point for pattern matcher translation
- case mch: Match if (!opt.virtPatmat) => // don't use old pattern matcher as fallback when the user wants the virtualizing one
- matchTranslation(mch)
-
- case _ =>
- if (opt.virtPatmat) { // this turned out to be expensive, hence the hacky `if` and `return`
- tree match {
- // for patmatvirtualiser
- // base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE
- // TODO remove the synthetic `<outer>` method from outerFor??
- case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, outerAcc), Nil), eq), args) if outerAcc == nme.OUTER_SYNTH =>
- val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary?
- val acc = outerAccessor(outerFor)
- if(acc == NoSymbol) {
- // println("WARNING: no outer for "+ outerFor)
- return transform(TRUE) // urgh... drop condition if there's no accessor
- } else {
- // println("(base, acc)= "+(base, acc))
- val outerSelect = localTyper typed Apply(Select(base, acc), Nil)
- // achieves the same as: localTyper typed atPos(tree.pos)(outerPath(base, base.tpe.typeSymbol, outerFor.outerClass))
- // println("(b, tpsym, outerForI, outerFor, outerClass)= "+ (base, base.tpe.typeSymbol, outerFor, sel.symbol.owner, outerFor.outerClass))
- // println("outerSelect = "+ outerSelect)
- return transform(treeCopy.Apply(tree, treeCopy.Select(eqsel, outerSelect, eq), args))
- }
- case _ =>
- }
+ case m: Match if settings.XoldPatmat.value => // the new pattern matcher runs in its own phase right after typer
+ matchTranslation(m)
+
+ // for the new pattern matcher
+ // base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE
+ // TODO remove the synthetic `<outer>` method from outerFor??
+ case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, nme.OUTER_SYNTH), Nil), eq), args) if !settings.XoldPatmat.value =>
+ val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary?
+ val acc = outerAccessor(outerFor)
+
+ if (acc == NoSymbol ||
+ // since we can't fix SI-4440 properly (we must drop the outer accessors of final classes when there's no immediate reference to them in sight)
+ // at least don't crash... this duplicates maybeOmittable from constructors
+ (acc.owner.isEffectivelyFinal && !acc.isOverridingSymbol)) {
+ unit.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.")
+ return transform(TRUE) // urgh... drop condition if there's no accessor (or if it may disappear after constructors)
+ } else {
+ // println("(base, acc)= "+(base, acc))
+ val outerSelect = localTyper typed Apply(Select(base, acc), Nil)
+ // achieves the same as: localTyper typed atPos(tree.pos)(outerPath(base, base.tpe.typeSymbol, outerFor.outerClass))
+ // println("(b, tpsym, outerForI, outerFor, outerClass)= "+ (base, base.tpe.typeSymbol, outerFor, sel.symbol.owner, outerFor.outerClass))
+ // println("outerSelect = "+ outerSelect)
+ return transform(treeCopy.Apply(tree, treeCopy.Select(eqsel, outerSelect, eq), args))
}
+ case _ =>
if (settings.Xmigration28.value) tree match {
case TypeApply(fn @ Select(qual, _), args) if fn.symbol == Object_isInstanceOf || fn.symbol == Any_isInstanceOf =>
if (isArraySeqTest(qual.tpe, args.head.tpe))
diff --git a/test/files/neg/t4440.check b/test/files/neg/t4440.check
new file mode 100644
index 0000000000..2861dc3040
--- /dev/null
+++ b/test/files/neg/t4440.check
@@ -0,0 +1,13 @@
+t4440.scala:12: error: The outer reference in this type test cannot be checked at run time.
+ case _: b.Inner => println("b")
+ ^
+t4440.scala:13: error: The outer reference in this type test cannot be checked at run time.
+ case _: a.Inner => println("a") // this is the case we want
+ ^
+t4440.scala:16: error: The outer reference in this type test cannot be checked at run time.
+ case _: a.Inner => println("a")
+ ^
+t4440.scala:17: error: The outer reference in this type test cannot be checked at run time.
+ case _: b.Inner => println("b") // this is the case we want
+ ^
+four errors found
diff --git a/test/files/neg/t4440.flags b/test/files/neg/t4440.flags
new file mode 100644
index 0000000000..779916d58f
--- /dev/null
+++ b/test/files/neg/t4440.flags
@@ -0,0 +1 @@
+-unchecked -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/t4440.scala b/test/files/neg/t4440.scala
new file mode 100644
index 0000000000..383b141edd
--- /dev/null
+++ b/test/files/neg/t4440.scala
@@ -0,0 +1,19 @@
+// constructors used to drop outer fields when they were not accessed
+// however, how can you know (respecting separate compilation) that they're not accessed!?
+class Outer { final class Inner }
+
+// the matches below require Inner's outer pointer
+// until SI-4440 is fixed properly, we can't make this a run test
+// in principle, the output should be "a\nb", but without outer checks it's "b\na"
+object Test extends App {
+ val a = new Outer
+ val b = new Outer
+ (new a.Inner: Any) match {
+ case _: b.Inner => println("b")
+ case _: a.Inner => println("a") // this is the case we want
+ }
+ (new b.Inner: Any) match {
+ case _: a.Inner => println("a")
+ case _: b.Inner => println("b") // this is the case we want
+ }
+}