summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-05-07 23:29:02 +0200
committerJason Zaugg <jzaugg@gmail.com>2014-11-14 22:19:49 +1000
commit5b8327b807c40cab867065cf695191a36c9210ee (patch)
tree8e3964382814439fe2436fa37941610179a92781 /src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
parentb431a4bd83d3bfb2b95d0426d2905b34ce1265ad (diff)
downloadscala-5b8327b807c40cab867065cf695191a36c9210ee.tar.gz
scala-5b8327b807c40cab867065cf695191a36c9210ee.tar.bz2
scala-5b8327b807c40cab867065cf695191a36c9210ee.zip
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 <synthetic> val x1: this.LM = x0$1; case4(){ matchEnd3(new tttt.Node[Any]()) }; matchEnd3(x: Any){ x } Or: // t7459b.scala ((x0$1: CC) => { case <synthetic> 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 <synthetic> val x1: _$1 = (null: Test.Mirror[_]).universe; case5(){ if (x1.isInstanceOf[Test.JavaUniverse]) { <synthetic> 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`.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala7
1 files changed, 5 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
index d862805a07..27360fea53 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
@@ -248,7 +248,10 @@ trait MatchTranslation {
if (caseDefs forall treeInfo.isCatchCase) caseDefs
else {
val swatches = { // switch-catches
- val bindersAndCases = caseDefs map { caseDef =>
+ // SI-7459 must duplicate here as we haven't commited to switch emission, and just figuring out
+ // if we can ends up mutating `caseDefs` down in the use of `substituteSymbols` in
+ // `TypedSubstitution#Substitution`. That is called indirectly by `emitTypeSwitch`.
+ val bindersAndCases = caseDefs.map(_.duplicate) map { caseDef =>
// generate a fresh symbol for each case, hoping we'll end up emitting a type-switch (we don't have a global scrut there)
// if we fail to emit a fine-grained switch, have to do translateCase again with a single scrutSym (TODO: uniformize substitution on treemakers so we can avoid this)
val caseScrutSym = freshSym(pos, pureType(ThrowableTpe))
@@ -518,7 +521,7 @@ trait MatchTranslation {
// reference the (i-1)th case accessor if it exists, otherwise the (i-1)th tuple component
override protected def tupleSel(binder: Symbol)(i: Int): Tree = {
val accessors = binder.caseFieldAccessors
- if (accessors isDefinedAt (i-1)) REF(binder) DOT accessors(i-1)
+ if (accessors isDefinedAt (i-1)) gen.mkAttributedStableRef(binder) DOT accessors(i-1)
else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN
}
}