summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala22
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala281
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/library/scala/collection/immutable/ListSet.scala6
-rw-r--r--src/library/scala/collection/immutable/Vector.scala6
-rw-r--r--src/library/scala/collection/mutable/AnyRefMap.scala6
-rw-r--r--src/library/scala/collection/mutable/ArrayBuilder.scala153
-rw-r--r--src/library/scala/collection/mutable/Builder.scala16
-rw-r--r--src/library/scala/collection/mutable/GrowingBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/LazyBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/ListBuffer.scala6
-rw-r--r--src/library/scala/collection/mutable/LongMap.scala6
-rw-r--r--src/library/scala/collection/mutable/MapBuilder.scala2
-rw-r--r--src/library/scala/collection/mutable/ReusableBuilder.scala51
-rw-r--r--src/library/scala/collection/mutable/SetBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/StringBuilder.scala8
-rw-r--r--src/library/scala/collection/mutable/WrappedArrayBuilder.scala13
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala16
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala4
-rw-r--r--test/files/jvm/t6941.check1
-rw-r--r--test/files/jvm/t6941.flags1
-rw-r--r--test/files/jvm/t6941/Analyzed_1.flags1
-rw-r--r--test/files/jvm/t6941/Analyzed_1.scala11
-rw-r--r--test/files/jvm/t6941/test.scala15
-rw-r--r--test/files/neg/choices.check6
-rw-r--r--test/files/neg/partestInvalidFlag.check4
-rw-r--r--test/files/neg/partestInvalidFlag.flags1
-rw-r--r--test/files/neg/partestInvalidFlag.scala1
-rw-r--r--test/files/pos/t2171.flags1
-rw-r--r--test/files/pos/t2171.scala7
-rw-r--r--test/files/pos/t3252.flags1
-rw-r--r--test/files/pos/t3252.scala15
-rw-r--r--test/files/pos/t3420.flags2
-rw-r--r--test/files/pos/t3430.flags1
-rw-r--r--test/files/pos/t3430.scala13
-rw-r--r--test/files/pos/t4579.flags1
-rw-r--r--test/files/pos/t4840.flags2
-rw-r--r--test/files/pos/t6157.flags1
-rw-r--r--test/files/pos/t6157.scala25
-rw-r--r--test/files/pos/t6547.flags1
-rw-r--r--test/files/pos/t6547.scala6
-rw-r--r--test/files/pos/t8062.flags1
-rw-r--r--test/files/pos/t8062/A_1.scala5
-rw-r--r--test/files/pos/t8062/B_2.scala3
-rw-r--r--test/files/pos/t8306.flags1
-rw-r--r--test/files/pos/t8306.scala8
-rw-r--r--test/files/pos/t8359-closelim-crash.flags1
-rw-r--r--test/files/pos/t8359-closelim-crash.scala23
-rw-r--r--test/files/pos/t9123.flags1
-rw-r--r--test/files/pos/t9123.scala10
-rw-r--r--test/files/pos/trait-force-info.flags1
-rw-r--r--test/files/pos/trait-force-info.scala18
-rw-r--r--test/files/run/elidable-opt.scala3
-rw-r--r--test/files/run/lisp.check26
-rw-r--r--test/files/run/lisp.scala (renamed from test/files/pos/t4579.scala)2
-rw-r--r--test/files/run/t7008-scala-defined.flags0
-rw-r--r--test/files/run/t7008-scala-defined/Test_3.scala3
-rw-r--r--test/files/run/t7582.check5
-rw-r--r--test/files/run/t7582.flags2
-rw-r--r--test/files/run/t7582/InlineHolder.scala3
-rw-r--r--test/files/run/t7582b.check5
-rw-r--r--test/files/run/t7582b.flags2
-rw-r--r--test/files/run/t7582b/InlineHolder.scala3
-rw-r--r--test/files/run/t7807.check3
-rw-r--r--test/files/run/t7807.scala21
-rw-r--r--test/junit/scala/collection/ReusableBuildersTest.scala48
-rw-r--r--test/junit/scala/issues/OptimizedBytecodeTest.scala331
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala70
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala23
-rw-r--r--test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala25
-rw-r--r--test/pending/run/private-inline.check13
-rw-r--r--test/pending/run/private-inline.flags1
-rw-r--r--test/pending/run/private-inline.scala52
-rw-r--r--versions.properties2
78 files changed, 935 insertions, 525 deletions
diff --git a/build.xml b/build.xml
index 0a41870b21..78c7a9a230 100644
--- a/build.xml
+++ b/build.xml
@@ -483,6 +483,8 @@ TODO:
<property name="scalac.args.quick" value="${scalac.args.all}"/>
<property name="scalac.args.strap" value="${scalac.args.quick}"/>
+ <property name="partest.scalac_opts" value=""/> <!-- set default value, otherwise the property name will be passed to partest if undefined -->
+
<!-- This is the start time for the distribution -->
<tstamp prefix="time">
<format property="human" pattern="d MMMM yyyy, HH:mm:ss" locale="en,US"/>
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index 4a10756468..328a8187c8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -40,7 +40,7 @@ abstract class BCodeIdiomatic extends SubComponent {
if (emitStackMapFrame) asm.ClassWriter.COMPUTE_FRAMES else 0
)
- val StringBuilderClassName = "scala/collection/mutable/StringBuilder"
+ lazy val JavaStringBuilderClassName = jlStringBuilderRef.internalName
val EMPTY_STRING_ARRAY = Array.empty[String]
val EMPTY_INT_ARRAY = Array.empty[Int]
@@ -184,10 +184,10 @@ abstract class BCodeIdiomatic extends SubComponent {
* can-multi-thread
*/
final def genStartConcat(pos: Position): Unit = {
- jmethod.visitTypeInsn(Opcodes.NEW, StringBuilderClassName)
+ jmethod.visitTypeInsn(Opcodes.NEW, JavaStringBuilderClassName)
jmethod.visitInsn(Opcodes.DUP)
invokespecial(
- StringBuilderClassName,
+ JavaStringBuilderClassName,
INSTANCE_CONSTRUCTOR_NAME,
"()V",
pos
@@ -198,21 +198,23 @@ abstract class BCodeIdiomatic extends SubComponent {
* can-multi-thread
*/
final def genStringConcat(el: BType, pos: Position): Unit = {
-
- val jtype =
- if (el.isArray || el.isClass) ObjectRef
- else el
+ val jtype = el match {
+ case ct: ClassBType if ct.isSubtypeOf(StringRef).get => StringRef
+ case ct: ClassBType if ct.isSubtypeOf(jlStringBufferRef).get => jlStringBufferRef
+ case ct: ClassBType if ct.isSubtypeOf(jlCharSequenceRef).get => jlCharSequenceRef
+ case rt: RefBType => ObjectRef
+ case pt: PrimitiveBType => pt // Currently this ends up being boxed in erasure
+ }
val bt = MethodBType(List(jtype), jlStringBuilderRef)
-
- invokevirtual(StringBuilderClassName, "append", bt.descriptor, pos)
+ invokevirtual(JavaStringBuilderClassName, "append", bt.descriptor, pos)
}
/*
* can-multi-thread
*/
final def genEndConcat(pos: Position): Unit = {
- invokevirtual(StringBuilderClassName, "toString", "()Ljava/lang/String;", pos)
+ invokevirtual(JavaStringBuilderClassName, "toString", "()Ljava/lang/String;", pos)
}
/*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 8bb71a386f..6d322d1a34 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -95,7 +95,9 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val ObjectRef : ClassBType = classBTypeFromSymbol(ObjectClass)
lazy val StringRef : ClassBType = classBTypeFromSymbol(StringClass)
lazy val PredefRef : ClassBType = classBTypeFromSymbol(PredefModule.moduleClass)
- lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(StringBuilderClass)
+ lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(JavaStringBuilderClass)
+ lazy val jlStringBufferRef : ClassBType = classBTypeFromSymbol(JavaStringBufferClass)
+ lazy val jlCharSequenceRef : ClassBType = classBTypeFromSymbol(JavaCharSequenceClass)
lazy val jlThrowableRef : ClassBType = classBTypeFromSymbol(ThrowableClass)
lazy val jlCloneableRef : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
lazy val jiSerializableRef : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
@@ -343,6 +345,8 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def StringRef : ClassBType = _coreBTypes.StringRef
def PredefRef : ClassBType = _coreBTypes.PredefRef
def jlStringBuilderRef : ClassBType = _coreBTypes.jlStringBuilderRef
+ def jlStringBufferRef : ClassBType = _coreBTypes.jlStringBufferRef
+ def jlCharSequenceRef : ClassBType = _coreBTypes.jlCharSequenceRef
def jlThrowableRef : ClassBType = _coreBTypes.jlThrowableRef
def jlCloneableRef : ClassBType = _coreBTypes.jlCloneableRef
def jiSerializableRef : ClassBType = _coreBTypes.jiSerializableRef
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
index 4ecaf17a10..16fe2e5cff 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala
@@ -21,7 +21,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) {
import backendUtils._
/**
- * Eliminate box-unbox paris within `method`. Such appear commonly after closure elimination:
+ * Eliminate box-unbox pairs within `method`. Such appear commonly after closure elimination:
*
* def t2 = {
* val f = (b: Byte, i: Int) => i + b // no specialized variant for this function type
@@ -767,7 +767,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) {
private def isSpecializedTupleClass(tupleClass: InternalName) = specializedTupleClassR.pattern.matcher(tupleClass).matches
private val specializedTupleGetterR = "_[12]\\$mc[IJDCZ]\\$sp".r
- private def isSpecializedTupleGetter(mi: MethodInsnNode) = specializedTupleGetterR.pattern.matcher(mi.name)matches
+ private def isSpecializedTupleGetter(mi: MethodInsnNode) = specializedTupleGetterR.pattern.matcher(mi.name).matches
private val tupleGetterR = "_\\d\\d?".r
private def isTupleGetter(mi: MethodInsnNode) = tupleGetterR.pattern.matcher(mi.name).matches
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/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."
diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala
index a65e25ed6e..98b91f7c84 100644
--- a/src/library/scala/collection/immutable/ListSet.scala
+++ b/src/library/scala/collection/immutable/ListSet.scala
@@ -12,7 +12,7 @@ package immutable
import generic._
import scala.annotation.tailrec
-import mutable.Builder
+import mutable.{Builder, ReusableBuilder}
/** $factoryInfo
* @define Coll immutable.ListSet
@@ -32,8 +32,10 @@ object ListSet extends ImmutableSetFactory[ListSet] {
* a time to a list backed set puts the "squared" in N^2. There is a
* temporary space cost, but it's improbable a list backed set could
* become large enough for this to matter given its pricy element lookup.
+ *
+ * This builder is reusable.
*/
- class ListSetBuilder[Elem](initial: ListSet[Elem]) extends Builder[Elem, ListSet[Elem]] {
+ class ListSetBuilder[Elem](initial: ListSet[Elem]) extends ReusableBuilder[Elem, ListSet[Elem]] {
def this() = this(empty[Elem])
protected val elems = (new mutable.ListBuffer[Elem] ++= initial).reverse
protected val seen = new mutable.HashSet[Elem] ++= initial
diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala
index 5a9734a99e..539ae9c387 100644
--- a/src/library/scala/collection/immutable/Vector.scala
+++ b/src/library/scala/collection/immutable/Vector.scala
@@ -13,7 +13,7 @@ package immutable
import scala.annotation.unchecked.uncheckedVariance
import scala.compat.Platform
import scala.collection.generic._
-import scala.collection.mutable.Builder
+import scala.collection.mutable.{Builder, ReusableBuilder}
import scala.collection.parallel.immutable.ParVector
/** Companion object to the Vector class
@@ -704,8 +704,8 @@ extends AbstractIterator[A]
}
}
-
-final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] {
+/** A class to build instances of `Vector`. This builder is reusable. */
+final class VectorBuilder[A]() extends ReusableBuilder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] {
// possible alternative: start with display0 = null, blockIndex = -32, lo = 32
// to avoid allocating initial array if the result will be empty anyways
diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala
index af7600ad3d..2ed5bbea60 100644
--- a/src/library/scala/collection/mutable/AnyRefMap.scala
+++ b/src/library/scala/collection/mutable/AnyRefMap.scala
@@ -427,7 +427,11 @@ object AnyRefMap {
def apply(): AnyRefMapBuilder[J, U] = new AnyRefMapBuilder[J, U]
}
- final class AnyRefMapBuilder[K <: AnyRef, V] extends Builder[(K, V), AnyRefMap[K, V]] {
+ /** A builder for instances of `AnyRefMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] {
private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V]
def +=(entry: (K, V)): this.type = {
elems += entry
diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala
index ac78ab823b..549ffef565 100644
--- a/src/library/scala/collection/mutable/ArrayBuilder.scala
+++ b/src/library/scala/collection/mutable/ArrayBuilder.scala
@@ -18,7 +18,7 @@ import scala.reflect.ClassTag
*
* @tparam T the type of the elements for the builder.
*/
-abstract class ArrayBuilder[T] extends Builder[T, Array[T]] with Serializable
+abstract class ArrayBuilder[T] extends ReusableBuilder[T, Array[T]] with Serializable
/** A companion object for array builders.
*
@@ -49,6 +49,8 @@ object ArrayBuilder {
/** A class for array builders for arrays of reference types.
*
+ * This builder can be reused.
+ *
* @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound.
*/
@deprecatedInheritance("ArrayBuilder.ofRef is an internal implementation not intended for subclassing.", "2.11.0")
@@ -98,12 +100,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -115,7 +118,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofRef"
}
- /** A class for array builders for arrays of `byte`s. */
+ /** A class for array builders for arrays of `byte`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofByte is an internal implementation not intended for subclassing.", "2.11.0")
class ofByte extends ArrayBuilder[Byte] {
@@ -163,12 +166,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -180,7 +184,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofByte"
}
- /** A class for array builders for arrays of `short`s. */
+ /** A class for array builders for arrays of `short`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofShort is an internal implementation not intended for subclassing.", "2.11.0")
class ofShort extends ArrayBuilder[Short] {
@@ -228,12 +232,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -245,7 +250,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofShort"
}
- /** A class for array builders for arrays of `char`s. */
+ /** A class for array builders for arrays of `char`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofChar is an internal implementation not intended for subclassing.", "2.11.0")
class ofChar extends ArrayBuilder[Char] {
@@ -293,12 +298,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -310,7 +316,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofChar"
}
- /** A class for array builders for arrays of `int`s. */
+ /** A class for array builders for arrays of `int`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofInt is an internal implementation not intended for subclassing.", "2.11.0")
class ofInt extends ArrayBuilder[Int] {
@@ -358,12 +364,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -375,7 +382,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofInt"
}
- /** A class for array builders for arrays of `long`s. */
+ /** A class for array builders for arrays of `long`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofLong is an internal implementation not intended for subclassing.", "2.11.0")
class ofLong extends ArrayBuilder[Long] {
@@ -423,12 +430,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -440,7 +448,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofLong"
}
- /** A class for array builders for arrays of `float`s. */
+ /** A class for array builders for arrays of `float`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofFloat is an internal implementation not intended for subclassing.", "2.11.0")
class ofFloat extends ArrayBuilder[Float] {
@@ -488,12 +496,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -505,7 +514,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofFloat"
}
- /** A class for array builders for arrays of `double`s. */
+ /** A class for array builders for arrays of `double`s. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofDouble is an internal implementation not intended for subclassing.", "2.11.0")
class ofDouble extends ArrayBuilder[Double] {
@@ -553,12 +562,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -570,7 +580,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofDouble"
}
- /** A class for array builders for arrays of `boolean`s. */
+ /** A class for array builders for arrays of `boolean`s. It can be reused. */
class ofBoolean extends ArrayBuilder[Boolean] {
private var elems: Array[Boolean] = _
@@ -617,12 +627,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -634,65 +645,33 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofBoolean"
}
- /** A class for array builders for arrays of `Unit` type. */
+ /** A class for array builders for arrays of `Unit` type. It can be reused. */
@deprecatedInheritance("ArrayBuilder.ofUnit is an internal implementation not intended for subclassing.", "2.11.0")
class ofUnit extends ArrayBuilder[Unit] {
- private var elems: Array[Unit] = _
- private var capacity: Int = 0
private var size: Int = 0
- private def mkArray(size: Int): Array[Unit] = {
- val newelems = new Array[Unit](size)
- if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
- newelems
- }
-
- private def resize(size: Int) {
- elems = mkArray(size)
- capacity = size
- }
-
- override def sizeHint(size: Int) {
- if (capacity < size) resize(size)
- }
-
- private def ensureSize(size: Int) {
- if (capacity < size || capacity == 0) {
- var newsize = if (capacity == 0) 16 else capacity * 2
- while (newsize < size) newsize *= 2
- resize(newsize)
- }
- }
-
def +=(elem: Unit): this.type = {
- ensureSize(size + 1)
- elems(size) = elem
size += 1
this
}
- override def ++=(xs: TraversableOnce[Unit]): this.type = xs match {
- case xs: WrappedArray.ofUnit =>
- ensureSize(this.size + xs.length)
- Array.copy(xs.array, 0, elems, this.size, xs.length)
- size += xs.length
- this
- case _ =>
- super.++=(xs)
+ override def ++=(xs: TraversableOnce[Unit]): this.type = {
+ size += xs.size
+ this
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
- else mkArray(size)
+ val ans = new Array[Unit](size)
+ var i = 0
+ while (i < size) { ans(i) = (); i += 1 }
+ ans
}
override def equals(other: Any): Boolean = other match {
- case x: ofUnit => (size == x.size) && (elems == x.elems)
+ case x: ofUnit => (size == x.size)
case _ => false
}
diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala
index 75560580cc..8d6a0ec69d 100644
--- a/src/library/scala/collection/mutable/Builder.scala
+++ b/src/library/scala/collection/mutable/Builder.scala
@@ -18,6 +18,14 @@ import generic._
* elements to the builder with `+=` and then converting to the required
* collection type with `result`.
*
+ * One cannot assume that a single `Builder` can build more than one
+ * instance of the desired collection. Particular subclasses may allow
+ * such behavior. Otherwise, `result` should be treated as a terminal
+ * operation: after it is called, no further methods should be called on
+ * the builder. Extend the [[collection.mutable.ReusableBuilder]] trait
+ * instead of `Builder` for builders that may be reused to build multiple
+ * instances.
+ *
* @tparam Elem the type of elements that get added to the builder.
* @tparam To the type of collection that it produced.
*
@@ -36,8 +44,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
*/
def clear()
- /** Produces a collection from the added elements.
- * The builder's contents are undefined after this operation.
+ /** Produces a collection from the added elements. This is a terminal operation:
+ * the builder's contents are undefined after this operation, and no further
+ * methods should be called.
+ *
* @return a collection containing the elements added to this builder.
*/
def result(): To
@@ -112,6 +122,8 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* @tparam NewTo the type of collection returned by `f`.
* @return a new builder which is the same as the current builder except
* that a transformation function is applied to this builder's result.
+ *
+ * @note The original builder should no longer be used after `mapResult` is called.
*/
def mapResult[NewTo](f: To => NewTo): Builder[Elem, NewTo] =
new Builder[Elem, NewTo] with Proxy {
diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala
index c4b5e546aa..27d554d98e 100644
--- a/src/library/scala/collection/mutable/GrowingBuilder.scala
+++ b/src/library/scala/collection/mutable/GrowingBuilder.scala
@@ -15,6 +15,8 @@ import generic._
/** The canonical builder for collections that are growable, i.e. that support an
* efficient `+=` method which adds an element to the collection.
*
+ * GrowableBuilders can produce only a single instance of the collection they are growing.
+ *
* @author Paul Phillips
* @version 2.8
* @since 2.8
@@ -25,6 +27,6 @@ import generic._
class GrowingBuilder[Elem, To <: Growable[Elem]](empty: To) extends Builder[Elem, To] {
protected var elems: To = empty
def +=(x: Elem): this.type = { elems += x; this }
- def clear() { elems = empty }
+ def clear() { empty.clear }
def result: To = elems
}
diff --git a/src/library/scala/collection/mutable/LazyBuilder.scala b/src/library/scala/collection/mutable/LazyBuilder.scala
index ebee38b77f..f0a5e6971a 100644
--- a/src/library/scala/collection/mutable/LazyBuilder.scala
+++ b/src/library/scala/collection/mutable/LazyBuilder.scala
@@ -13,12 +13,14 @@ package mutable
/** A builder that constructs its result lazily. Iterators or iterables to
* be added to this builder with `++=` are not evaluated until `result` is called.
*
+ * This builder can be reused.
+ *
* @since 2.8
*
* @tparam Elem type of the elements for this builder.
* @tparam To type of the collection this builder builds.
*/
-abstract class LazyBuilder[Elem, +To] extends Builder[Elem, To] {
+abstract class LazyBuilder[Elem, +To] extends ReusableBuilder[Elem, To] {
/** The different segments of elements to be added to the builder, represented as iterators */
protected var parts = new ListBuffer[TraversableOnce[Elem]]
def +=(x: Elem): this.type = { parts += List(x); this }
diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala
index 0a483ceb86..02fcced3ac 100644
--- a/src/library/scala/collection/mutable/ListBuffer.scala
+++ b/src/library/scala/collection/mutable/ListBuffer.scala
@@ -46,7 +46,7 @@ final class ListBuffer[A]
with Buffer[A]
with GenericTraversableTemplate[A, ListBuffer]
with BufferLike[A, ListBuffer[A]]
- with Builder[A, List[A]]
+ with ReusableBuilder[A, List[A]]
with SeqForwarder[A]
with Serializable
{
@@ -297,6 +297,10 @@ final class ListBuffer[A]
// Implementation of abstract method in Builder
+ /** Returns the accumulated `List`.
+ *
+ * This method may be called multiple times to obtain snapshots of the list in different stages of construction.
+ */
def result: List[A] = toList
/** Converts this buffer to a list. Takes constant time. The buffer is
diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala
index f39a6ba634..ecbb1952af 100644
--- a/src/library/scala/collection/mutable/LongMap.scala
+++ b/src/library/scala/collection/mutable/LongMap.scala
@@ -519,7 +519,11 @@ object LongMap {
def apply(): LongMapBuilder[U] = new LongMapBuilder[U]
}
- final class LongMapBuilder[V] extends Builder[(Long, V), LongMap[V]] {
+ /** A builder for instances of `LongMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] {
private[collection] var elems: LongMap[V] = new LongMap[V]
def +=(entry: (Long, V)): this.type = {
elems += entry
diff --git a/src/library/scala/collection/mutable/MapBuilder.scala b/src/library/scala/collection/mutable/MapBuilder.scala
index a5a6b12ea9..cfc3079f41 100644
--- a/src/library/scala/collection/mutable/MapBuilder.scala
+++ b/src/library/scala/collection/mutable/MapBuilder.scala
@@ -23,7 +23,7 @@ package mutable
* @since 2.8
*/
class MapBuilder[A, B, Coll <: scala.collection.GenMap[A, B] with scala.collection.GenMapLike[A, B, Coll]](empty: Coll)
-extends Builder[(A, B), Coll] {
+extends ReusableBuilder[(A, B), Coll] {
protected var elems: Coll = empty
def +=(x: (A, B)): this.type = {
elems = (elems + x).asInstanceOf[Coll]
diff --git a/src/library/scala/collection/mutable/ReusableBuilder.scala b/src/library/scala/collection/mutable/ReusableBuilder.scala
new file mode 100644
index 0000000000..caab3071b6
--- /dev/null
+++ b/src/library/scala/collection/mutable/ReusableBuilder.scala
@@ -0,0 +1,51 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package collection
+package mutable
+
+import generic._
+
+/** `ReusableBuilder` is a marker trait that indicates that a `Builder`
+ * can be reused to build more than one instance of a collection. In
+ * particular, calling `result` followed by `clear` will produce a
+ * collection and reset the builder to begin building a new collection
+ * of the same type.
+ *
+ * It is up to subclasses to implement this behavior, and to document any
+ * other behavior that varies from standard `ReusableBuilder` usage
+ * (e.g. operations being well-defined after a call to `result`, or allowing
+ * multiple calls to result to obtain different snapshots of a collection under
+ * construction).
+ *
+ * @tparam Elem the type of elements that get added to the builder.
+ * @tparam To the type of collection that it produced.
+ *
+ * @since 2.12
+ */
+trait ReusableBuilder[-Elem, +To] extends Builder[Elem, To] {
+ /** Clears the contents of this builder.
+ * After execution of this method, the builder will contain no elements.
+ *
+ * If executed immediately after a call to `result`, this allows a new
+ * instance of the same type of collection to be built.
+ */
+ override def clear(): Unit // Note: overriding for scaladoc only!
+
+ /** Produces a collection from the added elements.
+ *
+ * After a call to `result`, the behavior of all other methods is undefined
+ * save for `clear`. If `clear` is called, then the builder is reset and
+ * may be used to build another instance.
+ *
+ * @return a collection containing the elements added to this builder.
+ */
+ override def result(): To // Note: overriding for scaladoc only!
+}
diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala
index 01bfdc96ed..5d1e9ffc3a 100644
--- a/src/library/scala/collection/mutable/SetBuilder.scala
+++ b/src/library/scala/collection/mutable/SetBuilder.scala
@@ -17,7 +17,9 @@ package mutable
* @param empty The empty element of the collection.
* @since 2.8
*/
-class SetBuilder[A, Coll <: scala.collection.Set[A] with scala.collection.SetLike[A, Coll]](empty: Coll) extends Builder[A, Coll] {
+class SetBuilder[A, Coll <: scala.collection.Set[A]
+with scala.collection.SetLike[A, Coll]](empty: Coll)
+extends ReusableBuilder[A, Coll] {
protected var elems: Coll = empty
def +=(x: A): this.type = { elems = elems + x; this }
def clear() { elems = empty }
diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala
index c56d40786e..b5b9498374 100644
--- a/src/library/scala/collection/mutable/StringBuilder.scala
+++ b/src/library/scala/collection/mutable/StringBuilder.scala
@@ -33,7 +33,7 @@ final class StringBuilder(private val underlying: JavaStringBuilder)
with java.lang.CharSequence
with IndexedSeq[Char]
with StringLike[StringBuilder]
- with Builder[Char, String]
+ with ReusableBuilder[Char, String]
with Serializable {
override protected[this] def thisCollection: StringBuilder = this
@@ -435,7 +435,11 @@ final class StringBuilder(private val underlying: JavaStringBuilder)
*/
override def mkString = toString
- /** Returns the result of this Builder (a String)
+ /** Returns the result of this Builder (a String).
+ *
+ * If this method is called multiple times, each call will result in a snapshot of the buffer at that point in time.
+ * In particular, a `StringBuilder` can be used to build multiple independent strings by emptying the buffer with `clear`
+ * after each call to `result`.
*
* @return the string assembled by this StringBuilder
*/
diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
index bfe95a11ab..c4781321d7 100644
--- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
+++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
@@ -17,12 +17,14 @@ import scala.runtime.ScalaRunTime._
/** A builder class for arrays.
*
+ * This builder can be reused.
+ *
* @tparam A type of elements that can be added to this builder.
* @param tag class tag for objects of type `A`.
*
* @since 2.8
*/
-class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A]] {
+class WrappedArrayBuilder[A](tag: ClassTag[A]) extends ReusableBuilder[A, WrappedArray[A]] {
@deprecated("use tag instead", "2.10.0")
val manifest: ClassTag[A] = tag
@@ -73,12 +75,13 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A
this
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index ba6c363918..a025407672 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -428,13 +428,15 @@ trait Definitions extends api.StandardDefinitions {
def elementType(container: Symbol, tp: Type): Type = elementExtract(container, tp)
// collections classes
- lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]]
- lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]]
- lazy val IterableClass = requiredClass[scala.collection.Iterable[_]]
- lazy val ListClass = requiredClass[scala.collection.immutable.List[_]]
- lazy val SeqClass = requiredClass[scala.collection.Seq[_]]
- lazy val StringBuilderClass = requiredClass[scala.collection.mutable.StringBuilder]
- lazy val TraversableClass = requiredClass[scala.collection.Traversable[_]]
+ lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]]
+ lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]]
+ lazy val IterableClass = requiredClass[scala.collection.Iterable[_]]
+ lazy val ListClass = requiredClass[scala.collection.immutable.List[_]]
+ lazy val SeqClass = requiredClass[scala.collection.Seq[_]]
+ lazy val JavaStringBuilderClass = requiredClass[java.lang.StringBuilder]
+ lazy val JavaStringBufferClass = requiredClass[java.lang.StringBuffer]
+ lazy val JavaCharSequenceClass = requiredClass[java.lang.CharSequence]
+ lazy val TraversableClass = requiredClass[scala.collection.Traversable[_]]
lazy val ListModule = requiredModule[scala.collection.immutable.List.type]
def List_apply = getMemberMethod(ListModule, nme.apply)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index d6b611a3f4..e5f77c322d 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -266,7 +266,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.IterableClass
definitions.ListClass
definitions.SeqClass
- definitions.StringBuilderClass
+ definitions.JavaStringBuilderClass
+ definitions.JavaStringBufferClass
+ definitions.JavaCharSequenceClass
definitions.TraversableClass
definitions.ListModule
definitions.NilModule
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/neg/choices.check b/test/files/neg/choices.check
index b114394e96..df4f23461f 100644
--- a/test/files/neg/choices.check
+++ b/test/files/neg/choices.check
@@ -1,2 +1,6 @@
+error: Usage: -Yresolve-term-conflict:<strategy>
+ where <strategy> choices are package, object, error (default: error)
+error: bad option: '-Yresolve-term-conflict'
error: bad options: -Yresolve-term-conflict
-one error found
+error: flags file may only contain compiler options, found: -Yresolve-term-conflict
+four errors found
diff --git a/test/files/neg/partestInvalidFlag.check b/test/files/neg/partestInvalidFlag.check
new file mode 100644
index 0000000000..812191dc22
--- /dev/null
+++ b/test/files/neg/partestInvalidFlag.check
@@ -0,0 +1,4 @@
+error: bad option: '-badCompilerFlag'
+error: bad options: -badCompilerFlag notAFlag -Yopt:badChoice
+error: flags file may only contain compiler options, found: -badCompilerFlag notAFlag -Yopt:badChoice
+three errors found
diff --git a/test/files/neg/partestInvalidFlag.flags b/test/files/neg/partestInvalidFlag.flags
new file mode 100644
index 0000000000..68884532b9
--- /dev/null
+++ b/test/files/neg/partestInvalidFlag.flags
@@ -0,0 +1 @@
+-badCompilerFlag notAFlag -Yopt:badChoice
diff --git a/test/files/neg/partestInvalidFlag.scala b/test/files/neg/partestInvalidFlag.scala
new file mode 100644
index 0000000000..826a1a5bc2
--- /dev/null
+++ b/test/files/neg/partestInvalidFlag.scala
@@ -0,0 +1 @@
+class C
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/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: <none>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/pos/t4579.scala b/test/files/run/lisp.scala
index cd1553f02a..162c7d2599 100644
--- a/test/files/pos/t4579.scala
+++ b/test/files/run/lisp.scala
@@ -1,5 +1,5 @@
//############################################################################
-// Lisp interpreter (revived as an optimizer test.)
+// Lisp interpreter
//############################################################################
//############################################################################
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
--- a/test/files/run/t7008-scala-defined.flags
+++ /dev/null
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/collection/ReusableBuildersTest.scala b/test/junit/scala/collection/ReusableBuildersTest.scala
new file mode 100644
index 0000000000..8dd1a37adf
--- /dev/null
+++ b/test/junit/scala/collection/ReusableBuildersTest.scala
@@ -0,0 +1,48 @@
+package scala.collection
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+
+/* Tests various maps by making sure they all agree on the same answers. */
+@RunWith(classOf[JUnit4])
+class ReusableBuildersTest {
+ // GrowingBuilders are NOT reusable but can clear themselves
+ @Test
+ def test_SI8648() {
+ val b = collection.mutable.HashSet.newBuilder[Int]
+ b += 3
+ b.clear
+ assert(!b.isInstanceOf[collection.mutable.ReusableBuilder[_,_]])
+ assert(b.isInstanceOf[collection.mutable.GrowingBuilder[_,_]])
+ assert(b.result == Set[Int]())
+ }
+
+ // ArrayBuilders ARE reusable, regardless of whether they returned their internal array or not
+ @Test
+ def test_SI9564() {
+ val b = Array.newBuilder[Float]
+ b += 3f
+ val three = b.result
+ b.clear
+ b ++= (1 to 16).map(_.toFloat)
+ val sixteen = b.result
+ b.clear
+ b += 0f
+ val zero = b.result
+ assert(b.isInstanceOf[collection.mutable.ReusableBuilder[_,_]])
+ assert(three.toList == 3 :: Nil)
+ assert(sixteen.toList == (1 to 16))
+ assert(zero.toList == 0 :: Nil)
+ }
+
+ @Test
+ def test_reusability() {
+ val bl = List.newBuilder[String]
+ val bv = Vector.newBuilder[String]
+ val ba = collection.mutable.ArrayBuffer.newBuilder[String]
+ assert(bl.isInstanceOf[collection.mutable.ReusableBuilder[_, _]])
+ assert(bv.isInstanceOf[collection.mutable.ReusableBuilder[_, _]])
+ assert(!ba.isInstanceOf[collection.mutable.ReusableBuilder[_, _]])
+ }
+}
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: <none>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/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)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
new file mode 100644
index 0000000000..80cde6c9a9
--- /dev/null
+++ b/test/junit/scala/tools/nsc/backend/jvm/StringConcatTest.scala
@@ -0,0 +1,70 @@
+package scala.tools.nsc
+package backend.jvm
+
+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.testing.AssertUtil._
+
+import CodeGenTools._
+import scala.tools.partest.ASMConverters
+import ASMConverters._
+import scala.tools.testing.ClearAfterClass
+
+object StringConcatTest extends ClearAfterClass.Clearable {
+ var compiler = newCompiler()
+ def clear(): Unit = { compiler = null }
+}
+
+@RunWith(classOf[JUnit4])
+class StringConcatTest extends ClearAfterClass {
+ ClearAfterClass.stateToClear = StringConcatTest
+ val compiler = StringConcatTest.compiler
+
+ val commonPreInstructions = List(Label(0), LineNumber(1, Label(0)), TypeOp(NEW, "java/lang/StringBuilder"), Op(DUP), Invoke(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false), Ldc(LDC, "abc"), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false), VarOp(ALOAD, 0))
+
+ val commonPostInstructions = List(Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false), Op(ARETURN), Label(12))
+
+ def instructionsWithCommonParts(instructions: List[Instruction]) = commonPreInstructions ++ instructions ++ commonPostInstructions
+
+ def instructionsForResultMethod(code: String): List[Instruction] = {
+ val methods = compileMethods(compiler)(code)
+ val resultMethod = methods.find(_.name == "result").get
+ instructionsFromMethod(resultMethod)
+ }
+
+ @Test
+ def concatStringToStringBuilder: Unit = {
+ val code = """ def string = "def"; def result = "abc" + string """
+ val actualInstructions = instructionsForResultMethod(code)
+ val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "string", "()Ljava/lang/String;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false)))
+ assertSameCode(actualInstructions, expectedInstructions)
+ }
+
+ @Test
+ def concatStringBufferToStringBuilder: Unit = {
+ val code = """ def stringBuffer = new java.lang.StringBuffer("def"); def result = "abc" + stringBuffer """
+ val actualInstructions = instructionsForResultMethod(code)
+ val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "stringBuffer", "()Ljava/lang/StringBuffer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/StringBuffer;)Ljava/lang/StringBuilder;", false)))
+ assertSameCode(actualInstructions, expectedInstructions)
+ }
+
+ @Test
+ def concatCharSequenceToStringBuilder: Unit = {
+ val code = """ def charSequence: CharSequence = "def"; def result = "abc" + charSequence """
+ val actualInstructions = instructionsForResultMethod(code)
+ val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "charSequence", "()Ljava/lang/CharSequence;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/CharSequence;)Ljava/lang/StringBuilder;", false)))
+ assertSameCode(actualInstructions, expectedInstructions)
+ }
+
+ @Test
+ def concatIntToStringBuilder: Unit = {
+ val code = """ def int = 123; def result = "abc" + int """
+ val actualInstructions = instructionsForResultMethod(code)
+ val expectedInstructions = instructionsWithCommonParts(List(Invoke(INVOKEVIRTUAL, "C", "int", "()I", false), Invoke(INVOKESTATIC, "scala/runtime/BoxesRunTime", "boxToInteger", "(I)Ljava/lang/Integer;", false), Invoke(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuilder;", false)))
+ assertSameCode(actualInstructions, expectedInstructions)
+ }
+}
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)),
diff --git a/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala b/test/junit/scala/tools/nsc/transform/patmat/PatmatBytecodeTest.scala
index ec4621b230..3fc3144eb2 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*/, "<init>", 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*/ , "<init>", 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)
- }
- }
-}
diff --git a/versions.properties b/versions.properties
index bb6d6d1038..7cdafc975a 100644
--- a/versions.properties
+++ b/versions.properties
@@ -30,7 +30,7 @@ jline.version=2.12.1
scala-asm.version=5.0.4-scala-3
# external modules, used internally (not shipped)
-partest.version.number=1.0.11
+partest.version.number=1.0.12
scalacheck.version.number=1.11.6
# TODO: modularize the compiler