From 5ba1063518f1320b1e920b89c1815406df887467 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 3 Feb 2016 11:43:48 +0100 Subject: Improve simplifyJumps Improve simplifyJumps to rewrite IFEQ L4 L5 GOTO L6 to IFNE L6 L5 This rewrite is only correct if L5 is not the target of any jump instruction (otherwise, removing the GOTO would change semantics). Previously we did not do the rewrite if there was any label between the conditional jump and the goto (like L5). Now we track which labels are jump targets. --- .../scala/tools/nsc/backend/jvm/opt/LocalOpt.scala | 281 +++++++++++---------- .../nsc/backend/jvm/opt/SimplifyJumpsTest.scala | 23 +- 2 files changed, 169 insertions(+), 135 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala index c1fdb7eb59..f486bb0cb9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -771,154 +771,173 @@ object LocalOptImpls { // A set of all exception handlers that guard the current instruction, required for simplifyGotoReturn var activeHandlers = Set.empty[TryCatchBlockNode] - // Instructions that need to be removed. simplifyBranchOverGoto returns an instruction to be - // removed. It cannot remove it itself because the instruction may be the successor of the current - // instruction of the iterator, which is not supported in ASM. - var instructionsToRemove = Set.empty[AbstractInsnNode] + val jumpInsns = mutable.LinkedHashMap.empty[JumpInsnNode, Boolean] - val iterator = method.instructions.iterator() - while (iterator.hasNext) { - val instruction = iterator.next() + for (insn <- method.instructions.iterator().asScala) insn match { + case l: LabelNode => + activeHandlers ++= allHandlers.filter(_.start == l) + activeHandlers = activeHandlers.filter(_.end != l) - instruction match { - case l: LabelNode => - activeHandlers ++= allHandlers.filter(_.start == l) - activeHandlers = activeHandlers.filter(_.end != l) - case _ => + case ji: JumpInsnNode => + jumpInsns(ji) = activeHandlers.nonEmpty + + case _ => + } + + var _jumpTargets: Set[AbstractInsnNode] = null + def jumpTargets = { + if (_jumpTargets == null) { + _jumpTargets = jumpInsns.keysIterator.map(_.label).toSet } + _jumpTargets + } - if (instructionsToRemove(instruction)) { - iterator.remove() - instructionsToRemove -= instruction - } else if (isJumpNonJsr(instruction)) { // fast path - all of the below only treat jumps - var jumpRemoved = simplifyThenElseSameTarget(method, instruction) + def removeJumpFromMap(jump: JumpInsnNode) = { + jumpInsns.remove(jump) + _jumpTargets = null + } - if (!jumpRemoved) { - changed = collapseJumpChains(instruction) || changed - jumpRemoved = removeJumpToSuccessor(method, instruction) + def replaceJumpByPop(jump: JumpInsnNode) = { + removeJumpAndAdjustStack(method, jump) + removeJumpFromMap(jump) + } - if (!jumpRemoved) { - val staleGoto = simplifyBranchOverGoto(method, instruction) - instructionsToRemove ++= staleGoto - changed ||= staleGoto.nonEmpty - changed = simplifyGotoReturn(method, instruction, inTryBlock = activeHandlers.nonEmpty) || changed - } + /** + * Removes a conditional jump if it is followed by a GOTO to the same destination. + * + * CondJump l; [nops]; GOTO l; [...] + * POP*; [nops]; GOTO l; [...] + * + * Introduces 1 or 2 POP instructions, depending on the number of values consumed by the CondJump. + */ + def simplifyThenElseSameTarget(insn: AbstractInsnNode): Boolean = insn match { + case ConditionalJump(jump) => + nextExecutableInstruction(insn) match { + case Some(Goto(elseJump)) if sameTargetExecutableInstruction(jump, elseJump) => + replaceJumpByPop(jump) + true + + case _ => false } - changed ||= jumpRemoved - } + + case _ => false } - assert(instructionsToRemove.isEmpty, "some optimization required removing a previously traversed instruction. add `instructionsToRemove.foreach(method.instructions.remove)`") - changed - } - /** - * Removes a conditional jump if it is followed by a GOTO to the same destination. - * - * CondJump l; [nops]; GOTO l; [...] - * POP*; [nops]; GOTO l; [...] - * - * Introduces 1 or 2 POP instructions, depending on the number of values consumed by the CondJump. - */ - private def simplifyThenElseSameTarget(method: MethodNode, instruction: AbstractInsnNode): Boolean = instruction match { - case ConditionalJump(jump) => - nextExecutableInstruction(instruction) match { - case Some(Goto(elseJump)) if sameTargetExecutableInstruction(jump, elseJump) => - removeJumpAndAdjustStack(method, jump) + /** + * Replace jumps to a sequence of GOTO instructions by a jump to the final destination. + * + * Jump l; [any ops]; l: GOTO m; [any ops]; m: GOTO n; [any ops]; n: NotGOTO; [...] + * => Jump n; [rest unchanged] + * + * If there's a loop of GOTOs, the initial jump is replaced by one of the labels in the loop. + */ + def collapseJumpChains(insn: AbstractInsnNode): Boolean = insn match { + case JumpNonJsr(jump) => + val target = finalJumpTarget(jump) + if (jump.label == target) false else { + jump.label = target + _jumpTargets = null true + } - case _ => false - } - case _ => false - } + case _ => false + } - /** - * Replace jumps to a sequence of GOTO instructions by a jump to the final destination. - * - * Jump l; [any ops]; l: GOTO m; [any ops]; m: GOTO n; [any ops]; n: NotGOTO; [...] - * => Jump n; [rest unchanged] - * - * If there's a loop of GOTOs, the initial jump is replaced by one of the labels in the loop. - */ - private def collapseJumpChains(instruction: AbstractInsnNode): Boolean = instruction match { - case JumpNonJsr(jump) => - val target = finalJumpTarget(jump) - if (jump.label == target) false else { - jump.label = target + /** + * Eliminates unnecessary jump instructions + * + * Jump l; [nops]; l: [...] + * => POP*; [nops]; l: [...] + * + * Introduces 0, 1 or 2 POP instructions, depending on the number of values consumed by the Jump. + */ + def removeJumpToSuccessor(insn: AbstractInsnNode): Boolean = insn match { + case JumpNonJsr(jump) if nextExecutableInstruction(jump, alsoKeep = Set(jump.label)) contains jump.label => + replaceJumpByPop(jump) true - } - case _ => false - } + case _ => false + } - /** - * Eliminates unnecessary jump instructions - * - * Jump l; [nops]; l: [...] - * => POP*; [nops]; l: [...] - * - * Introduces 0, 1 or 2 POP instructions, depending on the number of values consumed by the Jump. - */ - private def removeJumpToSuccessor(method: MethodNode, instruction: AbstractInsnNode) = instruction match { - case JumpNonJsr(jump) if nextExecutableInstruction(jump, alsoKeep = Set(jump.label)) == Some(jump.label) => - removeJumpAndAdjustStack(method, jump) - true - case _ => false - } + /** + * If the "else" part of a conditional branch is a simple GOTO, negates the conditional branch + * and eliminates the GOTO. + * + * CondJump l; [nops, no jump targets]; GOTO m; [nops]; l: [...] + * => NegatedCondJump m; [nops, no jump targets]; [nops]; l: [...] + * + * Note that no jump targets are allowed in the first [nops] section. Otherwise, there could + * be some other jump to the GOTO, and eliminating it would change behavior. + */ + def simplifyBranchOverGoto(insn: AbstractInsnNode, inTryBlock: Boolean): Boolean = insn match { + case ConditionalJump(jump) => + // don't skip over jump targets, see doc comment + nextExecutableInstruction(jump, alsoKeep = jumpTargets) match { + case Some(Goto(goto)) => + if (nextExecutableInstruction(goto, alsoKeep = Set(jump.label)) contains jump.label) { + val newJump = new JumpInsnNode(negateJumpOpcode(jump.getOpcode), goto.label) + method.instructions.set(jump, newJump) + removeJumpFromMap(jump) + jumpInsns(newJump) = inTryBlock + replaceJumpByPop(goto) + true + } else false + + case _ => false + } + case _ => false + } - /** - * If the "else" part of a conditional branch is a simple GOTO, negates the conditional branch - * and eliminates the GOTO. - * - * CondJump l; [nops, no labels]; GOTO m; [nops]; l: [...] - * => NegatedCondJump m; [nops, no labels]; [nops]; l: [...] - * - * Note that no label definitions are allowed in the first [nops] section. Otherwise, there could - * be some other jump to the GOTO, and eliminating it would change behavior. - * - * For technical reasons, we cannot remove the GOTO here (*).Instead this method returns an Option - * containing the GOTO that needs to be eliminated. - * - * (*) The ASM instruction iterator (used in the caller [[simplifyJumps]]) has an undefined - * behavior if the successor of the current instruction is removed, which may be the case here - */ - private def simplifyBranchOverGoto(method: MethodNode, instruction: AbstractInsnNode): Option[JumpInsnNode] = instruction match { - case ConditionalJump(jump) => - // don't skip over labels, see doc comment - nextExecutableInstructionOrLabel(jump) match { - case Some(Goto(goto)) => - if (nextExecutableInstruction(goto, alsoKeep = Set(jump.label)) == Some(jump.label)) { - val newJump = new JumpInsnNode(negateJumpOpcode(jump.getOpcode), goto.label) - method.instructions.set(jump, newJump) - Some(goto) - } else None - - case _ => None - } - case _ => None - } + /** + * Inlines xRETURN and ATHROW + * + * GOTO l; [any ops]; l: xRETURN/ATHROW + * => xRETURN/ATHROW; [any ops]; l: xRETURN/ATHROW + * + * inlining is only done if the GOTO instruction is not part of a try block, otherwise the + * rewrite might change the behavior. For xRETURN, the reason is that return instructions may throw + * an IllegalMonitorStateException, as described here: + * http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.return + */ + def simplifyGotoReturn(instruction: AbstractInsnNode, inTryBlock: Boolean): Boolean = !inTryBlock && (instruction match { + case Goto(jump) => + nextExecutableInstruction(jump.label) match { + case Some(target) => + if (isReturn(target) || target.getOpcode == ATHROW) { + method.instructions.set(jump, target.clone(null)) + removeJumpFromMap(jump) + true + } else false + + case _ => false + } + case _ => false + }) - /** - * Inlines xRETURN and ATHROW - * - * GOTO l; [any ops]; l: xRETURN/ATHROW - * => xRETURN/ATHROW; [any ops]; l: xRETURN/ATHROW - * - * inlining is only done if the GOTO instruction is not part of a try block, otherwise the - * rewrite might change the behavior. For xRETURN, the reason is that return instructions may throw - * an IllegalMonitorStateException, as described here: - * http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.return - */ - private def simplifyGotoReturn(method: MethodNode, instruction: AbstractInsnNode, inTryBlock: Boolean): Boolean = !inTryBlock && (instruction match { - case Goto(jump) => - nextExecutableInstruction(jump.label) match { - case Some(target) => - if (isReturn(target) || target.getOpcode == ATHROW) { - method.instructions.set(jump, target.clone(null)) - true - } else false + def run(): Boolean = { + var changed = false + + // `.toList` because we're modifying the map while iterating over it + for ((jumpInsn, inTryBlock) <- jumpInsns.toList if jumpInsns.contains(jumpInsn) && isJumpNonJsr(jumpInsn)) { + var jumpRemoved = simplifyThenElseSameTarget(jumpInsn) - case _ => false + if (!jumpRemoved) { + changed = collapseJumpChains(jumpInsn) || changed + jumpRemoved = removeJumpToSuccessor(jumpInsn) + + if (!jumpRemoved) { + changed = simplifyBranchOverGoto(jumpInsn, inTryBlock) || changed + changed = simplifyGotoReturn(jumpInsn, inTryBlock) || changed + } + } + + changed ||= jumpRemoved } - case _ => false - }) + + if (changed) run() + changed + } + + run() + } } diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala index a685ae7dd5..99acb318de 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala @@ -96,10 +96,22 @@ class SimplifyJumpsTest { instructionsFromMethod(method), List(VarOp(ILOAD, 1), Jump(IFLT, Label(3))) ::: rest.tail ) - // no label allowed between begin and rest. if there's another label, then there could be a - // branch that label. eliminating the GOTO would change the behavior. - val nonOptMethod = genMethod()(begin ::: Label(22) :: rest: _*) - assertFalse(LocalOptImpls.simplifyJumps(nonOptMethod)) + // branch over goto is OK even if there's a label in between, if that label is not a jump target + val withNonJumpTargetLabel = genMethod()(begin ::: Label(22) :: rest: _*) + assertTrue(LocalOptImpls.simplifyJumps(withNonJumpTargetLabel)) + assertSameCode( + instructionsFromMethod(withNonJumpTargetLabel), + List(VarOp(ILOAD, 1), Jump(IFLT, Label(3)), Label(22)) ::: rest.tail ) + + // if the Label(22) between IFGE and GOTO is the target of some jump, we cannot rewrite the IFGE + // and remove the GOTO: removing the GOTO would change semantics. However, the jump that targets + // Label(22) will be re-written (jump-chain collapsing), so in a second round, the IFGE is still + // rewritten to IFLT + val twoRounds = genMethod()(List(VarOp(ILOAD, 1), Jump(IFLE, Label(22))) ::: begin ::: Label(22) :: rest: _*) + assertTrue(LocalOptImpls.simplifyJumps(twoRounds)) + assertSameCode( + instructionsFromMethod(twoRounds), + List(VarOp(ILOAD, 1), Jump(IFLE, Label(3)), VarOp(ILOAD, 1), Jump(IFLT, Label(3)), Label(22)) ::: rest.tail ) } @Test @@ -167,6 +179,9 @@ class SimplifyJumpsTest { VarOp(ILOAD, 1), Jump(IFGE, Label(target)), + VarOp(ILOAD, 1), // some code to prevent rewriting the conditional jump + Op(IRETURN), + Label(4), Jump(GOTO, Label(3)), -- cgit v1.2.3 From 9c9a22c82a1286cf251f794ebe568dc7745ae974 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 26 Jan 2016 21:24:31 +0100 Subject: rename -YoptTrace to -Yopt-trace --- src/compiler/scala/tools/nsc/settings/ScalaSettings.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 20e2c4346f..1446d22217 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -319,7 +319,7 @@ trait ScalaSettings extends AbsScalaSettings def YoptWarningNoInlineMissingBytecode = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingBytecode) def YoptWarningNoInlineMissingScalaInlineInfoAttr = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingScalaInlineInfoAttr) - val YoptTrace = StringSetting("-YoptTrace", "package/Class.method", "Trace the optimizer progress for a specific method.", "") + val YoptTrace = StringSetting("-Yopt-trace", "package/Class.method", "Trace the optimizer progress for a specific method.", "") private def removalIn212 = "This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug." -- cgit v1.2.3 From 3d811b8f96c124cb0a7b2a48434e82eda501f793 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 26 Jan 2016 21:24:56 +0100 Subject: show erroneous compiler flags in junit compiler tests --- test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala index 342f403426..0d353e930e 100644 --- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala +++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala @@ -50,9 +50,11 @@ object CodeGenTools { } def newCompilerWithoutVirtualOutdir(defaultArgs: String = "-usejavacp", extraArgs: String = ""): Global = { - val settings = new Settings() + def showError(s: String) = throw new Exception(s) + val settings = new Settings(showError) val args = (CommandLineParser tokenize defaultArgs) ++ (CommandLineParser tokenize extraArgs) - settings.processArguments(args, processAll = true) + val (_, nonSettingsArgs) = settings.processArguments(args, processAll = true) + if (nonSettingsArgs.nonEmpty) showError("invalid compiler flags: " + nonSettingsArgs.mkString(" ")) new Global(settings, new StoreReporter) } -- cgit v1.2.3 From 4af9f1566dde56adecdba2690df71e39552e32fe Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Mon, 25 Jan 2016 21:38:28 +0100 Subject: Re-write and Re-enable optimizer tests Rewrite tests for new optimizer - SI-6941 - SI-2171 - t3430 - t3252 - t4840 - t2171 - t3430 - t3252 - t6157 - t6547 - t8062 - t8306 - t8359 - t9123 - trait-force-info - private-inline test cases for bugs fixed in the new optimizer - SI-9160, the unnecessary boxing mentioned in the ticket is optimzied since push-pop elimination (#4858). - SI-8796 - SI-8524 - SI-7807 fix flags file for t3420 remove an empty flags file remove unnecessary partest filters explicit inliner warnings in test t7582 Restore the lisp test. Removing the flags file - our build runs with the (new) optimizer enabled anyway. The test spent the past few years as an optimizer test in pos/ see https://issues.scala-lang.org/browse/SI-4512. The attempt may fail, but why not give it a try. $ git lg -S"lisp" ... | * | | | f785785 - SI-4579 Yoke the power of lisp.scala as a stress for the optimizer. (3 years, 8 months ago) ... * | | | | | | 622cc99 - Revert the lisp test. (3 years, 10 months ago) ... * | | | | | | 97f0324 - Revived the lisp test. (3 years, 10 months ago) ... * | 1e0f7dc - Imprison the lisp test, no review. (4 years, 4 months ago) ... * | 6b09630 - "Freed the lisp test." Tweaked partest defaults... (4 years, 6 months ago) ... * | fec42c1 - Lisp test wins again, no review. (4 years, 8 months ago) ... * | 1c2d44d - Restored the lisp.scala test. (4 years, 8 months ago) ... * | 15ed892 - Temporarily sending lisp.scala to be interprete... (4 years, 8 months ago) ... --- test/files/jvm/t6941.check | 1 - test/files/jvm/t6941.flags | 1 - test/files/jvm/t6941/Analyzed_1.flags | 1 - test/files/jvm/t6941/Analyzed_1.scala | 11 - test/files/jvm/t6941/test.scala | 15 - test/files/pos/t2171.flags | 1 - test/files/pos/t2171.scala | 7 - test/files/pos/t3252.flags | 1 - test/files/pos/t3252.scala | 15 - test/files/pos/t3420.flags | 2 +- test/files/pos/t3430.flags | 1 - test/files/pos/t3430.scala | 13 - test/files/pos/t4579.flags | 1 - test/files/pos/t4579.scala | 518 --------------------- test/files/pos/t4840.flags | 2 +- test/files/pos/t6157.flags | 1 - test/files/pos/t6157.scala | 25 - test/files/pos/t6547.flags | 1 - test/files/pos/t6547.scala | 6 - test/files/pos/t8062.flags | 1 - test/files/pos/t8062/A_1.scala | 5 - test/files/pos/t8062/B_2.scala | 3 - test/files/pos/t8306.flags | 1 - test/files/pos/t8306.scala | 8 - test/files/pos/t8359-closelim-crash.flags | 1 - test/files/pos/t8359-closelim-crash.scala | 23 - test/files/pos/t9123.flags | 1 - test/files/pos/t9123.scala | 10 - test/files/pos/trait-force-info.flags | 1 - test/files/pos/trait-force-info.scala | 18 - test/files/run/elidable-opt.scala | 3 - test/files/run/lisp.check | 26 ++ test/files/run/lisp.scala | 518 +++++++++++++++++++++ test/files/run/t7008-scala-defined.flags | 0 test/files/run/t7008-scala-defined/Test_3.scala | 3 - test/files/run/t7582.check | 5 + test/files/run/t7582.flags | 2 +- test/files/run/t7582/InlineHolder.scala | 3 - test/files/run/t7582b.check | 5 + test/files/run/t7582b.flags | 2 +- test/files/run/t7582b/InlineHolder.scala | 3 - test/files/run/t7807.check | 3 + test/files/run/t7807.scala | 21 + .../junit/scala/issues/OptimizedBytecodeTest.scala | 331 +++++++++++++ .../nsc/transform/patmat/PatmatBytecodeTest.scala | 25 + test/pending/run/private-inline.check | 13 - test/pending/run/private-inline.flags | 1 - test/pending/run/private-inline.scala | 52 --- 48 files changed, 938 insertions(+), 773 deletions(-) delete mode 100644 test/files/jvm/t6941.check delete mode 100644 test/files/jvm/t6941.flags delete mode 100644 test/files/jvm/t6941/Analyzed_1.flags delete mode 100644 test/files/jvm/t6941/Analyzed_1.scala delete mode 100644 test/files/jvm/t6941/test.scala delete mode 100644 test/files/pos/t2171.flags delete mode 100644 test/files/pos/t2171.scala delete mode 100644 test/files/pos/t3252.flags delete mode 100644 test/files/pos/t3252.scala delete mode 100644 test/files/pos/t3430.flags delete mode 100644 test/files/pos/t3430.scala delete mode 100644 test/files/pos/t4579.flags delete mode 100644 test/files/pos/t4579.scala delete mode 100644 test/files/pos/t6157.flags delete mode 100644 test/files/pos/t6157.scala delete mode 100644 test/files/pos/t6547.flags delete mode 100644 test/files/pos/t6547.scala delete mode 100644 test/files/pos/t8062.flags delete mode 100644 test/files/pos/t8062/A_1.scala delete mode 100644 test/files/pos/t8062/B_2.scala delete mode 100644 test/files/pos/t8306.flags delete mode 100644 test/files/pos/t8306.scala delete mode 100644 test/files/pos/t8359-closelim-crash.flags delete mode 100644 test/files/pos/t8359-closelim-crash.scala delete mode 100644 test/files/pos/t9123.flags delete mode 100644 test/files/pos/t9123.scala delete mode 100644 test/files/pos/trait-force-info.flags delete mode 100644 test/files/pos/trait-force-info.scala create mode 100644 test/files/run/lisp.check create mode 100644 test/files/run/lisp.scala delete mode 100644 test/files/run/t7008-scala-defined.flags create mode 100644 test/files/run/t7807.check create mode 100644 test/files/run/t7807.scala create mode 100644 test/junit/scala/issues/OptimizedBytecodeTest.scala delete mode 100644 test/pending/run/private-inline.check delete mode 100644 test/pending/run/private-inline.flags delete mode 100644 test/pending/run/private-inline.scala diff --git a/test/files/jvm/t6941.check b/test/files/jvm/t6941.check deleted file mode 100644 index 43f53aba12..0000000000 --- a/test/files/jvm/t6941.check +++ /dev/null @@ -1 +0,0 @@ -bytecode identical diff --git a/test/files/jvm/t6941.flags b/test/files/jvm/t6941.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/jvm/t6941.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/jvm/t6941/Analyzed_1.flags b/test/files/jvm/t6941/Analyzed_1.flags deleted file mode 100644 index ad51758c39..0000000000 --- a/test/files/jvm/t6941/Analyzed_1.flags +++ /dev/null @@ -1 +0,0 @@ --nowarn diff --git a/test/files/jvm/t6941/Analyzed_1.scala b/test/files/jvm/t6941/Analyzed_1.scala deleted file mode 100644 index b6951f71ee..0000000000 --- a/test/files/jvm/t6941/Analyzed_1.scala +++ /dev/null @@ -1,11 +0,0 @@ -// this class's bytecode, compiled under -optimize is analyzed by the test -// method a's bytecode should be identical to method b's bytecode -class SameBytecode { - def a(xs: List[Int]) = xs match { - case x :: _ => x - } - - def b(xs: List[Int]) = xs match { - case xs: ::[Int] => xs.head - } -} \ No newline at end of file diff --git a/test/files/jvm/t6941/test.scala b/test/files/jvm/t6941/test.scala deleted file mode 100644 index fceb54487f..0000000000 --- a/test/files/jvm/t6941/test.scala +++ /dev/null @@ -1,15 +0,0 @@ -import scala.tools.partest.{BytecodeTest, ASMConverters} - -import scala.tools.nsc.util.JavaClassPath -import java.io.InputStream -import scala.tools.asm -import asm.ClassReader -import asm.tree.{ClassNode, InsnList} -import scala.collection.JavaConverters._ - -object Test extends BytecodeTest { - def show: Unit = { - val classNode = loadClassNode("SameBytecode") - similarBytecode(getMethod(classNode, "a"), getMethod(classNode, "b"), ASMConverters.equivalentBytecode(_, _)) - } -} diff --git a/test/files/pos/t2171.flags b/test/files/pos/t2171.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t2171.flags +++ /dev/null @@ -1 +0,0 @@ --optimise \ No newline at end of file diff --git a/test/files/pos/t2171.scala b/test/files/pos/t2171.scala deleted file mode 100644 index 6c754c76a6..0000000000 --- a/test/files/pos/t2171.scala +++ /dev/null @@ -1,7 +0,0 @@ -final object test { - def logIgnoredException(msg: => String) = - try 0 catch { case ex => println(msg) } - - def main (args: Array[String]): Unit = - while (true) logIgnoredException ("...") -} diff --git a/test/files/pos/t3252.flags b/test/files/pos/t3252.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t3252.flags +++ /dev/null @@ -1 +0,0 @@ --optimise \ No newline at end of file diff --git a/test/files/pos/t3252.scala b/test/files/pos/t3252.scala deleted file mode 100644 index 3ecc1e7cef..0000000000 --- a/test/files/pos/t3252.scala +++ /dev/null @@ -1,15 +0,0 @@ -class A { - def f(x : Boolean) : Thread = { - g { - x match { - case false => - B.h { } - } - } - } - - private def g[T](block : => T) = sys.error("") -} -object B { - def h(block : => Unit) : Nothing = sys.error("") -} diff --git a/test/files/pos/t3420.flags b/test/files/pos/t3420.flags index 4fbafb7e80..397969bb1d 100644 --- a/test/files/pos/t3420.flags +++ b/test/files/pos/t3420.flags @@ -1 +1 @@ --Yopt-warnings Yopt:l:project -Xfatal-warnings \ No newline at end of file +-Yopt-warnings -Yopt:l:classpath -Xfatal-warnings \ No newline at end of file diff --git a/test/files/pos/t3430.flags b/test/files/pos/t3430.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/t3430.flags +++ /dev/null @@ -1 +0,0 @@ --optimise \ No newline at end of file diff --git a/test/files/pos/t3430.scala b/test/files/pos/t3430.scala deleted file mode 100644 index 3129c6276a..0000000000 --- a/test/files/pos/t3430.scala +++ /dev/null @@ -1,13 +0,0 @@ -// package com.example - -object A { - def f1(f: String => Boolean) = f("a") - - def f2(): Boolean = - f1 { s1 => - f1 { s2 => - while (true) { } - true - } - } -} \ No newline at end of file diff --git a/test/files/pos/t4579.flags b/test/files/pos/t4579.flags deleted file mode 100644 index 1182725e86..0000000000 --- a/test/files/pos/t4579.flags +++ /dev/null @@ -1 +0,0 @@ --optimize \ No newline at end of file diff --git a/test/files/pos/t4579.scala b/test/files/pos/t4579.scala deleted file mode 100644 index cd1553f02a..0000000000 --- a/test/files/pos/t4579.scala +++ /dev/null @@ -1,518 +0,0 @@ -//############################################################################ -// Lisp interpreter (revived as an optimizer test.) -//############################################################################ - -//############################################################################ -// Lisp Scanner - -class LispTokenizer(s: String) extends Iterator[String] { - private var i = 0; - private def isDelimiter(ch: Char) = ch <= ' ' || ch == '(' || ch == ')' - def hasNext: Boolean = { - while (i < s.length() && s.charAt(i) <= ' ') i += 1 - i < s.length() - } - def next: String = - if (hasNext) { - val start = i - if (isDelimiter(s charAt i)) i += 1 - else - do i = i + 1 - while (!isDelimiter(s charAt i)) - s.substring(start, i) - } else sys.error("premature end of string") -} - -//############################################################################ -// Lisp Interface - -trait Lisp { - type Data - - def string2lisp(s: String): Data - def lisp2string(s: Data): String - - def evaluate(d: Data): Data - // !!! def evaluate(s: String): Data = evaluate(string2lisp(s)) - def evaluate(s: String): Data -} - -//############################################################################ -// Lisp Implementation Using Case Classes - -object LispCaseClasses extends Lisp { - - import List.range - - trait Data { - def elemsToString(): String = toString(); - } - case class CONS(car: Data, cdr: Data) extends Data { - override def toString() = "(" + elemsToString() + ")"; - override def elemsToString() = car.toString() + (cdr match { - case NIL() => "" - case _ => " " + cdr.elemsToString(); - }) - } - case class NIL() extends Data { // !!! use case object - override def toString() = "()"; - } - case class SYM(name: String) extends Data { - override def toString() = name; - } - case class NUM(x: Int) extends Data { - override def toString() = x.toString(); - } - case class STR(x: String) extends Data { - override def toString() = "\"" + x + "\""; - } - case class FUN(f: List[Data] => Data) extends Data { - override def toString() = ""; - } - - def list(): Data = - NIL(); - def list(x0: Data): Data = - CONS(x0, NIL()); - def list(x0: Data, x1: Data): Data = - CONS(x0, list(x1)); - def list(x0: Data, x1: Data, x2: Data): Data = - CONS(x0, list(x1, x2)); - def list(x0: Data, x1: Data, x2: Data, x3: Data): Data = - CONS(x0, list(x1, x2, x3)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data): Data = - CONS(x0, list(x1, x2, x3, x4)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data): Data = - CONS(x0, list(x1, x2, x3, x4, x5)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, - x6: Data): Data = - CONS(x0, list(x1, x2, x3, x4, x5, x6)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, - x6: Data, x7: Data): Data = - CONS(x0, list(x1, x2, x3, x4, x5, x6, x7)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, - x6: Data, x7: Data, x8: Data): Data = - CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8)); - def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, - x6: Data, x7: Data, x8: Data, x9: Data): Data = - CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8, x9)); - - var curexp: Data = null - var trace: Boolean = false - var indent: Int = 0 - - def lispError[a](msg: String): a = - sys.error("error: " + msg + "\n" + curexp); - - trait Environment { - def lookup(n: String): Data; - def extendRec(name: String, expr: Environment => Data) = - new Environment { - def lookup(n: String): Data = - if (n == name) expr(this) else Environment.this.lookup(n); - } - def extend(name: String, v: Data) = extendRec(name, (env1 => v)); - } - val EmptyEnvironment = new Environment { - def lookup(n: String): Data = lispError("undefined: " + n); - } - - def toList(x: Data): List[Data] = x match { - case NIL() => List() - case CONS(y, ys) => y :: toList(ys) - case _ => lispError("malformed list: " + x); - } - - def toBoolean(x: Data) = x match { - case NUM(0) => false - case _ => true - } - - def normalize(x: Data): Data = x match { - case CONS(SYM("def"), - CONS(CONS(SYM(name), args), CONS(body, CONS(expr, NIL())))) => - normalize(list(SYM("def"), - SYM(name), list(SYM("lambda"), args, body), expr)) - case CONS(SYM("cond"), CONS(CONS(SYM("else"), CONS(expr, NIL())),NIL())) => - normalize(expr) - case CONS(SYM("cond"), CONS(CONS(test, CONS(expr, NIL())), rest)) => - normalize(list(SYM("if"), test, expr, CONS(SYM("cond"), rest))) - case CONS(h, t) => CONS(normalize(h), normalize(t)) - case _ => x - } - - def eval(x: Data, env: Environment): Data = { - val prevexp = curexp; - curexp = x; - if (trace) { - for (x <- range(1, indent)) Console.print(" "); - Console.println("===> " + x); - indent = indent + 1; - } - val result = eval1(x, env); - if (trace) { - indent = indent - 1; - for (x <- range(1, indent)) Console.print(" "); - Console.println("<=== " + result); - } - curexp = prevexp; - result - } - - def eval1(x: Data, env: Environment): Data = x match { - case SYM(name) => - env lookup name - case CONS(SYM("def"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) => - eval(z, env.extendRec(name, (env1 => eval(y, env1)))) - case CONS(SYM("val"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) => - eval(z, env.extend(name, eval(y, env))) - case CONS(SYM("lambda"), CONS(params, CONS(y, NIL()))) => - mkLambda(params, y, env) - case CONS(SYM("if"), CONS(c, CONS(t, CONS(e, NIL())))) => - if (toBoolean(eval(c, env))) eval(t, env) else eval(e, env) - case CONS(SYM("quote"), CONS(x, NIL())) => - x - case CONS(y, xs) => - apply(eval(y, env), toList(xs) map (x => eval(x, env))) - case NUM(_) => x - case STR(_) => x - case FUN(_) => x - case _ => - lispError("illegal term") - } - - def apply(fn: Data, args: List[Data]): Data = fn match { - case FUN(f) => f(args); - case _ => lispError("application of non-function: " + fn); - } - - def mkLambda(params: Data, expr: Data, env: Environment): Data = { - - def extendEnv(env: Environment, - ps: List[String], args: List[Data]): Environment = - (ps, args) match { - case (List(), List()) => - env - case (p :: ps1, arg :: args1) => - extendEnv(env.extend(p, arg), ps1, args1) - case _ => - lispError("wrong number of arguments") - } - - val ps: List[String] = toList(params) map { - case SYM(name) => name - case _ => sys.error("illegal parameter list"); - } - - FUN(args => eval(expr, extendEnv(env, ps, args))) - } - - val globalEnv = EmptyEnvironment - .extend("=", FUN({ - case List(NUM(arg1),NUM(arg2)) => NUM(if (arg1 == arg2) 1 else 0) - case List(STR(arg1),STR(arg2)) => NUM(if (arg1 == arg2) 1 else 0)})) - .extend("+", FUN({ - case List(NUM(arg1),NUM(arg2)) => NUM(arg1 + arg2) - case List(STR(arg1),STR(arg2)) => STR(arg1 + arg2)})) - .extend("-", FUN({ - case List(NUM(arg1),NUM(arg2)) => NUM(arg1 - arg2)})) - .extend("*", FUN({ - case List(NUM(arg1),NUM(arg2)) => NUM(arg1 * arg2)})) - .extend("/", FUN({ - case List(NUM(arg1),NUM(arg2)) => NUM(arg1 / arg2)})) - .extend("car", FUN({ - case List(CONS(x, xs)) => x})) - .extend("cdr", FUN({ - case List(CONS(x, xs)) => xs})) - .extend("null?", FUN({ - case List(NIL()) => NUM(1) - case _ => NUM(0)})) - .extend("cons", FUN({ - case List(x, y) => CONS(x, y)})); - - def evaluate(x: Data): Data = eval(normalize(x), globalEnv); - def evaluate(s: String): Data = evaluate(string2lisp(s)); - - def string2lisp(s: String): Data = { - val it = new LispTokenizer(s); - def parse(token: String): Data = { - if (token == "(") parseList - else if (token == ")") sys.error("unbalanced parentheses") - else if ('0' <= token.charAt(0) && token.charAt(0) <= '9') - NUM(token.toInt) - else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"') - STR(token.substring(1,token.length() - 1)) - else SYM(token) - } - def parseList: Data = { - val token = it.next; - if (token == ")") NIL() else CONS(parse(token), parseList) - } - parse(it.next) - } - - def lisp2string(d: Data): String = d.toString(); -} - -//############################################################################ -// Lisp Implementation Using Any - -object LispAny extends Lisp { - - import List._; - - type Data = Any; - - case class Lambda(f: List[Data] => Data); - - var curexp: Data = null; - var trace: Boolean = false; - var indent: Int = 0; - - def lispError[a](msg: String): a = - sys.error("error: " + msg + "\n" + curexp); - - trait Environment { - def lookup(n: String): Data; - def extendRec(name: String, expr: Environment => Data) = - new Environment { - def lookup(n: String): Data = - if (n == name) expr(this) else Environment.this.lookup(n); - } - def extend(name: String, v: Data) = extendRec(name, (env1 => v)); - } - val EmptyEnvironment = new Environment { - def lookup(n: String): Data = lispError("undefined: " + n); - } - - def asList(x: Data): List[Data] = x match { - case y: List[_] => y - case _ => lispError("malformed list: " + x) - } - - def asInt(x: Data): Int = x match { - case y: Int => y - case _ => lispError("not an integer: " + x) - } - - def asString(x: Data): String = x match { - case y: String => y - case _ => lispError("not a string: " + x) - } - - def asBoolean(x: Data): Boolean = x != 0 - - def normalize(x: Data): Data = x match { - case 'and :: x :: y :: Nil => - normalize('if :: x :: y :: 0 :: Nil) - case 'or :: x :: y :: Nil => - normalize('if :: x :: 1 :: y :: Nil) - case 'def :: (name :: args) :: body :: expr :: Nil => - normalize('def :: name :: ('lambda :: args :: body :: Nil) :: expr :: Nil) - case 'cond :: ('else :: expr :: Nil) :: rest => - normalize(expr); - case 'cond :: (test :: expr :: Nil) :: rest => - normalize('if :: test :: expr :: ('cond :: rest) :: Nil) - case 'cond :: 'else :: expr :: Nil => - normalize(expr) - case h :: t => - normalize(h) :: asList(normalize(t)) - case _ => - x - } - - def eval(x: Data, env: Environment): Data = { - val prevexp = curexp; - curexp = x; - if (trace) { - for (x <- range(1, indent)) Console.print(" "); - Console.println("===> " + x); - indent += 1; - } - val result = eval1(x, env); - if (trace) { - indent -= 1; - for (x <- range(1, indent)) Console.print(" "); - Console.println("<=== " + result); - } - curexp = prevexp; - result - } - - def eval1(x: Data, env: Environment): Data = x match { - case Symbol(name) => - env lookup name - case 'def :: Symbol(name) :: y :: z :: Nil => - eval(z, env.extendRec(name, (env1 => eval(y, env1)))) - case 'val :: Symbol(name) :: y :: z :: Nil => - eval(z, env.extend(name, eval(y, env))) - case 'lambda :: params :: y :: Nil => - mkLambda(params, y, env) - case 'if :: c :: y :: z :: Nil => - if (asBoolean(eval(c, env))) eval(y, env) else eval(z, env) - case 'quote :: y :: Nil => - y - case y :: z => - apply(eval(y, env), z map (x => eval(x, env))) - case Lambda(_) => x - case y: String => x - case y: Int => x - case y => lispError("illegal term") - } - - def lisp2string(x: Data): String = x match { - case Symbol(name) => name - case Nil => "()" - case y :: ys => - def list2string(xs: List[Data]): String = xs match { - case List() => "" - case y :: ys => " " + lisp2string(y) + list2string(ys) - } - "(" + lisp2string(y) + list2string(ys) + ")" - case _ => if (x.isInstanceOf[String]) "\"" + x + "\""; else x.toString() - } - - def apply(fn: Data, args: List[Data]): Data = fn match { - case Lambda(f) => f(args); - case _ => lispError("application of non-function: " + fn + " to " + args); - } - - def mkLambda(params: Data, expr: Data, env: Environment): Data = { - - def extendEnv(env: Environment, - ps: List[String], args: List[Data]): Environment = - (ps, args) match { - case (List(), List()) => - env - case (p :: ps1, arg :: args1) => - extendEnv(env.extend(p, arg), ps1, args1) - case _ => - lispError("wrong number of arguments") - } - - val ps: List[String] = asList(params) map { - case Symbol(name) => name - case _ => sys.error("illegal parameter list"); - } - - Lambda(args => eval(expr, extendEnv(env, ps, args))) - } - - val globalEnv = EmptyEnvironment - .extend("=", Lambda{ - case List(arg1, arg2) => if(arg1 == arg2) 1 else 0}) - .extend("+", Lambda{ - case List(arg1: Int, arg2: Int) => arg1 + arg2 - case List(arg1: String, arg2: String) => arg1 + arg2}) - .extend("-", Lambda{ - case List(arg1: Int, arg2: Int) => arg1 - arg2}) - .extend("*", Lambda{ - case List(arg1: Int, arg2: Int) => arg1 * arg2}) - .extend("/", Lambda{ - case List(arg1: Int, arg2: Int) => arg1 / arg2}) - .extend("nil", Nil) - .extend("cons", Lambda{ - case List(arg1, arg2) => arg1 :: asList(arg2)}) - .extend("car", Lambda{ - case List(x :: xs) => x}) - .extend("cdr", Lambda{ - case List(x :: xs) => xs}) - .extend("null?", Lambda{ - case List(Nil) => 1 - case _ => 0}); - - def evaluate(x: Data): Data = eval(normalize(x), globalEnv); - def evaluate(s: String): Data = evaluate(string2lisp(s)); - - def string2lisp(s: String): Data = { - val it = new LispTokenizer(s); - def parse(token: String): Data = { - if (token == "(") parseList - else if (token == ")") sys.error("unbalanced parentheses") - //else if (Character.isDigit(token.charAt(0))) - else if (token.charAt(0).isDigit) - token.toInt - else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"') - token.substring(1,token.length() - 1) - else Symbol(token) - } - def parseList: List[Data] = { - val token = it.next; - if (token == ")") Nil else parse(token) :: parseList - } - parse(it.next) - } -} - -//############################################################################ -// List User - -class LispUser(lisp: Lisp) { - - import lisp._; - - def evaluate(s: String) = lisp2string(lisp.evaluate(s)); - - def run = { - - Console.println(string2lisp("(lambda (x) (+ (* x x) 1))").asInstanceOf[AnyRef]); - Console.println(lisp2string(string2lisp("(lambda (x) (+ (* x x) 1))"))); - Console.println; - - Console.println("( '(1 2 3)) = " + evaluate(" (quote(1 2 3))")); - Console.println("(car '(1 2 3)) = " + evaluate("(car (quote(1 2 3)))")); - Console.println("(cdr '(1 2 3)) = " + evaluate("(cdr (quote(1 2 3)))")); - Console.println("(null? '(2 3)) = " + evaluate("(null? (quote(2 3)))")); - Console.println("(null? '()) = " + evaluate("(null? (quote()))")); - Console.println; - - Console.println("faculty(10) = " + evaluate( - "(def (faculty n) " + - "(if (= n 0) " + - "1 " + - "(* n (faculty (- n 1)))) " + - "(faculty 10))")); - Console.println("faculty(10) = " + evaluate( - "(def (faculty n) " + - "(cond " + - "((= n 0) 1) " + - "(else (* n (faculty (- n 1))))) " + - "(faculty 10))")); - Console.println("foobar = " + evaluate( - "(def (foo n) " + - "(cond " + - "((= n 0) \"a\")" + - "((= n 1) \"b\")" + - "((= (/ n 2) 1) " + - "(cond " + - "((= n 2) \"c\")" + - "(else \"d\")))" + - "(else " + - "(def (bar m) " + - "(cond " + - "((= m 0) \"e\")" + - "((= m 1) \"f\")" + - "(else \"z\"))" + - "(bar (- n 4)))))" + - "(val nil (quote ())" + - "(val v1 (foo 0) " + - "(val v2 (+ (foo 1) (foo 2)) " + - "(val v3 (+ (+ (foo 3) (foo 4)) (foo 5)) " + - "(val v4 (foo 6) " + - "(cons v1 (cons v2 (cons v3 (cons v4 nil))))))))))")); - Console.println; - } -} - -//############################################################################ -// Main - -object Test { - def main(args: Array[String]) { - new LispUser(LispCaseClasses).run; - new LispUser(LispAny).run; - () - } -} - -//############################################################################ diff --git a/test/files/pos/t4840.flags b/test/files/pos/t4840.flags index eb4d19bcb9..422d6be431 100644 --- a/test/files/pos/t4840.flags +++ b/test/files/pos/t4840.flags @@ -1 +1 @@ --optimise \ No newline at end of file +-Yopt:l:classpath \ No newline at end of file diff --git a/test/files/pos/t6157.flags b/test/files/pos/t6157.flags deleted file mode 100644 index 0ebca3e7af..0000000000 --- a/test/files/pos/t6157.flags +++ /dev/null @@ -1 +0,0 @@ - -optimize diff --git a/test/files/pos/t6157.scala b/test/files/pos/t6157.scala deleted file mode 100644 index 7463989b14..0000000000 --- a/test/files/pos/t6157.scala +++ /dev/null @@ -1,25 +0,0 @@ -// SI-6157 - Compiler crash on inlined function and -optimize option - -object Test { - def main(args: Array[String]) { - Console.println( - ErrorHandler.defaultIfIOException("String")("String") - ) - } -} - -import java.io.IOException - -object ErrorHandler { - - @inline - def defaultIfIOException[T](default: => T)(closure: => T): T = { - try { - closure - } catch { - case e: IOException => - default - } - } -} - diff --git a/test/files/pos/t6547.flags b/test/files/pos/t6547.flags deleted file mode 100644 index c9b68d70dc..0000000000 --- a/test/files/pos/t6547.flags +++ /dev/null @@ -1 +0,0 @@ --optimise diff --git a/test/files/pos/t6547.scala b/test/files/pos/t6547.scala deleted file mode 100644 index 53bd798219..0000000000 --- a/test/files/pos/t6547.scala +++ /dev/null @@ -1,6 +0,0 @@ -trait ConfigurableDefault[@specialized V] { - def fillArray(arr: Array[V], v: V) = (arr: Any) match { - case x: Array[Int] => null - case x: Array[Long] => v.asInstanceOf[Long] - } -} diff --git a/test/files/pos/t8062.flags b/test/files/pos/t8062.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8062.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8062/A_1.scala b/test/files/pos/t8062/A_1.scala deleted file mode 100644 index ca0411dae8..0000000000 --- a/test/files/pos/t8062/A_1.scala +++ /dev/null @@ -1,5 +0,0 @@ -package warmup - -object Warmup { - def filter[A](p: Any => Boolean): Any = filter[Any](p) -} diff --git a/test/files/pos/t8062/B_2.scala b/test/files/pos/t8062/B_2.scala deleted file mode 100644 index f0a6761488..0000000000 --- a/test/files/pos/t8062/B_2.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test { - warmup.Warmup.filter[Any](x => false) -} diff --git a/test/files/pos/t8306.flags b/test/files/pos/t8306.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8306.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8306.scala b/test/files/pos/t8306.scala deleted file mode 100644 index e04b054eb9..0000000000 --- a/test/files/pos/t8306.scala +++ /dev/null @@ -1,8 +0,0 @@ -class Si8306 { - def foo: Int = 123 - lazy val extension: Int = - foo match { - case idx if idx != -1 => 15 - case _ => 17 - } -} diff --git a/test/files/pos/t8359-closelim-crash.flags b/test/files/pos/t8359-closelim-crash.flags deleted file mode 100644 index 49d036a887..0000000000 --- a/test/files/pos/t8359-closelim-crash.flags +++ /dev/null @@ -1 +0,0 @@ --optimize diff --git a/test/files/pos/t8359-closelim-crash.scala b/test/files/pos/t8359-closelim-crash.scala deleted file mode 100644 index 1413694d10..0000000000 --- a/test/files/pos/t8359-closelim-crash.scala +++ /dev/null @@ -1,23 +0,0 @@ -package test - -// This is a minimization of code that crashed the compiler during bootstrapping -// in the first iteration of https://github.com/scala/scala/pull/4373, the PR -// that adjusted the order of free and declared params in LambdaLift. - -// Was: -// java.lang.AssertionError: assertion failed: -// Record Record(<$anon: Function1>,Map(value a$1 -> Deref(LocalVar(value b)))) does not contain a field value b$1 -// at scala.tools.nsc.Global.assert(Global.scala:262) -// at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:113) -// at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:122) -// at scala.tools.nsc.backend.opt.ClosureElimination$ClosureElim$$anonfun$analyzeMethod$1$$anonfun$apply$2.replaceFieldAccess$1(ClosureElimination.scala:124) -class Typer { - def bar(a: Boolean, b: Boolean): Unit = { - @inline - def baz(): Unit = { - ((_: Any) => (Typer.this, a, b)).apply("") - } - ((_: Any) => baz()).apply("") - } -} - diff --git a/test/files/pos/t9123.flags b/test/files/pos/t9123.flags deleted file mode 100644 index c16e2f71dc..0000000000 --- a/test/files/pos/t9123.flags +++ /dev/null @@ -1 +0,0 @@ --optimize -Ydelambdafy:method diff --git a/test/files/pos/t9123.scala b/test/files/pos/t9123.scala deleted file mode 100644 index 22d55b4351..0000000000 --- a/test/files/pos/t9123.scala +++ /dev/null @@ -1,10 +0,0 @@ -trait Setting { - type T - def value: T -} - -object Test { - def test(x: Some[Setting]) = x match { - case Some(dep) => Some(dep.value) map (_ => true) - } -} diff --git a/test/files/pos/trait-force-info.flags b/test/files/pos/trait-force-info.flags deleted file mode 100644 index eb4d19bcb9..0000000000 --- a/test/files/pos/trait-force-info.flags +++ /dev/null @@ -1 +0,0 @@ --optimise \ No newline at end of file diff --git a/test/files/pos/trait-force-info.scala b/test/files/pos/trait-force-info.scala deleted file mode 100644 index c2b33869c3..0000000000 --- a/test/files/pos/trait-force-info.scala +++ /dev/null @@ -1,18 +0,0 @@ -/** This does NOT crash unless it's in the interactive package. - */ - -package scala.tools.nsc -package interactive - -trait MyContextTrees { - val self: Global - val NoContext = self.analyzer.NoContext -} -// -// error: java.lang.AssertionError: assertion failed: trait Contexts.NoContext$ linkedModule: List() -// at scala.Predef$.assert(Predef.scala:160) -// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.innerSymbol$1(ClassfileParser.scala:1211) -// at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.classSymbol(ClassfileParser.scala:1223) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:489) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:757) -// at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:789) diff --git a/test/files/run/elidable-opt.scala b/test/files/run/elidable-opt.scala index ebada46de8..a2f29d2caf 100644 --- a/test/files/run/elidable-opt.scala +++ b/test/files/run/elidable-opt.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warnings; re-run with - */ import annotation._ import elidable._ diff --git a/test/files/run/lisp.check b/test/files/run/lisp.check new file mode 100644 index 0000000000..64053f26d0 --- /dev/null +++ b/test/files/run/lisp.check @@ -0,0 +1,26 @@ +(lambda (x) (+ (* x x) 1)) +(lambda (x) (+ (* x x) 1)) + +( '(1 2 3)) = (1 2 3) +(car '(1 2 3)) = 1 +(cdr '(1 2 3)) = (2 3) +(null? '(2 3)) = 0 +(null? '()) = 1 + +faculty(10) = 3628800 +faculty(10) = 3628800 +foobar = ("a" "bc" "def" "z") + +List('lambda, List('x), List('+, List('*, 'x, 'x), 1)) +(lambda (x) (+ (* x x) 1)) + +( '(1 2 3)) = (1 2 3) +(car '(1 2 3)) = 1 +(cdr '(1 2 3)) = (2 3) +(null? '(2 3)) = 0 +(null? '()) = 1 + +faculty(10) = 3628800 +faculty(10) = 3628800 +foobar = ("a" "bc" "def" "z") + diff --git a/test/files/run/lisp.scala b/test/files/run/lisp.scala new file mode 100644 index 0000000000..162c7d2599 --- /dev/null +++ b/test/files/run/lisp.scala @@ -0,0 +1,518 @@ +//############################################################################ +// Lisp interpreter +//############################################################################ + +//############################################################################ +// Lisp Scanner + +class LispTokenizer(s: String) extends Iterator[String] { + private var i = 0; + private def isDelimiter(ch: Char) = ch <= ' ' || ch == '(' || ch == ')' + def hasNext: Boolean = { + while (i < s.length() && s.charAt(i) <= ' ') i += 1 + i < s.length() + } + def next: String = + if (hasNext) { + val start = i + if (isDelimiter(s charAt i)) i += 1 + else + do i = i + 1 + while (!isDelimiter(s charAt i)) + s.substring(start, i) + } else sys.error("premature end of string") +} + +//############################################################################ +// Lisp Interface + +trait Lisp { + type Data + + def string2lisp(s: String): Data + def lisp2string(s: Data): String + + def evaluate(d: Data): Data + // !!! def evaluate(s: String): Data = evaluate(string2lisp(s)) + def evaluate(s: String): Data +} + +//############################################################################ +// Lisp Implementation Using Case Classes + +object LispCaseClasses extends Lisp { + + import List.range + + trait Data { + def elemsToString(): String = toString(); + } + case class CONS(car: Data, cdr: Data) extends Data { + override def toString() = "(" + elemsToString() + ")"; + override def elemsToString() = car.toString() + (cdr match { + case NIL() => "" + case _ => " " + cdr.elemsToString(); + }) + } + case class NIL() extends Data { // !!! use case object + override def toString() = "()"; + } + case class SYM(name: String) extends Data { + override def toString() = name; + } + case class NUM(x: Int) extends Data { + override def toString() = x.toString(); + } + case class STR(x: String) extends Data { + override def toString() = "\"" + x + "\""; + } + case class FUN(f: List[Data] => Data) extends Data { + override def toString() = ""; + } + + def list(): Data = + NIL(); + def list(x0: Data): Data = + CONS(x0, NIL()); + def list(x0: Data, x1: Data): Data = + CONS(x0, list(x1)); + def list(x0: Data, x1: Data, x2: Data): Data = + CONS(x0, list(x1, x2)); + def list(x0: Data, x1: Data, x2: Data, x3: Data): Data = + CONS(x0, list(x1, x2, x3)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data): Data = + CONS(x0, list(x1, x2, x3, x4)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data): Data = + CONS(x0, list(x1, x2, x3, x4, x5)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, + x6: Data): Data = + CONS(x0, list(x1, x2, x3, x4, x5, x6)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, + x6: Data, x7: Data): Data = + CONS(x0, list(x1, x2, x3, x4, x5, x6, x7)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, + x6: Data, x7: Data, x8: Data): Data = + CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8)); + def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data, + x6: Data, x7: Data, x8: Data, x9: Data): Data = + CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8, x9)); + + var curexp: Data = null + var trace: Boolean = false + var indent: Int = 0 + + def lispError[a](msg: String): a = + sys.error("error: " + msg + "\n" + curexp); + + trait Environment { + def lookup(n: String): Data; + def extendRec(name: String, expr: Environment => Data) = + new Environment { + def lookup(n: String): Data = + if (n == name) expr(this) else Environment.this.lookup(n); + } + def extend(name: String, v: Data) = extendRec(name, (env1 => v)); + } + val EmptyEnvironment = new Environment { + def lookup(n: String): Data = lispError("undefined: " + n); + } + + def toList(x: Data): List[Data] = x match { + case NIL() => List() + case CONS(y, ys) => y :: toList(ys) + case _ => lispError("malformed list: " + x); + } + + def toBoolean(x: Data) = x match { + case NUM(0) => false + case _ => true + } + + def normalize(x: Data): Data = x match { + case CONS(SYM("def"), + CONS(CONS(SYM(name), args), CONS(body, CONS(expr, NIL())))) => + normalize(list(SYM("def"), + SYM(name), list(SYM("lambda"), args, body), expr)) + case CONS(SYM("cond"), CONS(CONS(SYM("else"), CONS(expr, NIL())),NIL())) => + normalize(expr) + case CONS(SYM("cond"), CONS(CONS(test, CONS(expr, NIL())), rest)) => + normalize(list(SYM("if"), test, expr, CONS(SYM("cond"), rest))) + case CONS(h, t) => CONS(normalize(h), normalize(t)) + case _ => x + } + + def eval(x: Data, env: Environment): Data = { + val prevexp = curexp; + curexp = x; + if (trace) { + for (x <- range(1, indent)) Console.print(" "); + Console.println("===> " + x); + indent = indent + 1; + } + val result = eval1(x, env); + if (trace) { + indent = indent - 1; + for (x <- range(1, indent)) Console.print(" "); + Console.println("<=== " + result); + } + curexp = prevexp; + result + } + + def eval1(x: Data, env: Environment): Data = x match { + case SYM(name) => + env lookup name + case CONS(SYM("def"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) => + eval(z, env.extendRec(name, (env1 => eval(y, env1)))) + case CONS(SYM("val"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) => + eval(z, env.extend(name, eval(y, env))) + case CONS(SYM("lambda"), CONS(params, CONS(y, NIL()))) => + mkLambda(params, y, env) + case CONS(SYM("if"), CONS(c, CONS(t, CONS(e, NIL())))) => + if (toBoolean(eval(c, env))) eval(t, env) else eval(e, env) + case CONS(SYM("quote"), CONS(x, NIL())) => + x + case CONS(y, xs) => + apply(eval(y, env), toList(xs) map (x => eval(x, env))) + case NUM(_) => x + case STR(_) => x + case FUN(_) => x + case _ => + lispError("illegal term") + } + + def apply(fn: Data, args: List[Data]): Data = fn match { + case FUN(f) => f(args); + case _ => lispError("application of non-function: " + fn); + } + + def mkLambda(params: Data, expr: Data, env: Environment): Data = { + + def extendEnv(env: Environment, + ps: List[String], args: List[Data]): Environment = + (ps, args) match { + case (List(), List()) => + env + case (p :: ps1, arg :: args1) => + extendEnv(env.extend(p, arg), ps1, args1) + case _ => + lispError("wrong number of arguments") + } + + val ps: List[String] = toList(params) map { + case SYM(name) => name + case _ => sys.error("illegal parameter list"); + } + + FUN(args => eval(expr, extendEnv(env, ps, args))) + } + + val globalEnv = EmptyEnvironment + .extend("=", FUN({ + case List(NUM(arg1),NUM(arg2)) => NUM(if (arg1 == arg2) 1 else 0) + case List(STR(arg1),STR(arg2)) => NUM(if (arg1 == arg2) 1 else 0)})) + .extend("+", FUN({ + case List(NUM(arg1),NUM(arg2)) => NUM(arg1 + arg2) + case List(STR(arg1),STR(arg2)) => STR(arg1 + arg2)})) + .extend("-", FUN({ + case List(NUM(arg1),NUM(arg2)) => NUM(arg1 - arg2)})) + .extend("*", FUN({ + case List(NUM(arg1),NUM(arg2)) => NUM(arg1 * arg2)})) + .extend("/", FUN({ + case List(NUM(arg1),NUM(arg2)) => NUM(arg1 / arg2)})) + .extend("car", FUN({ + case List(CONS(x, xs)) => x})) + .extend("cdr", FUN({ + case List(CONS(x, xs)) => xs})) + .extend("null?", FUN({ + case List(NIL()) => NUM(1) + case _ => NUM(0)})) + .extend("cons", FUN({ + case List(x, y) => CONS(x, y)})); + + def evaluate(x: Data): Data = eval(normalize(x), globalEnv); + def evaluate(s: String): Data = evaluate(string2lisp(s)); + + def string2lisp(s: String): Data = { + val it = new LispTokenizer(s); + def parse(token: String): Data = { + if (token == "(") parseList + else if (token == ")") sys.error("unbalanced parentheses") + else if ('0' <= token.charAt(0) && token.charAt(0) <= '9') + NUM(token.toInt) + else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"') + STR(token.substring(1,token.length() - 1)) + else SYM(token) + } + def parseList: Data = { + val token = it.next; + if (token == ")") NIL() else CONS(parse(token), parseList) + } + parse(it.next) + } + + def lisp2string(d: Data): String = d.toString(); +} + +//############################################################################ +// Lisp Implementation Using Any + +object LispAny extends Lisp { + + import List._; + + type Data = Any; + + case class Lambda(f: List[Data] => Data); + + var curexp: Data = null; + var trace: Boolean = false; + var indent: Int = 0; + + def lispError[a](msg: String): a = + sys.error("error: " + msg + "\n" + curexp); + + trait Environment { + def lookup(n: String): Data; + def extendRec(name: String, expr: Environment => Data) = + new Environment { + def lookup(n: String): Data = + if (n == name) expr(this) else Environment.this.lookup(n); + } + def extend(name: String, v: Data) = extendRec(name, (env1 => v)); + } + val EmptyEnvironment = new Environment { + def lookup(n: String): Data = lispError("undefined: " + n); + } + + def asList(x: Data): List[Data] = x match { + case y: List[_] => y + case _ => lispError("malformed list: " + x) + } + + def asInt(x: Data): Int = x match { + case y: Int => y + case _ => lispError("not an integer: " + x) + } + + def asString(x: Data): String = x match { + case y: String => y + case _ => lispError("not a string: " + x) + } + + def asBoolean(x: Data): Boolean = x != 0 + + def normalize(x: Data): Data = x match { + case 'and :: x :: y :: Nil => + normalize('if :: x :: y :: 0 :: Nil) + case 'or :: x :: y :: Nil => + normalize('if :: x :: 1 :: y :: Nil) + case 'def :: (name :: args) :: body :: expr :: Nil => + normalize('def :: name :: ('lambda :: args :: body :: Nil) :: expr :: Nil) + case 'cond :: ('else :: expr :: Nil) :: rest => + normalize(expr); + case 'cond :: (test :: expr :: Nil) :: rest => + normalize('if :: test :: expr :: ('cond :: rest) :: Nil) + case 'cond :: 'else :: expr :: Nil => + normalize(expr) + case h :: t => + normalize(h) :: asList(normalize(t)) + case _ => + x + } + + def eval(x: Data, env: Environment): Data = { + val prevexp = curexp; + curexp = x; + if (trace) { + for (x <- range(1, indent)) Console.print(" "); + Console.println("===> " + x); + indent += 1; + } + val result = eval1(x, env); + if (trace) { + indent -= 1; + for (x <- range(1, indent)) Console.print(" "); + Console.println("<=== " + result); + } + curexp = prevexp; + result + } + + def eval1(x: Data, env: Environment): Data = x match { + case Symbol(name) => + env lookup name + case 'def :: Symbol(name) :: y :: z :: Nil => + eval(z, env.extendRec(name, (env1 => eval(y, env1)))) + case 'val :: Symbol(name) :: y :: z :: Nil => + eval(z, env.extend(name, eval(y, env))) + case 'lambda :: params :: y :: Nil => + mkLambda(params, y, env) + case 'if :: c :: y :: z :: Nil => + if (asBoolean(eval(c, env))) eval(y, env) else eval(z, env) + case 'quote :: y :: Nil => + y + case y :: z => + apply(eval(y, env), z map (x => eval(x, env))) + case Lambda(_) => x + case y: String => x + case y: Int => x + case y => lispError("illegal term") + } + + def lisp2string(x: Data): String = x match { + case Symbol(name) => name + case Nil => "()" + case y :: ys => + def list2string(xs: List[Data]): String = xs match { + case List() => "" + case y :: ys => " " + lisp2string(y) + list2string(ys) + } + "(" + lisp2string(y) + list2string(ys) + ")" + case _ => if (x.isInstanceOf[String]) "\"" + x + "\""; else x.toString() + } + + def apply(fn: Data, args: List[Data]): Data = fn match { + case Lambda(f) => f(args); + case _ => lispError("application of non-function: " + fn + " to " + args); + } + + def mkLambda(params: Data, expr: Data, env: Environment): Data = { + + def extendEnv(env: Environment, + ps: List[String], args: List[Data]): Environment = + (ps, args) match { + case (List(), List()) => + env + case (p :: ps1, arg :: args1) => + extendEnv(env.extend(p, arg), ps1, args1) + case _ => + lispError("wrong number of arguments") + } + + val ps: List[String] = asList(params) map { + case Symbol(name) => name + case _ => sys.error("illegal parameter list"); + } + + Lambda(args => eval(expr, extendEnv(env, ps, args))) + } + + val globalEnv = EmptyEnvironment + .extend("=", Lambda{ + case List(arg1, arg2) => if(arg1 == arg2) 1 else 0}) + .extend("+", Lambda{ + case List(arg1: Int, arg2: Int) => arg1 + arg2 + case List(arg1: String, arg2: String) => arg1 + arg2}) + .extend("-", Lambda{ + case List(arg1: Int, arg2: Int) => arg1 - arg2}) + .extend("*", Lambda{ + case List(arg1: Int, arg2: Int) => arg1 * arg2}) + .extend("/", Lambda{ + case List(arg1: Int, arg2: Int) => arg1 / arg2}) + .extend("nil", Nil) + .extend("cons", Lambda{ + case List(arg1, arg2) => arg1 :: asList(arg2)}) + .extend("car", Lambda{ + case List(x :: xs) => x}) + .extend("cdr", Lambda{ + case List(x :: xs) => xs}) + .extend("null?", Lambda{ + case List(Nil) => 1 + case _ => 0}); + + def evaluate(x: Data): Data = eval(normalize(x), globalEnv); + def evaluate(s: String): Data = evaluate(string2lisp(s)); + + def string2lisp(s: String): Data = { + val it = new LispTokenizer(s); + def parse(token: String): Data = { + if (token == "(") parseList + else if (token == ")") sys.error("unbalanced parentheses") + //else if (Character.isDigit(token.charAt(0))) + else if (token.charAt(0).isDigit) + token.toInt + else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"') + token.substring(1,token.length() - 1) + else Symbol(token) + } + def parseList: List[Data] = { + val token = it.next; + if (token == ")") Nil else parse(token) :: parseList + } + parse(it.next) + } +} + +//############################################################################ +// List User + +class LispUser(lisp: Lisp) { + + import lisp._; + + def evaluate(s: String) = lisp2string(lisp.evaluate(s)); + + def run = { + + Console.println(string2lisp("(lambda (x) (+ (* x x) 1))").asInstanceOf[AnyRef]); + Console.println(lisp2string(string2lisp("(lambda (x) (+ (* x x) 1))"))); + Console.println; + + Console.println("( '(1 2 3)) = " + evaluate(" (quote(1 2 3))")); + Console.println("(car '(1 2 3)) = " + evaluate("(car (quote(1 2 3)))")); + Console.println("(cdr '(1 2 3)) = " + evaluate("(cdr (quote(1 2 3)))")); + Console.println("(null? '(2 3)) = " + evaluate("(null? (quote(2 3)))")); + Console.println("(null? '()) = " + evaluate("(null? (quote()))")); + Console.println; + + Console.println("faculty(10) = " + evaluate( + "(def (faculty n) " + + "(if (= n 0) " + + "1 " + + "(* n (faculty (- n 1)))) " + + "(faculty 10))")); + Console.println("faculty(10) = " + evaluate( + "(def (faculty n) " + + "(cond " + + "((= n 0) 1) " + + "(else (* n (faculty (- n 1))))) " + + "(faculty 10))")); + Console.println("foobar = " + evaluate( + "(def (foo n) " + + "(cond " + + "((= n 0) \"a\")" + + "((= n 1) \"b\")" + + "((= (/ n 2) 1) " + + "(cond " + + "((= n 2) \"c\")" + + "(else \"d\")))" + + "(else " + + "(def (bar m) " + + "(cond " + + "((= m 0) \"e\")" + + "((= m 1) \"f\")" + + "(else \"z\"))" + + "(bar (- n 4)))))" + + "(val nil (quote ())" + + "(val v1 (foo 0) " + + "(val v2 (+ (foo 1) (foo 2)) " + + "(val v3 (+ (+ (foo 3) (foo 4)) (foo 5)) " + + "(val v4 (foo 6) " + + "(cons v1 (cons v2 (cons v3 (cons v4 nil))))))))))")); + Console.println; + } +} + +//############################################################################ +// Main + +object Test { + def main(args: Array[String]) { + new LispUser(LispCaseClasses).run; + new LispUser(LispAny).run; + () + } +} + +//############################################################################ diff --git a/test/files/run/t7008-scala-defined.flags b/test/files/run/t7008-scala-defined.flags deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/files/run/t7008-scala-defined/Test_3.scala b/test/files/run/t7008-scala-defined/Test_3.scala index 26178142ab..ee7b9d9cde 100644 --- a/test/files/run/t7008-scala-defined/Test_3.scala +++ b/test/files/run/t7008-scala-defined/Test_3.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ import scala.reflect.runtime.universe._ object Test extends App { diff --git a/test/files/run/t7582.check b/test/files/run/t7582.check index 0cfbf08886..58d0f19f5d 100644 --- a/test/files/run/t7582.check +++ b/test/files/run/t7582.check @@ -1 +1,6 @@ +InlineHolder.scala:9: warning: p1/InlineHolder$::inlinable()I is annotated @inline but could not be inlined: +The callee p1/InlineHolder$::inlinable()I contains the instruction INVOKESTATIC p1/PackageProtectedJava.protectedMethod ()I +that would cause an IllegalAccessError when inlined into class O$. + def x = p1.InlineHolder.inlinable + ^ 2 diff --git a/test/files/run/t7582.flags b/test/files/run/t7582.flags index 422d6be431..1f45833eff 100644 --- a/test/files/run/t7582.flags +++ b/test/files/run/t7582.flags @@ -1 +1 @@ --Yopt:l:classpath \ No newline at end of file +-Yopt:l:classpath -Yopt-warnings \ No newline at end of file diff --git a/test/files/run/t7582/InlineHolder.scala b/test/files/run/t7582/InlineHolder.scala index 3cbf233ce1..a18b9effaa 100644 --- a/test/files/run/t7582/InlineHolder.scala +++ b/test/files/run/t7582/InlineHolder.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ package p1 { object InlineHolder { @inline def inlinable = p1.PackageProtectedJava.protectedMethod() + 1 diff --git a/test/files/run/t7582b.check b/test/files/run/t7582b.check index 0cfbf08886..58d0f19f5d 100644 --- a/test/files/run/t7582b.check +++ b/test/files/run/t7582b.check @@ -1 +1,6 @@ +InlineHolder.scala:9: warning: p1/InlineHolder$::inlinable()I is annotated @inline but could not be inlined: +The callee p1/InlineHolder$::inlinable()I contains the instruction INVOKESTATIC p1/PackageProtectedJava.protectedMethod ()I +that would cause an IllegalAccessError when inlined into class O$. + def x = p1.InlineHolder.inlinable + ^ 2 diff --git a/test/files/run/t7582b.flags b/test/files/run/t7582b.flags index 422d6be431..1f45833eff 100644 --- a/test/files/run/t7582b.flags +++ b/test/files/run/t7582b.flags @@ -1 +1 @@ --Yopt:l:classpath \ No newline at end of file +-Yopt:l:classpath -Yopt-warnings \ No newline at end of file diff --git a/test/files/run/t7582b/InlineHolder.scala b/test/files/run/t7582b/InlineHolder.scala index 3cbf233ce1..a18b9effaa 100644 --- a/test/files/run/t7582b/InlineHolder.scala +++ b/test/files/run/t7582b/InlineHolder.scala @@ -1,6 +1,3 @@ -/* - * filter: inliner warning; re-run with - */ package p1 { object InlineHolder { @inline def inlinable = p1.PackageProtectedJava.protectedMethod() + 1 diff --git a/test/files/run/t7807.check b/test/files/run/t7807.check new file mode 100644 index 0000000000..fd22077f2e --- /dev/null +++ b/test/files/run/t7807.check @@ -0,0 +1,3 @@ +... +... +... diff --git a/test/files/run/t7807.scala b/test/files/run/t7807.scala new file mode 100644 index 0000000000..8e3099ec14 --- /dev/null +++ b/test/files/run/t7807.scala @@ -0,0 +1,21 @@ +object Test { + def main(args: Array[String]) { + try { + println("...") + } + finally { + try { + println("...") + } + finally { + try { + println("...") + } + catch { + case ct: scala.util.control.ControlThrowable => throw(ct) + case t: Throwable => t.printStackTrace() + } + } + } + } +} diff --git a/test/junit/scala/issues/OptimizedBytecodeTest.scala b/test/junit/scala/issues/OptimizedBytecodeTest.scala new file mode 100644 index 0000000000..3c6f1ff25e --- /dev/null +++ b/test/junit/scala/issues/OptimizedBytecodeTest.scala @@ -0,0 +1,331 @@ +package scala.issues + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.tools.asm.Opcodes._ +import org.junit.Assert._ + +import scala.tools.nsc.backend.jvm.{AsmUtils, CodeGenTools} + +import CodeGenTools._ +import scala.tools.partest.ASMConverters +import ASMConverters._ +import AsmUtils._ + +import scala.tools.testing.ClearAfterClass + +object OptimizedBytecodeTest extends ClearAfterClass.Clearable { + val args = "-Yopt:l:classpath -Yopt-warnings" + var compiler = newCompiler(extraArgs = args) + def clear(): Unit = { compiler = null } +} + +@RunWith(classOf[JUnit4]) +class OptimizedBytecodeTest extends ClearAfterClass { + ClearAfterClass.stateToClear = OptimizedBytecodeTest + + val compiler = OptimizedBytecodeTest.compiler + + @Test + def t2171(): Unit = { + val code = + """class C { + | final def m(msg: => String) = try 0 catch { case ex: Throwable => println(msg) } + | def t(): Unit = while (true) m("...") + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertSameCode(getSingleMethod(c, "t").instructions.dropNonOp, List(Label(0), Jump(GOTO, Label(0)))) + } + + @Test + def t3430(): Unit = { + val code = + """class C { + | final def m(f: String => Boolean) = f("a") + | def t(): Boolean = + | m { s1 => + | m { s2 => + | while (true) { } + | true + | } + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List(LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN)) + + assertEquals( + getSingleMethod(c, "C$$$anonfun$1").instructions.summary, + List(LDC, "C$$$anonfun$2", IRETURN)) + + assertEquals( + getSingleMethod(c, "C$$$anonfun$2").instructions.summary, + List(-1 /*A*/, GOTO /*A*/)) + } + + @Test + def t3252(): Unit = { + val code = + """class C { + | def t(x: Boolean): Thread = { + | g { + | x match { + | case false => Tat.h { } + | } + | } + | } + | + | private def g[T](block: => T) = ??? + |} + |object Tat { + | def h(block: => Unit): Nothing = ??? + |} + """.stripMargin + val List(c, t, tMod) = compileClasses(compiler)(code, allowMessage = _.msg.contains("not be exhaustive")) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List(GETSTATIC, "$qmark$qmark$qmark", ATHROW)) + } + + @Test + def t6157(): Unit = { + val code = + """class C { + | def t = println(ErrorHandler.defaultIfIOException("String")("String")) + |} + |object ErrorHandler { + | import java.io.IOException + | @inline + | def defaultIfIOException[T](default: => T)(closure: => T): T = try closure catch { + | case e: IOException => default + | } + |} + """.stripMargin + + val msg = + """ErrorHandler$::defaultIfIOException(Lscala/Function0;Lscala/Function0;)Ljava/lang/Object; is annotated @inline but could not be inlined: + |The operand stack at the callsite in C::t()V contains more values than the + |arguments expected by the callee ErrorHandler$::defaultIfIOException(Lscala/Function0;Lscala/Function0;)Ljava/lang/Object;. These values would be discarded + |when entering an exception handler declared in the inlined method.""".stripMargin + + compileClasses(compiler)(code, allowMessage = _.msg == msg) + } + + @Test + def t6547(): Unit = { // "pos" test -- check that it compiles + val code = + """trait ConfigurableDefault[@specialized V] { + | def fillArray(arr: Array[V], v: V) = (arr: Any) match { + | case x: Array[Int] => null + | case x: Array[Long] => v.asInstanceOf[Long] + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t8062(): Unit = { + val c1 = + """package warmup + |object Warmup { def filter[A](p: Any => Boolean): Any = filter[Any](p) } + """.stripMargin + val c2 = "class C { def t = warmup.Warmup.filter[Any](x => false) }" + val List(c, _, _) = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args) + assertInvoke(getSingleMethod(c, "t"), "warmup/Warmup$", "filter") + } + + @Test + def t8306(): Unit = { // "pos" test + val code = + """class C { + | def foo: Int = 123 + | lazy val extension: Int = foo match { + | case idx if idx != -1 => 15 + | case _ => 17 + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t8359(): Unit = { // "pos" test + // This is a minimization of code that crashed the compiler during bootstrapping + // in the first iteration of https://github.com/scala/scala/pull/4373, the PR + // that adjusted the order of free and declared params in LambdaLift. + + // Was: + // java.lang.AssertionError: assertion failed: + // Record Record(<$anon: Function1>,Map(value a$1 -> Deref(LocalVar(value b)))) does not contain a field value b$1 + // at scala.tools.nsc.Global.assert(Global.scala:262) + // at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:113) + // at scala.tools.nsc.backend.icode.analysis.CopyPropagation$copyLattice$State.getFieldNonRecordValue(CopyPropagation.scala:122) + // at scala.tools.nsc.backend.opt.ClosureElimination$ClosureElim$$anonfun$analyzeMethod$1$$anonfun$apply$2.replaceFieldAccess$1(ClosureElimination.scala:124) + val code = + """package test + |class Typer { + | def bar(a: Boolean, b: Boolean): Unit = { + | @inline + | def baz(): Unit = { + | ((_: Any) => (Typer.this, a, b)).apply("") + | } + | ((_: Any) => baz()).apply("") + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t9123(): Unit = { // "pos" test + val code = + """trait Setting { + | type T + | def value: T + |} + |object Test { + | def test(x: Some[Setting]) = x match { + | case Some(dep) => Some(dep.value) map (_ => true) + | } + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def traitForceInfo(): Unit = { + // This did NOT crash unless it's in the interactive package. + // error: java.lang.AssertionError: assertion failed: trait Contexts.NoContext$ linkedModule: List() + // at scala.Predef$.assert(Predef.scala:160) + // at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.innerSymbol$1(ClassfileParser.scala:1211) + // at scala.tools.nsc.symtab.classfile.ClassfileParser$innerClasses$.classSymbol(ClassfileParser.scala:1223) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.classNameToSymbol(ClassfileParser.scala:489) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:757) + // at scala.tools.nsc.symtab.classfile.ClassfileParser.sig2type$1(ClassfileParser.scala:789) + val code = + """package scala.tools.nsc + |package interactive + | + |trait MyContextTrees { + | val self: Global + | val NoContext = self.analyzer.NoContext + |} + """.stripMargin + compileClasses(compiler)(code) + } + + @Test + def t9160(): Unit = { + val code = + """class C { + | def getInt: Int = 0 + | def t(trees: Object): Int = { + | trees match { + | case Some(elems) => + | case tree => getInt + | } + | 55 + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List( + ALOAD /*1*/, INSTANCEOF /*Some*/, IFNE /*A*/, + ALOAD /*0*/, "getInt", POP, + -1 /*A*/, BIPUSH, IRETURN)) + } + + @Test + def t8796(): Unit = { + val code = + """final class C { + | def pr(): Unit = () + | def t(index: Int): Unit = index match { + | case 0 => pr() + | case 1 => pr() + | case _ => t(index - 2) + | } + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code) + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List( + -1 /*A*/, ILOAD /*1*/, TABLESWITCH, + -1, ALOAD, "pr", RETURN, + -1, ALOAD, "pr", RETURN, + -1, ILOAD, ICONST_2, ISUB, ISTORE, GOTO /*A*/)) + } + + @Test + def t8524(): Unit = { + val c1 = + """package library + |object Library { + | @inline def pleaseInlineMe() = 1 + | object Nested { @inline def pleaseInlineMe() = 2 } + |} + """.stripMargin + + val c2 = + """class C { + | def t = library.Library.pleaseInlineMe() + library.Library.Nested.pleaseInlineMe() + |} + """.stripMargin + + val cls = compileClassesSeparately(List(c1, c2), extraArgs = OptimizedBytecodeTest.args) + val c = cls.find(_.name == "C").get + assertEquals( + getSingleMethod(c, "t").instructions.summary, + List( + GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, // module load and null checks not yet eliminated + -1, ICONST_1, GETSTATIC, IFNONNULL, ACONST_NULL, ATHROW, + -1, ICONST_2, IADD, IRETURN)) + } + + @Test + def privateInline(): Unit = { + val code = + """final class C { + | private var x1 = false + | var x2 = false + | + | @inline private def wrapper1[T](body: => T): T = { + | val saved = x1 + | x1 = true + | try body + | finally x1 = saved + | } + | + | @inline private def wrapper2[T](body: => T): T = { + | val saved = x2 + | x2 = true + | try body + | finally x2 = saved + | } + | // inlined + | def f1a() = wrapper1(5) + | // not inlined: even after inlining `identity`, the Predef module is already on the stack for the + | // subsequent null check (the receiver of an inlined method, in this case Predef, is checked for + | // nullness, to ensure an NPE is thrown) + | def f1b() = identity(wrapper1(5)) + | + | def f2a() = wrapper2(5) // inlined + | def f2b() = identity(wrapper2(5)) // not inlined + |} + """.stripMargin + val List(c) = compileClasses(compiler)(code, allowMessage = _.msg.contains("exception handler declared in the inlined method")) + assertInvoke(getSingleMethod(c, "f1a"), "C", "C$$$anonfun$1") + assertInvoke(getSingleMethod(c, "f1b"), "C", "wrapper1") + assertInvoke(getSingleMethod(c, "f2a"), "C", "C$$$anonfun$3") + assertInvoke(getSingleMethod(c, "f2b"), "C", "wrapper2") + } +} diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala index cef27b4d87..4d345ab9f7 100644 --- a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala +++ b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala @@ -134,4 +134,29 @@ class PatmatBytecodeTest extends ClearAfterClass { NEW, DUP, ALOAD /*1*/, "", ATHROW, /*R*/ -1, ALOAD /*2*/, ARETURN)) } + + @Test + def t6941(): Unit = { + val code = + """class C { + | def a(xs: List[Int]) = xs match { + | case x :: _ => x + | } + | def b(xs: List[Int]) = xs match { + | case xs: ::[Int] => xs.head + | } + |} + """.stripMargin + val c = compileClasses(optCompiler)(code, allowMessage = _.msg.contains("may not be exhaustive")).head + + val expected = List( + ALOAD /*1*/ , INSTANCEOF /*::*/ , IFEQ /*A*/ , + ALOAD, CHECKCAST /*::*/ , "head", "unboxToInt", + ISTORE, GOTO /*B*/ , + -1 /*A*/ , NEW /*MatchError*/ , DUP, ALOAD /*1*/ , "", ATHROW, + -1 /*B*/ , ILOAD, IRETURN) + + assertEquals(textify(findAsmMethod(c, "a")), getSingleMethod(c, "a").instructions.summary, expected) + assertEquals(textify(findAsmMethod(c, "b")), getSingleMethod(c, "b").instructions.summary, expected) + } } diff --git a/test/pending/run/private-inline.check b/test/pending/run/private-inline.check deleted file mode 100644 index e71aec2fcf..0000000000 --- a/test/pending/run/private-inline.check +++ /dev/null @@ -1,13 +0,0 @@ -private-inline.scala:24: warning: Could not inline required method wrapper1 because callee contains exception handlers / finally clause, and is invoked with non-empty operand stack. - def f1b() = identity(wrapper1(5)) - ^ -private-inline.scala:24: warning: At the end of the day, could not inline @inline-marked method wrapper1 - def f1b() = identity(wrapper1(5)) - ^ -private-inline.scala:29: warning: Could not inline required method wrapper2 because callee contains exception handlers / finally clause, and is invoked with non-empty operand stack. - def f2b() = identity(wrapper2(5)) - ^ -private-inline.scala:29: warning: At the end of the day, could not inline @inline-marked method wrapper2 - def f2b() = identity(wrapper2(5)) - ^ -20 diff --git a/test/pending/run/private-inline.flags b/test/pending/run/private-inline.flags deleted file mode 100644 index c550fdce16..0000000000 --- a/test/pending/run/private-inline.flags +++ /dev/null @@ -1 +0,0 @@ --optimise -Yinline-warnings -Ybackend:GenASM diff --git a/test/pending/run/private-inline.scala b/test/pending/run/private-inline.scala deleted file mode 100644 index 60fef9efca..0000000000 --- a/test/pending/run/private-inline.scala +++ /dev/null @@ -1,52 +0,0 @@ - -final class A { - private var x1 = false - var x2 = false - - // manipulates private var - @inline private def wrapper1[T](body: => T): T = { - val saved = x1 - x1 = true - try body - finally x1 = saved - } - // manipulates public var - @inline private def wrapper2[T](body: => T): T = { - val saved = x2 - x2 = true - try body - finally x2 = saved - } - - // not inlined - def f1a() = wrapper1(5) - // inlined! - def f1b() = identity(wrapper1(5)) - - // not inlined - def f2a() = wrapper2(5) - // inlined! - def f2b() = identity(wrapper2(5)) -} - -object Test { - def methodClasses = List("f1a", "f2a") map ("A$$anonfun$" + _ + "$1") - - def main(args: Array[String]): Unit = { - val a = new A - import a._ - println(f1a() + f1b() + f2a() + f2b()) - - // Don't know how else to test this: all these should have been - // inlined, so all should fail. - methodClasses foreach { clazz => - - val foundClass = ( - try Class.forName(clazz) - catch { case _: Throwable => null } - ) - - assert(foundClass == null, foundClass) - } - } -} -- cgit v1.2.3