diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-05-07 23:29:02 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-11-14 22:19:49 +1000 |
commit | 5b8327b807c40cab867065cf695191a36c9210ee (patch) | |
tree | 8e3964382814439fe2436fa37941610179a92781 /src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala | |
parent | b431a4bd83d3bfb2b95d0426d2905b34ce1265ad (diff) | |
download | scala-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.scala | 7 |
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 } } |