summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMiguel Garcia <miguelalfredo.garcia@epfl.ch>2012-05-21 22:39:37 +0200
committerMiguel Garcia <miguelalfredo.garcia@epfl.ch>2012-05-21 22:39:37 +0200
commit3eb0245cdd698b5be6ee8dd755eaa5442aae259f (patch)
tree37b716b1f549e4ce45f825bd54794dc183bb56fe /src
parentf406550146250f5a6036d3d778582efa6d68252a (diff)
downloadscala-3eb0245cdd698b5be6ee8dd755eaa5442aae259f.tar.gz
scala-3eb0245cdd698b5be6ee8dd755eaa5442aae259f.tar.bz2
scala-3eb0245cdd698b5be6ee8dd755eaa5442aae259f.zip
fix for SI-5672
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala20
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala2
3 files changed, 25 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 71795a02aa..019e887c4e 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -257,11 +257,23 @@ trait Members {
var succ = bb
do {
succ = nextBlock(succ);
- bb.removeLastInstruction
- succ.toList foreach { i => bb.emit(i, i.pos) }
- code.removeBlock(succ)
+ val lastInstr = bb.lastInstruction
+ /* Ticket SI-5672
+ * Besides removing the control-flow instruction at the end of `bb` (usually a JUMP), we have to pop any values it pushes.
+ * Examples:
+ * `SWITCH` consisting of just the default case, or
+ * `CJUMP(targetBlock, targetBlock, _, _)` ie where success and failure targets coincide (this one consumes two stack values).
+ */
+ val oldTKs = lastInstr.consumedTypes
+ assert(lastInstr.consumed == oldTKs.size, "Someone forgot to override consumedTypes() in " + lastInstr)
+
+ bb.removeLastInstruction
+ for(tk <- oldTKs.reverse) { bb.emit(DROP(tk), lastInstr.pos) }
+ succ.toList foreach { i => bb.emit(i, i.pos) }
+ code.removeBlock(succ)
+ exh foreach { e => e.covered = e.covered - succ }
+
nextBlock -= bb
- exh foreach { e => e.covered = e.covered - succ }
} while (nextBlock.isDefinedAt(succ))
bb.close
} else
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
index 576cc72f82..3179fc5c56 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -436,6 +436,8 @@ trait Opcodes { self: ICodes =>
override def consumed = 1
override def produced = 0
+ override val consumedTypes = List(INT)
+
def flatTagsCount: Int = { var acc = 0; var rest = tags; while(rest.nonEmpty) { acc += rest.head.length; rest = rest.tail }; acc } // a one-liner
}
@@ -470,6 +472,8 @@ trait Opcodes { self: ICodes =>
override def consumed = 2
override def produced = 0
+
+ override val consumedTypes = List(kind, kind)
}
/** This class represents a CZJUMP instruction
@@ -489,6 +493,8 @@ trait Opcodes { self: ICodes =>
override def consumed = 1
override def produced = 0
+
+ override val consumedTypes = List(kind)
}
@@ -499,6 +505,8 @@ trait Opcodes { self: ICodes =>
case class RETURN(kind: TypeKind) extends Instruction {
override def consumed = if (kind == UNIT) 0 else 1
override def produced = 0
+
+ // TODO override val consumedTypes = List(kind)
}
/** This class represents a THROW instruction
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 61e02edaff..c48c81ea7a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1646,7 +1646,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// TODO: if patterns allow switch but the type of the scrutinee doesn't, cast (type-test) the scrutinee to the corresponding switchable type and switch on the result
if (regularSwitchMaker.switchableTpe(scrutSym.tpe)) {
val caseDefsWithDefault = regularSwitchMaker(cases map {c => (scrutSym, c)}, pt)
- if (caseDefsWithDefault.length <= 2) None // not worth emitting a switch... also, the optimizer has trouble digesting tiny switches, apparently, so let's be nice and not generate them
+ if (caseDefsWithDefault isEmpty) None // not worth emitting a switch.
else {
// match on scrutSym -- converted to an int if necessary -- not on scrut directly (to avoid duplicating scrut)
val scrutToInt: Tree =