Skip to content

Commit 950c783

Browse files
author
Adriaan Moors
committed
Merge pull request scala#976 from adriaanm/ticket-4440b
SI-4440 workaround: avoid outer accessor that'll vanish
2 parents b859a58 + ee93df0 commit 950c783

File tree

4 files changed

+58
-25
lines changed

4 files changed

+58
-25
lines changed

src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ abstract class ExplicitOuter extends InfoTransform
377377
}
378378
}
379379

380+
// requires settings.XoldPatmat.value
380381
def matchTranslation(tree: Match) = {
381382
val Match(selector, cases) = tree
382383
var nselector = transform(selector)
@@ -519,33 +520,32 @@ abstract class ExplicitOuter extends InfoTransform
519520
super.transform(treeCopy.Apply(tree, sel, outerVal :: args))
520521

521522
// entry point for pattern matcher translation
522-
case mch: Match if (!opt.virtPatmat) => // don't use old pattern matcher as fallback when the user wants the virtualizing one
523-
matchTranslation(mch)
524-
525-
case _ =>
526-
if (opt.virtPatmat) { // this turned out to be expensive, hence the hacky `if` and `return`
527-
tree match {
528-
// for patmatvirtualiser
529-
// base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE
530-
// TODO remove the synthetic `<outer>` method from outerFor??
531-
case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, outerAcc), Nil), eq), args) if outerAcc == nme.OUTER_SYNTH =>
532-
val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary?
533-
val acc = outerAccessor(outerFor)
534-
if(acc == NoSymbol) {
535-
// println("WARNING: no outer for "+ outerFor)
536-
return transform(TRUE) // urgh... drop condition if there's no accessor
537-
} else {
538-
// println("(base, acc)= "+(base, acc))
539-
val outerSelect = localTyper typed Apply(Select(base, acc), Nil)
540-
// achieves the same as: localTyper typed atPos(tree.pos)(outerPath(base, base.tpe.typeSymbol, outerFor.outerClass))
541-
// println("(b, tpsym, outerForI, outerFor, outerClass)= "+ (base, base.tpe.typeSymbol, outerFor, sel.symbol.owner, outerFor.outerClass))
542-
// println("outerSelect = "+ outerSelect)
543-
return transform(treeCopy.Apply(tree, treeCopy.Select(eqsel, outerSelect, eq), args))
544-
}
545-
case _ =>
546-
}
523+
case m: Match if settings.XoldPatmat.value => // the new pattern matcher runs in its own phase right after typer
524+
matchTranslation(m)
525+
526+
// for the new pattern matcher
527+
// base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE
528+
// TODO remove the synthetic `<outer>` method from outerFor??
529+
case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, nme.OUTER_SYNTH), Nil), eq), args) if !settings.XoldPatmat.value =>
530+
val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary?
531+
val acc = outerAccessor(outerFor)
532+
533+
if (acc == NoSymbol ||
534+
// 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)
535+
// at least don't crash... this duplicates maybeOmittable from constructors
536+
(acc.owner.isEffectivelyFinal && !acc.isOverridingSymbol)) {
537+
unit.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.")
538+
return transform(TRUE) // urgh... drop condition if there's no accessor (or if it may disappear after constructors)
539+
} else {
540+
// println("(base, acc)= "+(base, acc))
541+
val outerSelect = localTyper typed Apply(Select(base, acc), Nil)
542+
// achieves the same as: localTyper typed atPos(tree.pos)(outerPath(base, base.tpe.typeSymbol, outerFor.outerClass))
543+
// println("(b, tpsym, outerForI, outerFor, outerClass)= "+ (base, base.tpe.typeSymbol, outerFor, sel.symbol.owner, outerFor.outerClass))
544+
// println("outerSelect = "+ outerSelect)
545+
return transform(treeCopy.Apply(tree, treeCopy.Select(eqsel, outerSelect, eq), args))
547546
}
548547

548+
case _ =>
549549
if (settings.Xmigration28.value) tree match {
550550
case TypeApply(fn @ Select(qual, _), args) if fn.symbol == Object_isInstanceOf || fn.symbol == Any_isInstanceOf =>
551551
if (isArraySeqTest(qual.tpe, args.head.tpe))

test/files/neg/t4440.check

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
t4440.scala:12: error: The outer reference in this type test cannot be checked at run time.
2+
case _: b.Inner => println("b")
3+
^
4+
t4440.scala:13: error: The outer reference in this type test cannot be checked at run time.
5+
case _: a.Inner => println("a") // this is the case we want
6+
^
7+
t4440.scala:16: error: The outer reference in this type test cannot be checked at run time.
8+
case _: a.Inner => println("a")
9+
^
10+
t4440.scala:17: error: The outer reference in this type test cannot be checked at run time.
11+
case _: b.Inner => println("b") // this is the case we want
12+
^
13+
four errors found

test/files/neg/t4440.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-unchecked -Xfatal-warnings

test/files/neg/t4440.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// constructors used to drop outer fields when they were not accessed
2+
// however, how can you know (respecting separate compilation) that they're not accessed!?
3+
class Outer { final class Inner }
4+
5+
// the matches below require Inner's outer pointer
6+
// until SI-4440 is fixed properly, we can't make this a run test
7+
// in principle, the output should be "a\nb", but without outer checks it's "b\na"
8+
object Test extends App {
9+
val a = new Outer
10+
val b = new Outer
11+
(new a.Inner: Any) match {
12+
case _: b.Inner => println("b")
13+
case _: a.Inner => println("a") // this is the case we want
14+
}
15+
(new b.Inner: Any) match {
16+
case _: a.Inner => println("a")
17+
case _: b.Inner => println("b") // this is the case we want
18+
}
19+
}

0 commit comments

Comments
 (0)