summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-04-21 10:14:38 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-04-21 10:14:38 +0200
commitefc1f198b47d1c853b8d5600dfbfb7378a38fe51 (patch)
tree239d3f08621fd43e365fb7b4164535818a63a48e
parent56d79460dc3e9dbec054c1459122f5b87989f4e3 (diff)
parentfedbfd74f2d874ef3851f6ce2261011877ac505d (diff)
downloadscala-efc1f198b47d1c853b8d5600dfbfb7378a38fe51.tar.gz
scala-efc1f198b47d1c853b8d5600dfbfb7378a38fe51.tar.bz2
scala-efc1f198b47d1c853b8d5600dfbfb7378a38fe51.zip
Merge commit 'fedbfd7' into merge/2.11-to-2.12-apr-21
-rw-r--r--.travis.yml2
-rw-r--r--Gemfile2
-rw-r--r--src/compiler/scala/tools/nsc/Reporting.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala28
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala23
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala56
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala28
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala14
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala63
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala72
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugin.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala25
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Logic.scala24
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala109
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Solving.scala74
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/library/scala/collection/TraversableLike.scala2
-rw-r--r--src/library/scala/collection/TraversableOnce.scala17
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala6
-rwxr-xr-xsrc/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala33
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css2
-rw-r--r--test/files/neg/case-collision2.flags2
-rw-r--r--test/files/neg/inlineMaxSize.check9
-rw-r--r--test/files/neg/inlineMaxSize.flags1
-rw-r--r--test/files/neg/inlineMaxSize.scala8
-rw-r--r--test/files/neg/t0899.check6
-rw-r--r--test/files/neg/t562.check2
-rw-r--r--test/files/pos/t6942.flags2
-rw-r--r--test/files/pos/t9181.flags1
-rw-r--r--test/files/pos/t9181.scala806
-rw-r--r--test/files/run/t7407.flags2
-rw-r--r--test/files/run/t7407b.flags2
-rw-r--r--test/files/run/t8845.flags2
-rw-r--r--test/files/run/t8925.flags2
-rw-r--r--test/files/run/t9252.check1
-rw-r--r--test/files/run/t9252.scala5
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala7
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala4
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala6
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala48
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala27
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala24
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala2
-rw-r--r--test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala3
-rw-r--r--test/scaladoc/run/t5795.check4
-rw-r--r--test/scaladoc/run/t5795.scala63
-rw-r--r--test/scaladoc/scalacheck/CommentFactoryTest.scala20
-rw-r--r--test/scaladoc/scalacheck/HtmlFactoryTest.scala4
-rw-r--r--versions.properties2
51 files changed, 1420 insertions, 250 deletions
diff --git a/.travis.yml b/.travis.yml
index e90fc35267..6a7ac45e3d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@
# based on http://www.paperplanes.de/2013/8/13/deploying-your-jekyll-blog-to-s3-with-travis-ci.html
language: ruby
rvm:
- - 1.9.3
+ - 2.2
script: bundle exec jekyll build -s spec/ -d build/spec
install: bundle install
diff --git a/Gemfile b/Gemfile
index 53924a4381..6921f792c3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,7 @@
# To build the spec on Travis CI
source "https://rubygems.org"
-gem "jekyll", "2.0.0.alpha.2"
+gem "jekyll", "2.5.3"
gem "rouge"
# gem 's3_website'
# gem 'redcarpet'
diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala
index 72a4b69536..4e7a527a5a 100644
--- a/src/compiler/scala/tools/nsc/Reporting.scala
+++ b/src/compiler/scala/tools/nsc/Reporting.scala
@@ -46,7 +46,7 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w
private val _deprecationWarnings = new ConditionalWarning("deprecation", settings.deprecation)()
private val _uncheckedWarnings = new ConditionalWarning("unchecked", settings.unchecked)()
private val _featureWarnings = new ConditionalWarning("feature", settings.feature)()
- private val _inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings)(if (settings.isBCodeAskedFor) settings.YoptWarnings.name else settings.YinlinerWarnings.name)
+ private val _inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings)(if (settings.isBCodeActive) settings.YoptWarnings.name else settings.YinlinerWarnings.name)
private val _allConditionalWarnings = List(_deprecationWarnings, _uncheckedWarnings, _featureWarnings, _inlinerWarnings)
// TODO: remove in favor of the overload that takes a Symbol, give that argument a default (NoSymbol)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index b1b6c73f8d..cbe6239bb2 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -883,7 +883,12 @@ abstract class GenICode extends SubComponent {
case None =>
val saved = settings.uniqid
settings.uniqid.value = true
- try abort(s"symbol $sym does not exist in ${ctx.method}, which contains locals ${ctx.method.locals.mkString(",")}")
+ try {
+ val methodCode = unit.body.collect { case dd: DefDef
+ if dd.symbol == ctx.method.symbol => showCode(dd);
+ }.headOption.getOrElse("<unknown>")
+ abort(s"symbol $sym does not exist in ${ctx.method}, which contains locals ${ctx.method.locals.mkString(",")}. \nMethod code: $methodCode")
+ }
finally settings.uniqid.value = saved
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index d8a17e975e..d690542f0e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -11,11 +11,12 @@ import scala.collection.concurrent.TrieMap
import scala.reflect.internal.util.Position
import scala.tools.asm
import asm.Opcodes
-import scala.tools.asm.tree.{MethodInsnNode, InnerClassNode, ClassNode}
+import scala.tools.asm.tree.{MethodNode, MethodInsnNode, InnerClassNode, ClassNode}
import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo}
import scala.tools.nsc.backend.jvm.BackendReporting._
import scala.tools.nsc.backend.jvm.opt._
import scala.collection.convert.decorateAsScala._
+import scala.tools.nsc.settings.ScalaSettings
/**
* The BTypes component defines The BType class hierarchy. A BType stores all type information
@@ -39,6 +40,8 @@ abstract class BTypes {
*/
val byteCodeRepository: ByteCodeRepository
+ val localOpt: LocalOpt[this.type]
+
val inliner: Inliner[this.type]
val callGraph: CallGraph[this.type]
@@ -48,14 +51,9 @@ abstract class BTypes {
// Allows to define per-run caches here and in the CallGraph component, which don't have a global
def recordPerRunCache[T <: collection.generic.Clearable](cache: T): T
- // When building the call graph, we need to know if global inlining is allowed (the component doesn't have a global)
- def inlineGlobalEnabled: Boolean
-
- // When the inliner is not enabled, there's no point in adding InlineInfos to all ClassBTypes
- def inlinerEnabled: Boolean
+ // Allows access to the compiler settings for backend components that don't have a global in scope
+ def compilerSettings: ScalaSettings
- // Settings that define what kind of optimizer warnings are emitted.
- def warnSettings: WarnSettings
/**
* A map from internal names to ClassBTypes. Every ClassBType is added to this map on its
@@ -83,6 +81,18 @@ abstract class BTypes {
val javaDefinedClasses: collection.mutable.Set[InternalName] = recordPerRunCache(collection.mutable.Set.empty)
/**
+ * Cache, contains methods whose unreachable instructions are eliminated.
+ *
+ * The ASM Analyzer class does not compute any frame information for unreachable instructions.
+ * Transformations that use an analyzer (including inlining) therefore require unreachable code
+ * to be eliminated.
+ *
+ * This cache allows running dead code elimination whenever an analyzer is used. If the method
+ * is already optimized, DCE can return early.
+ */
+ val unreachableCodeEliminated: collection.mutable.Set[MethodNode] = recordPerRunCache(collection.mutable.Set.empty)
+
+ /**
* Obtain the BType for a type descriptor or internal name. For class descriptors, the ClassBType
* is constructed by parsing the corresponding classfile.
*
@@ -229,7 +239,7 @@ abstract class BTypes {
// The InlineInfo is built from the classfile (not from the symbol) for all classes that are NOT
// being compiled. For those classes, the info is only needed if the inliner is enabled, othewise
// we can save the memory.
- if (!inlinerEnabled) BTypes.EmptyInlineInfo
+ if (!compilerSettings.YoptInlinerEnabled) BTypes.EmptyInlineInfo
else fromClassfileAttribute getOrElse fromClassfileWithoutAttribute
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index eeb6ed24a2..1b9fd5e298 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -7,9 +7,10 @@ package scala.tools.nsc
package backend.jvm
import scala.tools.asm
-import scala.tools.nsc.backend.jvm.opt.{CallGraph, Inliner, ByteCodeRepository}
+import scala.tools.nsc.backend.jvm.opt.{LocalOpt, CallGraph, Inliner, ByteCodeRepository}
import scala.tools.nsc.backend.jvm.BTypes.{InlineInfo, MethodInlineInfo, InternalName}
import BackendReporting._
+import scala.tools.nsc.settings.ScalaSettings
/**
* This class mainly contains the method classBTypeFromSymbol, which extracts the necessary
@@ -37,6 +38,8 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
val byteCodeRepository = new ByteCodeRepository(global.classPath, javaDefinedClasses, recordPerRunCache(collection.concurrent.TrieMap.empty))
+ val localOpt: LocalOpt[this.type] = new LocalOpt(this)
+
val inliner: Inliner[this.type] = new Inliner(this)
val callGraph: CallGraph[this.type] = new CallGraph(this)
@@ -49,19 +52,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
def recordPerRunCache[T <: collection.generic.Clearable](cache: T): T = perRunCaches.recordCache(cache)
- def inlineGlobalEnabled: Boolean = settings.YoptInlineGlobal
-
- def inlinerEnabled: Boolean = settings.YoptInlinerEnabled
-
- def warnSettings: WarnSettings = {
- val c = settings.YoptWarningsChoices
- // cannot extract settings.YoptWarnings into a local val due to some dependent typing issue.
- WarnSettings(
- !settings.YoptWarnings.isSetByUser || settings.YoptWarnings.contains(c.atInlineFailedSummary.name) || settings.YoptWarnings.contains(c.atInlineFailed.name),
- settings.YoptWarnings.contains(c.noInlineMixed.name),
- settings.YoptWarnings.contains(c.noInlineMissingBytecode.name),
- settings.YoptWarnings.contains(c.noInlineMissingScalaInlineInfoAttr.name))
- }
+ def compilerSettings: ScalaSettings = settings
// helpers that need access to global.
// TODO @lry create a separate component, they don't belong to BTypesFromSymbols
@@ -418,8 +409,8 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
// phase travel required, see implementation of `compiles`. for nested classes, it checks if the
// enclosingTopLevelClass is being compiled. after flatten, all classes are considered top-level,
// so `compiles` would return `false`.
- if (exitingPickler(currentRun.compiles(classSym))) buildFromSymbol // InlineInfo required for classes being compiled, we have to create the classfile attribute
- else if (!inlinerEnabled) BTypes.EmptyInlineInfo // For other classes, we need the InlineInfo only inf the inliner is enabled.
+ if (exitingPickler(currentRun.compiles(classSym))) buildFromSymbol // InlineInfo required for classes being compiled, we have to create the classfile attribute
+ else if (!compilerSettings.YoptInlinerEnabled) BTypes.EmptyInlineInfo // For other classes, we need the InlineInfo only inf the inliner is enabled.
else {
// For classes not being compiled, the InlineInfo is read from the classfile attribute. This
// fixes an issue with mixed-in methods: the mixin phase enters mixin methods only to class
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
index a06fb4bab8..d641f708d2 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala
@@ -4,6 +4,8 @@ package backend.jvm
import scala.tools.asm.tree.{AbstractInsnNode, MethodNode}
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.reflect.internal.util.Position
+import scala.tools.nsc.settings.ScalaSettings
+import scala.util.control.ControlThrowable
/**
* Interface for emitting inline warnings. The interface is required because the implementation
@@ -73,24 +75,22 @@ object BackendReporting {
}
}
- case class Invalid[A](e: A) extends Exception
+ case class Invalid[A](e: A) extends ControlThrowable
/**
* See documentation of orThrow above.
*/
def tryEither[A, B](op: => Either[A, B]): Either[A, B] = try { op } catch { case Invalid(e) => Left(e.asInstanceOf[A]) }
- final case class WarnSettings(atInlineFailed: Boolean, noInlineMixed: Boolean, noInlineMissingBytecode: Boolean, noInlineMissingScalaInlineInfoAttr: Boolean)
-
sealed trait OptimizerWarning {
- def emitWarning(settings: WarnSettings): Boolean
+ def emitWarning(settings: ScalaSettings): Boolean
}
// Method filter in RightBiasedEither requires an implicit empty value. Taking the value here
// in scope allows for-comprehensions that desugar into filter calls (for example when using a
// tuple de-constructor).
implicit object emptyOptimizerWarning extends OptimizerWarning {
- def emitWarning(settings: WarnSettings): Boolean = false
+ def emitWarning(settings: ScalaSettings): Boolean = false
}
sealed trait MissingBytecodeWarning extends OptimizerWarning {
@@ -112,17 +112,17 @@ object BackendReporting {
missingClass.map(c => s" Reason:\n$c").getOrElse("")
}
- def emitWarning(settings: WarnSettings): Boolean = this match {
+ def emitWarning(settings: ScalaSettings): Boolean = this match {
case ClassNotFound(_, javaDefined) =>
- if (javaDefined) settings.noInlineMixed
- else settings.noInlineMissingBytecode
+ if (javaDefined) settings.YoptWarningNoInlineMixed
+ else settings.YoptWarningNoInlineMissingBytecode
case m @ MethodNotFound(_, _, _, missing) =>
if (m.isArrayMethod) false
- else settings.noInlineMissingBytecode || missing.exists(_.emitWarning(settings))
+ else settings.YoptWarningNoInlineMissingBytecode || missing.exists(_.emitWarning(settings))
case FieldNotFound(_, _, _, missing) =>
- settings.noInlineMissingBytecode || missing.exists(_.emitWarning(settings))
+ settings.YoptWarningNoInlineMissingBytecode || missing.exists(_.emitWarning(settings))
}
}
@@ -141,9 +141,9 @@ object BackendReporting {
s"Failed to get the type of class symbol $classFullName due to SI-9111."
}
- def emitWarning(settings: WarnSettings): Boolean = this match {
+ def emitWarning(settings: ScalaSettings): Boolean = this match {
case NoClassBTypeInfoMissingBytecode(cause) => cause.emitWarning(settings)
- case NoClassBTypeInfoClassSymbolInfoFailedSI9111(_) => settings.noInlineMissingBytecode
+ case NoClassBTypeInfoClassSymbolInfoFailedSI9111(_) => settings.YoptWarningNoInlineMissingBytecode
}
}
@@ -175,11 +175,11 @@ object BackendReporting {
cause.toString
}
- def emitWarning(settings: WarnSettings): Boolean = this match {
+ def emitWarning(settings: ScalaSettings): Boolean = this match {
case MethodInlineInfoIncomplete(_, _, _, cause) => cause.emitWarning(settings)
case MethodInlineInfoMissing(_, _, _, Some(cause)) => cause.emitWarning(settings)
- case MethodInlineInfoMissing(_, _, _, None) => settings.noInlineMissingBytecode
+ case MethodInlineInfoMissing(_, _, _, None) => settings.YoptWarningNoInlineMissingBytecode
case MethodInlineInfoError(_, _, _, cause) => cause.emitWarning(settings)
@@ -214,11 +214,21 @@ object BackendReporting {
case SynchronizedMethod(_, _, _) =>
s"Method $calleeMethodSig cannot be inlined because it is synchronized."
+
+ case StrictfpMismatch(_, _, _, callsiteClass, callsiteName, callsiteDesc) =>
+ s"""The callsite method ${BackendReporting.methodSignature(callsiteClass, callsiteName, callsiteDesc)}
+ |does not have the same strictfp mode as the callee $calleeMethodSig.
+ """.stripMargin
+
+ case ResultingMethodTooLarge(_, _, _, callsiteClass, callsiteName, callsiteDesc) =>
+ s"""The size of the callsite method ${BackendReporting.methodSignature(callsiteClass, callsiteName, callsiteDesc)}
+ |would exceed the JVM method size limit after inlining $calleeMethodSig.
+ """.stripMargin
}
- def emitWarning(settings: WarnSettings): Boolean = this match {
- case _: IllegalAccessInstruction | _: MethodWithHandlerCalledOnNonEmptyStack | _: SynchronizedMethod =>
- settings.atInlineFailed
+ def emitWarning(settings: ScalaSettings): Boolean = this match {
+ case _: IllegalAccessInstruction | _: MethodWithHandlerCalledOnNonEmptyStack | _: SynchronizedMethod | _: StrictfpMismatch | _: ResultingMethodTooLarge =>
+ settings.YoptWarningEmitAtInlineFailed
case IllegalAccessCheckFailed(_, _, _, _, _, cause) =>
cause.emitWarning(settings)
@@ -231,6 +241,10 @@ object BackendReporting {
case class MethodWithHandlerCalledOnNonEmptyStack(calleeDeclarationClass: InternalName, name: String, descriptor: String,
callsiteClass: InternalName, callsiteName: String, callsiteDesc: String) extends CannotInlineWarning
case class SynchronizedMethod(calleeDeclarationClass: InternalName, name: String, descriptor: String) extends CannotInlineWarning
+ case class StrictfpMismatch(calleeDeclarationClass: InternalName, name: String, descriptor: String,
+ callsiteClass: InternalName, callsiteName: String, callsiteDesc: String) extends CannotInlineWarning
+ case class ResultingMethodTooLarge(calleeDeclarationClass: InternalName, name: String, descriptor: String,
+ callsiteClass: InternalName, callsiteName: String, callsiteDesc: String) extends CannotInlineWarning
/**
* Used in the InlineInfo of a ClassBType, when some issue occurred obtaining the inline information.
@@ -250,11 +264,11 @@ object BackendReporting {
s"Cannot read ScalaInlineInfo version $version in classfile $internalName. Use a more recent compiler."
}
- def emitWarning(settings: WarnSettings): Boolean = this match {
- case NoInlineInfoAttribute(_) => settings.noInlineMissingScalaInlineInfoAttr
+ def emitWarning(settings: ScalaSettings): Boolean = this match {
+ case NoInlineInfoAttribute(_) => settings.YoptWarningNoInlineMissingScalaInlineInfoAttr
case ClassNotFoundWhenBuildingInlineInfoFromSymbol(cause) => cause.emitWarning(settings)
- case ClassSymbolInfoFailureSI9111(_) => settings.noInlineMissingBytecode
- case UnknownScalaInlineInfoVersion(_, _) => settings.noInlineMissingScalaInlineInfoAttr
+ case ClassSymbolInfoFailureSI9111(_) => settings.YoptWarningNoInlineMissingBytecode
+ case UnknownScalaInlineInfoVersion(_, _) => settings.YoptWarningNoInlineMissingScalaInlineInfoAttr
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index be1595dc29..c6ee36d7b2 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -14,7 +14,6 @@ import scala.reflect.internal.util.Statistics
import scala.tools.asm
import scala.tools.asm.tree.ClassNode
-import scala.tools.nsc.backend.jvm.opt.LocalOpt
/*
* Prepare in-memory representations of classfiles using the ASM Tree API, and serialize them to disk.
@@ -215,17 +214,12 @@ abstract class GenBCode extends BCodeSyncAndTry {
* - converting the plain ClassNode to byte array and placing it on queue-3
*/
class Worker2 {
- lazy val localOpt = new LocalOpt(settings)
-
def runGlobalOptimizations(): Unit = {
import scala.collection.convert.decorateAsScala._
q2.asScala foreach {
case Item2(_, _, plain, _, _) =>
// skip mirror / bean: wd don't inline into tem, and they are not used in the plain class
- if (plain != null) {
- localOpt.minimalRemoveUnreachableCode(plain)
- callGraph.addClass(plain)
- }
+ if (plain != null) callGraph.addClass(plain)
}
bTypes.inliner.runInliner()
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index 14e8cccc60..201ab15177 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -10,6 +10,7 @@ package opt
import scala.annotation.{tailrec, switch}
import scala.collection.mutable
import scala.reflect.internal.util.Collections._
+import scala.tools.asm.commons.CodeSizeEvaluator
import scala.tools.asm.tree.analysis._
import scala.tools.asm.{MethodWriter, ClassWriter, Label, Opcodes}
import scala.tools.asm.tree._
@@ -21,6 +22,12 @@ import scala.tools.nsc.backend.jvm.BTypes._
object BytecodeUtils {
+ // http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.9.1
+ final val maxJVMMethodSize = 65535
+
+ // 5% margin, more than enough for the instructions added by the inliner (store / load args, null check for instance methods)
+ final val maxMethodSizeAfterInline = maxJVMMethodSize - (maxJVMMethodSize / 20)
+
object Goto {
def unapply(instruction: AbstractInsnNode): Option[JumpInsnNode] = {
if (instruction.getOpcode == Opcodes.GOTO) Some(instruction.asInstanceOf[JumpInsnNode])
@@ -83,10 +90,14 @@ object BytecodeUtils {
def isSynchronizedMethod(methodNode: MethodNode): Boolean = (methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0
+ def isNativeMethod(methodNode: MethodNode): Boolean = (methodNode.access & Opcodes.ACC_NATIVE) != 0
+
def isFinalClass(classNode: ClassNode): Boolean = (classNode.access & Opcodes.ACC_FINAL) != 0
def isFinalMethod(methodNode: MethodNode): Boolean = (methodNode.access & (Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) != 0
+ def isStrictfpMethod(methodNode: MethodNode): Boolean = (methodNode.access & Opcodes.ACC_STRICT) != 0
+
def nextExecutableInstruction(instruction: AbstractInsnNode, alsoKeep: AbstractInsnNode => Boolean = Set()): Option[AbstractInsnNode] = {
var result = instruction
do { result = result.getNext }
@@ -215,7 +226,7 @@ object BytecodeUtils {
* to create a separate visitor for computing those values, duplicating the functionality from the
* MethodWriter.
*/
- def computeMaxLocalsMaxStack(method: MethodNode) {
+ def computeMaxLocalsMaxStack(method: MethodNode): Unit = {
val cw = new ClassWriter(ClassWriter.COMPUTE_MAXS)
val excs = method.exceptions.asScala.toArray
val mw = cw.visitMethod(method.access, method.name, method.desc, method.signature, excs).asInstanceOf[MethodWriter]
@@ -224,6 +235,21 @@ object BytecodeUtils {
method.maxStack = mw.getMaxStack
}
+ def codeSizeOKForInlining(caller: MethodNode, callee: MethodNode): Boolean = {
+ // Looking at the implementation of CodeSizeEvaluator, all instructions except tableswitch and
+ // lookupswitch are <= 8 bytes. These should be rare enough for 8 to be an OK rough upper bound.
+ def roughUpperBound(methodNode: MethodNode): Int = methodNode.instructions.size * 8
+
+ def maxSize(methodNode: MethodNode): Int = {
+ val eval = new CodeSizeEvaluator(null)
+ methodNode.accept(eval)
+ eval.getMaxSize
+ }
+
+ (roughUpperBound(caller) + roughUpperBound(callee) > maxMethodSizeAfterInline) &&
+ (maxSize(caller) + maxSize(callee) > maxMethodSizeAfterInline)
+ }
+
def removeLineNumberNodes(classNode: ClassNode): Unit = {
for (m <- classNode.methods.asScala) removeLineNumberNodes(m.instructions)
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index 47d32c94cb..028f0f8fa6 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -43,14 +43,14 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
// callee, we only check there for the methodInlineInfo, we should find it there.
calleeDeclarationClassBType.info.orThrow.inlineInfo.methodInfos.get(methodSignature) match {
case Some(methodInlineInfo) =>
- val canInlineFromSource = inlineGlobalEnabled || calleeSource == CompilationUnit
+ val canInlineFromSource = compilerSettings.YoptInlineGlobal || calleeSource == CompilationUnit
val isAbstract = BytecodeUtils.isAbstractMethod(calleeMethodNode)
// (1) A non-final method can be safe to inline if the receiver type is a final subclass. Example:
// class A { @inline def f = 1 }; object B extends A; B.f // can be inlined
//
- // TODO: type analysis can render more calls statically resolved. Example˜∫
+ // TODO: type analysis can render more calls statically resolved. Example:
// new A.f // can be inlined, the receiver type is known to be exactly A.
val isStaticallyResolved: Boolean = {
methodInlineInfo.effectivelyFinal ||
@@ -68,8 +68,13 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
// (2) Final trait methods can be rewritten from the interface to the static implementation
// method to enable inlining.
CallsiteInfo(
- safeToInline = canInlineFromSource && isStaticallyResolved && !isAbstract, // (1)
- safeToRewrite = canInlineFromSource && isRewritableTraitCall, // (2)
+ safeToInline =
+ canInlineFromSource &&
+ isStaticallyResolved && // (1)
+ !isAbstract &&
+ !BytecodeUtils.isConstructor(calleeMethodNode) &&
+ !BytecodeUtils.isNativeMethod(calleeMethodNode),
+ safeToRewrite = canInlineFromSource && isRewritableTraitCall, // (2)
annotatedInline = methodInlineInfo.annotatedInline,
annotatedNoInline = methodInlineInfo.annotatedNoInline,
warning = warning)
@@ -92,6 +97,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
// TODO: for now we run a basic analyzer to get the stack height at the call site.
// once we run a more elaborate analyzer (types, nullness), we can get the stack height out of there.
+ localOpt.minimalRemoveUnreachableCode(methodNode, definingClass.internalName)
val analyzer = new AsmAnalyzer(methodNode, definingClass.internalName)
methodNode.instructions.iterator.asScala.collect({
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
index e14e57d3ab..ac5c9ce2e6 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -16,7 +16,7 @@ import scala.collection.convert.decorateAsJava._
import AsmUtils._
import BytecodeUtils._
import collection.mutable
-import scala.tools.asm.tree.analysis.{SourceInterpreter, Analyzer}
+import scala.tools.asm.tree.analysis.SourceInterpreter
import BackendReporting._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
@@ -24,21 +24,39 @@ class Inliner[BT <: BTypes](val btypes: BT) {
import btypes._
import callGraph._
+ def eliminateUnreachableCodeAndUpdateCallGraph(methodNode: MethodNode, definingClass: InternalName): Unit = {
+ localOpt.minimalRemoveUnreachableCode(methodNode, definingClass) foreach {
+ case invocation: MethodInsnNode => callGraph.callsites.remove(invocation)
+ case _ =>
+ }
+ }
+
def runInliner(): Unit = {
rewriteFinalTraitMethodInvocations()
for (request <- collectAndOrderInlineRequests) {
val Right(callee) = request.callee // collectAndOrderInlineRequests returns callsites with a known callee
- val r = inline(request.callsiteInstruction, request.callsiteStackHeight, request.callsiteMethod, request.callsiteClass,
- callee.callee, callee.calleeDeclarationClass,
- receiverKnownNotNull = false, keepLineNumbers = false)
-
- for (warning <- r) {
- if ((callee.annotatedInline && btypes.warnSettings.atInlineFailed) || warning.emitWarning(warnSettings)) {
- val annotWarn = if (callee.annotatedInline) " is annotated @inline but" else ""
- val msg = s"${BackendReporting.methodSignature(callee.calleeDeclarationClass.internalName, callee.callee)}$annotWarn could not be inlined:\n$warning"
- backendReporting.inlinerWarning(request.callsitePosition, msg)
+ // Inlining a method can create unreachable code. Example:
+ // def f = throw e
+ // def g = f; println() // println is unreachable after inlining f
+ // If we have an inline request for a call to g, and f has been already inlined into g, we
+ // need to run DCE before inlining g.
+ eliminateUnreachableCodeAndUpdateCallGraph(callee.callee, callee.calleeDeclarationClass.internalName)
+
+ // DCE above removes unreachable callsites from the call graph. If the inlining request denotes
+ // such an eliminated callsite, do nothing.
+ if (callGraph.callsites contains request.callsiteInstruction) {
+ val r = inline(request.callsiteInstruction, request.callsiteStackHeight, request.callsiteMethod, request.callsiteClass,
+ callee.callee, callee.calleeDeclarationClass,
+ receiverKnownNotNull = false, keepLineNumbers = false)
+
+ for (warning <- r) {
+ if ((callee.annotatedInline && btypes.compilerSettings.YoptWarningEmitAtInlineFailed) || warning.emitWarning(compilerSettings)) {
+ val annotWarn = if (callee.annotatedInline) " is annotated @inline but" else ""
+ val msg = s"${BackendReporting.methodSignature(callee.calleeDeclarationClass.internalName, callee.callee)}$annotWarn could not be inlined:\n$warning"
+ backendReporting.inlinerWarning(request.callsitePosition, msg)
+ }
}
}
}
@@ -75,7 +93,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
val res = doInlineCallsite(callsite)
if (!res) {
- if (annotatedInline && btypes.warnSettings.atInlineFailed) {
+ if (annotatedInline && btypes.compilerSettings.YoptWarningEmitAtInlineFailed) {
// if the callsite is annotated @inline, we report an inline warning even if the underlying
// reason is, for example, mixed compilation (which has a separate -Yopt-warning flag).
def initMsg = s"${BackendReporting.methodSignature(calleeDeclClass.internalName, callee)} is annotated @inline but cannot be inlined"
@@ -86,7 +104,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
backendReporting.inlinerWarning(pos, s"$initMsg: the method is not final and may be overridden." + warnMsg)
else
backendReporting.inlinerWarning(pos, s"$initMsg." + warnMsg)
- } else if (warning.isDefined && warning.get.emitWarning(warnSettings)) {
+ } else if (warning.isDefined && warning.get.emitWarning(compilerSettings)) {
// when annotatedInline is false, and there is some warning, the callsite metadata is possibly incomplete.
backendReporting.inlinerWarning(pos, s"there was a problem determining if method ${callee.name} can be inlined: \n"+ warning.get)
}
@@ -95,7 +113,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
res
case Callsite(ins, _, _, Left(warning), _, _, pos) =>
- if (warning.emitWarning(warnSettings))
+ if (warning.emitWarning(compilerSettings))
backendReporting.inlinerWarning(pos, s"failed to determine if ${ins.name} should be inlined:\n$warning")
false
}).toList
@@ -106,7 +124,8 @@ class Inliner[BT <: BTypes](val btypes: BT) {
*/
def doInlineCallsite(callsite: Callsite): Boolean = callsite match {
case Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, annotatedInline, _, warning)), _, _, pos) =>
- annotatedInline && safeToInline
+ if (compilerSettings.YoptInlineHeuristics.value == "everything") safeToInline
+ else annotatedInline && safeToInline
case _ => false
}
@@ -167,6 +186,8 @@ class Inliner[BT <: BTypes](val btypes: BT) {
// VerifyError. We run a `SourceInterpreter` to find all producer instructions of the
// receiver value and add a cast to the self type after each.
if (!selfTypeOk) {
+ // there's no need to run eliminateUnreachableCode here. building the call graph does that
+ // already, no code can become unreachable in the meantime.
val analyzer = new AsmAnalyzer(callsite.callsiteMethod, callsite.callsiteClass.internalName, new SourceInterpreter)
val receiverValue = analyzer.frameAt(callsite.callsiteInstruction).peekDown(traitMethodArgumentTypes.length)
for (i <- receiverValue.insns.asScala) {
@@ -311,6 +332,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
val localVarShift = callsiteMethod.maxLocals
clonedInstructions.iterator.asScala foreach {
case varInstruction: VarInsnNode => varInstruction.`var` += localVarShift
+ case iinc: IincInsnNode => iinc.`var` += localVarShift
case _ => ()
}
@@ -433,6 +455,9 @@ class Inliner[BT <: BTypes](val btypes: BT) {
// Remove the elided invocation from the call graph
callGraph.callsites.remove(callsiteInstruction)
+ // Inlining a method body can render some code unreachable, see example above (in runInliner).
+ unreachableCodeEliminated -= callsiteMethod
+
callsiteMethod.maxLocals += returnType.getSize + callee.maxLocals
callsiteMethod.maxStack = math.max(callsiteMethod.maxStack, callee.maxStack + callsiteStackHeight)
@@ -472,10 +497,18 @@ class Inliner[BT <: BTypes](val btypes: BT) {
callsiteStackHeight > expectedArgs
}
- if (isSynchronizedMethod(callee)) {
+ if (codeSizeOKForInlining(callsiteMethod, callee)) {
+ Some(ResultingMethodTooLarge(
+ calleeDeclarationClass.internalName, callee.name, callee.desc,
+ callsiteClass.internalName, callsiteMethod.name, callsiteMethod.desc))
+ } else if (isSynchronizedMethod(callee)) {
// Could be done by locking on the receiver, wrapping the inlined code in a try and unlocking
// in finally. But it's probably not worth the effort, scala never emits synchronized methods.
Some(SynchronizedMethod(calleeDeclarationClass.internalName, callee.name, callee.desc))
+ } else if (isStrictfpMethod(callsiteMethod) != isStrictfpMethod(callee)) {
+ Some(StrictfpMismatch(
+ calleeDeclarationClass.internalName, callee.name, callee.desc,
+ callsiteClass.internalName, callsiteMethod.name, callsiteMethod.desc))
} else if (!callee.tryCatchBlocks.isEmpty && stackHasNonParameters) {
Some(MethodWithHandlerCalledOnNonEmptyStack(
calleeDeclarationClass.internalName, callee.name, callee.desc,
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 f6cfc5598b..5f51a94673 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
@@ -14,7 +14,6 @@ import scala.tools.asm.tree._
import scala.collection.convert.decorateAsScala._
import scala.tools.nsc.backend.jvm.BTypes.InternalName
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
-import scala.tools.nsc.settings.ScalaSettings
/**
* Optimizations within a single method.
@@ -47,18 +46,9 @@ import scala.tools.nsc.settings.ScalaSettings
* stale labels
* - eliminate labels that are not referenced, merge sequences of label definitions.
*/
-class LocalOpt(settings: ScalaSettings) {
- /**
- * Remove unreachable code from all methods of `classNode`. See of its overload.
- *
- * @param classNode The class to optimize
- * @return `true` if unreachable code was removed from any method
- */
- def minimalRemoveUnreachableCode(classNode: ClassNode): Boolean = {
- classNode.methods.asScala.foldLeft(false) {
- case (changed, method) => minimalRemoveUnreachableCode(method, classNode.name) || changed
- }
- }
+class LocalOpt[BT <: BTypes](val btypes: BT) {
+ import LocalOptImpls._
+ import btypes._
/**
* Remove unreachable code from a method.
@@ -66,25 +56,30 @@ class LocalOpt(settings: ScalaSettings) {
* This implementation only removes instructions that are unreachable for an ASM analyzer /
* interpreter. This ensures that future analyses will not produce `null` frames. The inliner
* and call graph builder depend on this property.
+ *
+ * @return A set containing the eliminated instructions
*/
- def minimalRemoveUnreachableCode(method: MethodNode, ownerClassName: InternalName): Boolean = {
- if (method.instructions.size == 0) return false // fast path for abstract methods
+ def minimalRemoveUnreachableCode(method: MethodNode, ownerClassName: InternalName): Set[AbstractInsnNode] = {
+ if (method.instructions.size == 0) return Set.empty // fast path for abstract methods
+ if (unreachableCodeEliminated(method)) return Set.empty // we know there is no unreachable code
// For correctness, after removing unreachable code, we have to eliminate empty exception
// handlers, see scaladoc of def methodOptimizations. Removing an live handler may render more
// code unreachable and therefore requires running another round.
- def removalRound(): Boolean = {
- val (codeRemoved, liveLabels) = removeUnreachableCodeImpl(method, ownerClassName)
- if (codeRemoved) {
+ def removalRound(): Set[AbstractInsnNode] = {
+ val (removedInstructions, liveLabels) = removeUnreachableCodeImpl(method, ownerClassName)
+ val removedRecursively = if (removedInstructions.nonEmpty) {
val liveHandlerRemoved = removeEmptyExceptionHandlers(method).exists(h => liveLabels(h.start))
if (liveHandlerRemoved) removalRound()
- }
- codeRemoved
+ else Set.empty
+ } else Set.empty
+ removedInstructions ++ removedRecursively
}
- val codeRemoved = removalRound()
- if (codeRemoved) removeUnusedLocalVariableNodes(method)()
- codeRemoved
+ val removedInstructions = removalRound()
+ if (removedInstructions.nonEmpty) removeUnusedLocalVariableNodes(method)()
+ unreachableCodeEliminated += method
+ removedInstructions
}
/**
@@ -95,7 +90,7 @@ class LocalOpt(settings: ScalaSettings) {
* @return `true` if unreachable code was eliminated in some method, `false` otherwise.
*/
def methodOptimizations(clazz: ClassNode): Boolean = {
- !settings.YoptNone && clazz.methods.asScala.foldLeft(false) {
+ !compilerSettings.YoptNone && clazz.methods.asScala.foldLeft(false) {
case (changed, method) => methodOptimizations(method, clazz.name) || changed
}
}
@@ -144,15 +139,15 @@ class LocalOpt(settings: ScalaSettings) {
def removalRound(): Boolean = {
// unreachable-code, empty-handlers and simplify-jumps run until reaching a fixpoint (see doc on class LocalOpt)
- val (codeRemoved, handlersRemoved, liveHandlerRemoved) = if (settings.YoptUnreachableCode) {
- val (codeRemoved, liveLabels) = removeUnreachableCodeImpl(method, ownerClassName)
+ val (codeRemoved, handlersRemoved, liveHandlerRemoved) = if (compilerSettings.YoptUnreachableCode) {
+ val (removedInstructions, liveLabels) = removeUnreachableCodeImpl(method, ownerClassName)
val removedHandlers = removeEmptyExceptionHandlers(method)
- (codeRemoved, removedHandlers.nonEmpty, removedHandlers.exists(h => liveLabels(h.start)))
+ (removedInstructions.nonEmpty, removedHandlers.nonEmpty, removedHandlers.exists(h => liveLabels(h.start)))
} else {
(false, false, false)
}
- val jumpsChanged = if (settings.YoptSimplifyJumps) simplifyJumps(method) else false
+ val jumpsChanged = if (compilerSettings.YoptSimplifyJumps) simplifyJumps(method) else false
// Eliminating live handlers and simplifying jump instructions may render more code
// unreachable, so we need to run another round.
@@ -165,13 +160,13 @@ class LocalOpt(settings: ScalaSettings) {
// (*) Removing stale local variable descriptors is required for correctness of unreachable-code
val localsRemoved =
- if (settings.YoptCompactLocals) compactLocalVariables(method) // also removes unused
- else if (settings.YoptUnreachableCode) removeUnusedLocalVariableNodes(method)() // (*)
+ if (compilerSettings.YoptCompactLocals) compactLocalVariables(method) // also removes unused
+ else if (compilerSettings.YoptUnreachableCode) removeUnusedLocalVariableNodes(method)() // (*)
else false
- val lineNumbersRemoved = if (settings.YoptEmptyLineNumbers) removeEmptyLineNumbers(method) else false
+ val lineNumbersRemoved = if (compilerSettings.YoptEmptyLineNumbers) removeEmptyLineNumbers(method) else false
- val labelsRemoved = if (settings.YoptEmptyLabels) removeEmptyLabelNodes(method) else false
+ val labelsRemoved = if (compilerSettings.YoptEmptyLabels) removeEmptyLabelNodes(method) else false
// assert that local variable annotations are empty (we don't emit them) - otherwise we'd have
// to eliminate those covering an empty range, similar to removeUnusedLocalVariableNodes.
@@ -179,15 +174,22 @@ class LocalOpt(settings: ScalaSettings) {
assert(nullOrEmpty(method.visibleLocalVariableAnnotations), method.visibleLocalVariableAnnotations)
assert(nullOrEmpty(method.invisibleLocalVariableAnnotations), method.invisibleLocalVariableAnnotations)
+ unreachableCodeEliminated += method
+
codeHandlersOrJumpsChanged || localsRemoved || lineNumbersRemoved || labelsRemoved
}
+}
+
+object LocalOptImpls {
/**
* Removes unreachable basic blocks.
*
* TODO: rewrite, don't use computeMaxLocalsMaxStack (runs a ClassWriter) / Analyzer. Too slow.
+ *
+ * @return A set containing eliminated instructions, and a set containing all live label nodes.
*/
- def removeUnreachableCodeImpl(method: MethodNode, ownerClassName: InternalName): (Boolean, Set[LabelNode]) = {
+ def removeUnreachableCodeImpl(method: MethodNode, ownerClassName: InternalName): (Set[AbstractInsnNode], Set[LabelNode]) = {
// The data flow analysis requires the maxLocals / maxStack fields of the method to be computed.
computeMaxLocalsMaxStack(method)
val a = new Analyzer(new BasicInterpreter)
@@ -197,6 +199,7 @@ class LocalOpt(settings: ScalaSettings) {
val initialSize = method.instructions.size
var i = 0
var liveLabels = Set.empty[LabelNode]
+ var removedInstructions = Set.empty[AbstractInsnNode]
val itr = method.instructions.iterator()
while (itr.hasNext) {
itr.next() match {
@@ -209,11 +212,12 @@ class LocalOpt(settings: ScalaSettings) {
// Instruction iterators allow removing during iteration.
// Removing is O(1): instructions are doubly linked list elements.
itr.remove()
+ removedInstructions += ins
}
}
i += 1
}
- (method.instructions.size != initialSize, liveLabels)
+ (removedInstructions, liveLabels)
}
/**
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
index 5a7a0df595..1a5529140c 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala
@@ -60,13 +60,15 @@ abstract class Plugin {
* @return true to continue, or false to opt out
*/
def init(options: List[String], error: String => Unit): Boolean = {
- if (!options.isEmpty) error(s"Error: $name takes no options")
+ // call to deprecated method required here, we must continue to support
+ // code that subclasses that override `processOptions`.
+ processOptions(options, error)
true
}
@deprecated("use Plugin#init instead", since="2.11")
def processOptions(options: List[String], error: String => Unit): Unit = {
- init(options, error)
+ if (!options.isEmpty) error(s"Error: $name takes no options")
}
/** A description of this plugin's options, suitable as a response
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index d273995e6e..03fd0976e5 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -256,6 +256,13 @@ trait ScalaSettings extends AbsScalaSettings
def YoptInlineGlobal = Yopt.contains(YoptChoices.inlineGlobal)
def YoptInlinerEnabled = YoptInlineProject || YoptInlineGlobal
+ val YoptInlineHeuristics = ChoiceSetting(
+ name = "-Yopt-inline-heuristics",
+ helpArg = "strategy",
+ descr = "Set the heuristics for inlining decisions.",
+ choices = List("at-inline-annotated", "everything"),
+ default = "at-inline-annotated")
+
object YoptWarningsChoices extends MultiChoiceEnumeration {
val none = Choice("none" , "No optimizer warnings.")
val atInlineFailedSummary = Choice("at-inline-failed-summary" , "One-line summary if there were @inline method calls that could not be inlined.")
@@ -267,7 +274,7 @@ trait ScalaSettings extends AbsScalaSettings
val YoptWarnings = MultiChoiceSetting(
name = "-Yopt-warnings",
- helpArg = "warnings",
+ helpArg = "warning",
descr = "Enable optimizer warnings",
domain = YoptWarningsChoices,
default = Some(List(YoptWarningsChoices.atInlineFailed.name))) withPostSetHook (self => {
@@ -275,6 +282,15 @@ trait ScalaSettings extends AbsScalaSettings
else YinlinerWarnings.value = true
})
+ def YoptWarningEmitAtInlineFailed =
+ !YoptWarnings.isSetByUser ||
+ YoptWarnings.contains(YoptWarningsChoices.atInlineFailedSummary) ||
+ YoptWarnings.contains(YoptWarningsChoices.atInlineFailed)
+
+ def YoptWarningNoInlineMixed = YoptWarnings.contains(YoptWarningsChoices.noInlineMixed)
+ def YoptWarningNoInlineMissingBytecode = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingBytecode)
+ def YoptWarningNoInlineMissingScalaInlineInfoAttr = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingScalaInlineInfoAttr)
+
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."
object YstatisticsPhases extends MultiChoiceEnumeration { val parser, typer, patmat, erasure, cleanup, jvm = Value }
@@ -345,12 +361,7 @@ trait ScalaSettings extends AbsScalaSettings
/** Test whether this is scaladoc we're looking at */
def isScaladoc = false
- /**
- * Helper utilities for use by checkConflictingSettings()
- */
- def isBCodeActive = !isICodeAskedFor
- def isBCodeAskedFor = (Ybackend.value != "GenASM")
- def isICodeAskedFor = ((Ybackend.value == "GenASM") || optimiseSettings.exists(_.value) || writeICode.isSetByUser)
+ def isBCodeActive = Ybackend.value == "GenBCode"
object MacroExpand {
val None = "none"
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
index 0b53dc37de..4ea569c8e6 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
@@ -9,8 +9,7 @@ package tools.nsc.transform.patmat
import scala.language.postfixOps
import scala.collection.mutable
-import scala.reflect.internal.util.Statistics
-import scala.reflect.internal.util.HashSet
+import scala.reflect.internal.util.{NoPosition, Position, Statistics, HashSet}
trait Logic extends Debugging {
import PatternMatchingStats._
@@ -71,6 +70,8 @@ trait Logic extends Debugging {
def unapply(v: Var): Some[Tree]
}
+ def uncheckedWarning(pos: Position, msg: String): Unit
+
def reportWarning(message: String): Unit
// resets hash consing -- only supposed to be called by TreeMakersToProps
@@ -283,6 +284,23 @@ trait Logic extends Debugging {
}
}
+ // to govern how much time we spend analyzing matches for unreachability/exhaustivity
+ object AnalysisBudget {
+ val maxDPLLdepth = global.settings.YpatmatExhaustdepth.value
+ val maxFormulaSize = 100 * math.min(Int.MaxValue / 100, maxDPLLdepth)
+
+ private def advice =
+ s"Please try with scalac -Ypatmat-exhaust-depth ${maxDPLLdepth * 2} or -Ypatmat-exhaust-depth off."
+
+ def recursionDepthReached =
+ s"Exhaustivity analysis reached max recursion depth, not all missing cases are reported.\n($advice)"
+
+ abstract class Exception(val advice: String) extends RuntimeException("CNF budget exceeded")
+
+ object formulaSizeExceeded extends Exception(s"The analysis required more space than allowed.\n$advice")
+
+ }
+
// TODO: remove since deprecated
val budgetProp = scala.sys.Prop[String]("scalac.patmat.analysisBudget")
if (budgetProp.isSet) {
@@ -385,7 +403,7 @@ trait Logic extends Debugging {
def findModelFor(solvable: Solvable): Model
- def findAllModelsFor(solvable: Solvable): List[Solution]
+ def findAllModelsFor(solvable: Solvable, pos: Position = NoPosition): List[Solution]
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 34ebbc7463..cecb5c37be 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -399,6 +399,7 @@ trait MatchAnalysis extends MatchApproximation {
trait MatchAnalyzer extends MatchApproximator {
def uncheckedWarning(pos: Position, msg: String) = currentRun.reporting.uncheckedWarning(pos, msg)
+ def warn(pos: Position, ex: AnalysisBudget.Exception, kind: String) = uncheckedWarning(pos, s"Cannot check match for $kind.\n${ex.advice}")
def reportWarning(message: String) = global.reporter.warning(typer.context.tree.pos, message)
// TODO: model dependencies between variables: if V1 corresponds to (x: List[_]) and V2 is (x.hd), V2 cannot be assigned when V1 = null or V1 = Nil
@@ -429,44 +430,50 @@ trait MatchAnalysis extends MatchApproximation {
val propsCasesOk = approximate(True) map caseWithoutBodyToProp
val propsCasesFail = approximate(False) map (t => Not(caseWithoutBodyToProp(t)))
- val (eqAxiomsFail, symbolicCasesFail) = removeVarEq(propsCasesFail, modelNull = true)
- val (eqAxiomsOk, symbolicCasesOk) = removeVarEq(propsCasesOk, modelNull = true)
- val eqAxioms = simplify(And(eqAxiomsOk, eqAxiomsFail)) // I'm pretty sure eqAxiomsOk == eqAxiomsFail, but not 100% sure.
-
- val prefix = mutable.ArrayBuffer[Prop]()
- prefix += eqAxioms
-
- var prefixRest = symbolicCasesFail
- var current = symbolicCasesOk
- var reachable = true
- var caseIndex = 0
-
- debug.patmat("reachability, vars:\n" + ((propsCasesFail flatMap gatherVariables).distinct map (_.describe) mkString ("\n")))
- debug.patmat(s"equality axioms:\n$eqAxiomsOk")
-
- // invariant (prefixRest.length == current.length) && (prefix.reverse ++ prefixRest == symbolicCasesFail)
- // termination: prefixRest.length decreases by 1
- while (prefixRest.nonEmpty && reachable) {
- val prefHead = prefixRest.head
- caseIndex += 1
- prefixRest = prefixRest.tail
- if (prefixRest.isEmpty) reachable = true
- else {
- prefix += prefHead
- current = current.tail
+ try {
+ val (eqAxiomsFail, symbolicCasesFail) = removeVarEq(propsCasesFail, modelNull = true)
+ val (eqAxiomsOk, symbolicCasesOk) = removeVarEq(propsCasesOk, modelNull = true)
+ val eqAxioms = simplify(And(eqAxiomsOk, eqAxiomsFail)) // I'm pretty sure eqAxiomsOk == eqAxiomsFail, but not 100% sure.
+
+ val prefix = mutable.ArrayBuffer[Prop]()
+ prefix += eqAxioms
+
+ var prefixRest = symbolicCasesFail
+ var current = symbolicCasesOk
+ var reachable = true
+ var caseIndex = 0
+
+ debug.patmat("reachability, vars:\n" + ((propsCasesFail flatMap gatherVariables).distinct map (_.describe) mkString ("\n")))
+ debug.patmat(s"equality axioms:\n$eqAxiomsOk")
+
+ // invariant (prefixRest.length == current.length) && (prefix.reverse ++ prefixRest == symbolicCasesFail)
+ // termination: prefixRest.length decreases by 1
+ while (prefixRest.nonEmpty && reachable) {
+ val prefHead = prefixRest.head
+ caseIndex += 1
+ prefixRest = prefixRest.tail
+ if (prefixRest.isEmpty) reachable = true
+ else {
+ prefix += prefHead
+ current = current.tail
val and = And((current.head +: prefix): _*)
val model = findModelFor(eqFreePropToSolvable(and))
- // debug.patmat("trying to reach:\n"+ cnfString(current.head) +"\nunder prefix:\n"+ cnfString(prefix))
- // if (NoModel ne model) debug.patmat("reached: "+ modelString(model))
+ // debug.patmat("trying to reach:\n"+ cnfString(current.head) +"\nunder prefix:\n"+ cnfString(prefix))
+ // if (NoModel ne model) debug.patmat("reached: "+ modelString(model))
- reachable = NoModel ne model
+ reachable = NoModel ne model
+ }
}
- }
- if (Statistics.canEnable) Statistics.stopTimer(patmatAnaReach, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaReach, start)
- if (reachable) None else Some(caseIndex)
+ if (reachable) None else Some(caseIndex)
+ } catch {
+ case ex: AnalysisBudget.Exception =>
+ warn(prevBinder.pos, ex, "unreachability")
+ None // CNF budget exceeded
+ }
}
// exhaustivity
@@ -507,32 +514,38 @@ trait MatchAnalysis extends MatchApproximation {
// when does the match fail?
val matchFails = Not(\/(symbolicCases))
- // debug output:
+ // debug output:
debug.patmat("analysing:")
showTreeMakers(cases)
// debug.patmat("\nvars:\n"+ (vars map (_.describe) mkString ("\n")))
// debug.patmat("\nmatchFails as CNF:\n"+ cnfString(propToSolvable(matchFails)))
- // find the models (under which the match fails)
- val matchFailModels = findAllModelsFor(propToSolvable(matchFails))
+ try {
+ // find the models (under which the match fails)
+ val matchFailModels = findAllModelsFor(propToSolvable(matchFails), prevBinder.pos)
- val scrutVar = Var(prevBinderTree)
- val counterExamples = {
- matchFailModels.flatMap {
- model =>
- val varAssignments = expandModel(model)
- varAssignments.flatMap(modelToCounterExample(scrutVar) _)
+ val scrutVar = Var(prevBinderTree)
+ val counterExamples = {
+ matchFailModels.flatMap {
+ model =>
+ val varAssignments = expandModel(model)
+ varAssignments.flatMap(modelToCounterExample(scrutVar) _)
+ }
}
- }
-
- // sorting before pruning is important here in order to
- // keep neg/t7020.scala stable
- // since e.g. List(_, _) would cover List(1, _)
- val pruned = CounterExample.prune(counterExamples.sortBy(_.toString)).map(_.toString)
- if (Statistics.canEnable) Statistics.stopTimer(patmatAnaExhaust, start)
- pruned
+ // sorting before pruning is important here in order to
+ // keep neg/t7020.scala stable
+ // since e.g. List(_, _) would cover List(1, _)
+ val pruned = CounterExample.prune(counterExamples.sortBy(_.toString)).map(_.toString)
+
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaExhaust, start)
+ pruned
+ } catch {
+ case ex: AnalysisBudget.Exception =>
+ warn(prevBinder.pos, ex, "exhaustivity")
+ Nil // CNF budget exceeded
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
index 27217f0dc2..c43f1b6209 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Solving.scala
@@ -11,6 +11,7 @@ import scala.reflect.internal.util.Statistics
import scala.language.postfixOps
import scala.collection.mutable
import scala.reflect.internal.util.Collections._
+import scala.reflect.internal.util.Position
// a literal is a (possibly negated) variable
class Lit(val v: Int) extends AnyVal {
@@ -64,7 +65,12 @@ trait Solving extends Logic {
def size = symbols.size
}
- case class Solvable(cnf: Cnf, symbolMapping: SymbolMapping)
+ final case class Solvable(cnf: Cnf, symbolMapping: SymbolMapping) {
+ def ++(other: Solvable) = {
+ require(this.symbolMapping eq other.symbolMapping)
+ Solvable(cnf ++ other.cnf, symbolMapping)
+ }
+ }
trait CnfBuilder {
private[this] val buff = ArrayBuffer[Clause]()
@@ -95,7 +101,11 @@ trait Solving extends Logic {
}
}
- def buildCnf: Array[Clause] = buff.toArray
+ def buildCnf: Array[Clause] = {
+ val cnf = buff.toArray
+ buff.clear()
+ cnf
+ }
}
@@ -244,19 +254,54 @@ trait Solving extends Logic {
def eqFreePropToSolvable(p: Prop): Solvable = {
+ def doesFormulaExceedSize(p: Prop): Boolean = {
+ p match {
+ case And(ops) =>
+ if (ops.size > AnalysisBudget.maxFormulaSize) {
+ true
+ } else {
+ ops.exists(doesFormulaExceedSize)
+ }
+ case Or(ops) =>
+ if (ops.size > AnalysisBudget.maxFormulaSize) {
+ true
+ } else {
+ ops.exists(doesFormulaExceedSize)
+ }
+ case Not(a) => doesFormulaExceedSize(a)
+ case _ => false
+ }
+ }
+
+ val simplified = simplify(p)
+ if (doesFormulaExceedSize(simplified)) {
+ throw AnalysisBudget.formulaSizeExceeded
+ }
+
// collect all variables since after simplification / CNF conversion
// they could have been removed from the formula
val symbolMapping = new SymbolMapping(gatherSymbols(p))
-
- val simplified = simplify(p)
val cnfExtractor = new AlreadyInCNF(symbolMapping)
+ val cnfTransformer = new TransformToCnf(symbolMapping)
+
+ def cnfFor(prop: Prop): Solvable = {
+ prop match {
+ case cnfExtractor.ToCnf(solvable) =>
+ // this is needed because t6942 would generate too many clauses with Tseitin
+ // already in CNF, just add clauses
+ solvable
+ case p =>
+ cnfTransformer.apply(p)
+ }
+ }
+
simplified match {
- case cnfExtractor.ToCnf(solvable) =>
- // this is needed because t6942 would generate too many clauses with Tseitin
- // already in CNF, just add clauses
- solvable
- case p =>
- new TransformToCnf(symbolMapping).apply(p)
+ case And(props) =>
+ // SI-6942:
+ // CNF(P1 /\ ... /\ PN) == CNF(P1) ++ CNF(...) ++ CNF(PN)
+ props.map(cnfFor).reduce(_ ++ _)
+ case p =>
+ cnfFor(p)
}
}
}
@@ -288,7 +333,7 @@ trait Solving extends Logic {
val NoTseitinModel: TseitinModel = null
// returns all solutions, if any (TODO: better infinite recursion backstop -- detect fixpoint??)
- def findAllModelsFor(solvable: Solvable): List[Solution] = {
+ def findAllModelsFor(solvable: Solvable, pos: Position): List[Solution] = {
debug.patmat("find all models for\n"+ cnfString(solvable.cnf))
// we must take all vars from non simplified formula
@@ -308,13 +353,12 @@ trait Solving extends Logic {
final case class TseitinSolution(model: TseitinModel, unassigned: List[Int]) {
def projectToSolution(symForVar: Map[Int, Sym]) = Solution(projectToModel(model, symForVar), unassigned map symForVar)
}
+
def findAllModels(clauses: Array[Clause],
models: List[TseitinSolution],
- recursionDepthAllowed: Int = global.settings.YpatmatExhaustdepth.value): List[TseitinSolution]=
+ recursionDepthAllowed: Int = AnalysisBudget.maxDPLLdepth): List[TseitinSolution]=
if (recursionDepthAllowed == 0) {
- val maxDPLLdepth = global.settings.YpatmatExhaustdepth.value
- reportWarning("(Exhaustivity analysis reached max recursion depth, not all missing cases are reported. " +
- s"Please try with scalac -Ypatmat-exhaust-depth ${maxDPLLdepth * 2} or -Ypatmat-exhaust-depth off.)")
+ uncheckedWarning(pos, AnalysisBudget.recursionDepthReached)
models
} else {
debug.patmat("find all models for\n" + cnfString(clauses))
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index db81eecdf5..e0d96df062 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -322,7 +322,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case Super(_, mix) =>
if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) {
if (!settings.overrideVars)
- reporter.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf)
+ reporter.error(tree.pos, "super may not be used on " + sym.accessedOrSelf)
} else if (isDisallowed(sym)) {
reporter.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
}
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 5a07874fd6..f187a7a655 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -54,7 +54,7 @@ import scala.language.higherKinds
* `HashMap` of objects. The traversal order for hash maps will
* depend on the hash codes of its elements, and these hash codes might
* differ from one run to the next. By contrast, a `LinkedHashMap`
- * is ordered because it's `foreach` method visits elements in the
+ * is ordered because its `foreach` method visits elements in the
* order they were inserted into the `HashMap`.
*
* @author Martin Odersky
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index 2eab58009c..c5b0d0f085 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -128,8 +128,21 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
* @example `Seq("a", 1, 5L).collectFirst({ case x: Int => x*10 }) = Some(10)`
*/
def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
- // make sure to use an iterator or `seq`
- self.toIterator.foreach(pf.runWith(b => return Some(b)))
+ // TODO 2.12 -- move out alternate implementations into child classes
+ val i: Iterator[A] = self match {
+ case it: Iterator[A] => it
+ case _: GenIterable[_] => self.toIterator // If it might be parallel, be sure to .seq or use iterator!
+ case _ => // Not parallel, not iterable--just traverse
+ self.foreach(pf.runWith(b => return Some(b)))
+ return None
+ }
+ // Presumably the fastest way to get in and out of a partial function is for a sentinel function to return itself
+ // (Tested to be lower-overhead than runWith. Would be better yet to not need to (formally) allocate it--change in 2.12.)
+ val sentinel: Function1[A, Any] = new scala.runtime.AbstractFunction1[A, Any]{ def apply(a: A) = this }
+ while (i.hasNext) {
+ val x = pf.applyOrElse(i.next, sentinel)
+ if (x.asInstanceOf[AnyRef] ne sentinel) return Some(x.asInstanceOf[B])
+ }
None
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 6efac6d873..237efd004f 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -1285,16 +1285,12 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
jclazz getDeclaredConstructor (effectiveParamClasses: _*)
}
- private def jArrayClass(elemClazz: jClass[_]): jClass[_] = {
- jArray.newInstance(elemClazz, 0).getClass
- }
-
/** The Java class that corresponds to given Scala type.
* Pre: Scala type is already transformed to Java level.
*/
def typeToJavaClass(tpe: Type): jClass[_] = tpe match {
case ExistentialType(_, rtpe) => typeToJavaClass(rtpe)
- case TypeRef(_, ArrayClass, List(elemtpe)) => jArrayClass(typeToJavaClass(elemtpe))
+ case TypeRef(_, ArrayClass, List(elemtpe)) => ScalaRunTime.arrayClass(typeToJavaClass(elemtpe))
case TypeRef(_, sym: ClassSymbol, _) => classToJava(sym.asClass)
case tpe @ TypeRef(_, sym: AliasTypeSymbol, _) => typeToJavaClass(tpe.dealias)
case SingleType(_, sym: ModuleSymbol) => classToJava(sym.moduleClass.asClass)
diff --git a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
index d31b877262..fb4ed34571 100755
--- a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala
@@ -281,13 +281,16 @@ trait CommentFactoryBase { this: MemberLookupBase =>
parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock)
case line :: ls if (lastTagKey.isDefined) =>
- val key = lastTagKey.get
- val value =
- ((tags get key): @unchecked) match {
- case Some(b :: bs) => (b + endOfLine + line) :: bs
- case None => oops("lastTagKey set when no tag exists for key")
- }
- parse0(docBody, tags + (key -> value), lastTagKey, ls, inCodeBlock)
+ val newtags = if (!line.isEmpty) {
+ val key = lastTagKey.get
+ val value =
+ ((tags get key): @unchecked) match {
+ case Some(b :: bs) => (b + endOfLine + line) :: bs
+ case None => oops("lastTagKey set when no tag exists for key")
+ }
+ tags + (key -> value)
+ } else tags
+ parse0(docBody, newtags, lastTagKey, ls, inCodeBlock)
case line :: ls =>
if (docBody.length > 0) docBody append endOfLine
@@ -315,18 +318,18 @@ trait CommentFactoryBase { this: MemberLookupBase =>
val bodyTags: mutable.Map[TagKey, List[Body]] =
mutable.Map(tagsWithoutDiagram mapValues {tag => tag map (parseWikiAtSymbol(_, pos, site))} toSeq: _*)
- def oneTag(key: SimpleTagKey): Option[Body] =
+ def oneTag(key: SimpleTagKey, filterEmpty: Boolean = true): Option[Body] =
((bodyTags remove key): @unchecked) match {
- case Some(r :: rs) =>
+ case Some(r :: rs) if !(filterEmpty && r.blocks.isEmpty) =>
if (!rs.isEmpty) reporter.warning(pos, "Only one '@" + key.name + "' tag is allowed")
Some(r)
- case None => None
+ case _ => None
}
def allTags(key: SimpleTagKey): List[Body] =
- (bodyTags remove key) getOrElse Nil
+ (bodyTags remove key).getOrElse(Nil).filterNot(_.blocks.isEmpty)
- def allSymsOneTag(key: TagKey): Map[String, Body] = {
+ def allSymsOneTag(key: TagKey, filterEmpty: Boolean = true): Map[String, Body] = {
val keys: Seq[SymbolTagKey] =
bodyTags.keys.toSeq flatMap {
case stk: SymbolTagKey if (stk.name == key.name) => Some(stk)
@@ -342,11 +345,11 @@ trait CommentFactoryBase { this: MemberLookupBase =>
reporter.warning(pos, "Only one '@" + key.name + "' tag for symbol " + key.symbol + " is allowed")
(key.symbol, bs.head)
}
- Map.empty[String, Body] ++ pairs
+ Map.empty[String, Body] ++ (if (filterEmpty) pairs.filterNot(_._2.blocks.isEmpty) else pairs)
}
def linkedExceptions: Map[String, Body] = {
- val m = allSymsOneTag(SimpleTagKey("throws"))
+ val m = allSymsOneTag(SimpleTagKey("throws"), filterEmpty = false)
m.map { case (name,body) =>
val link = memberLookup(pos, name, site)
@@ -372,7 +375,7 @@ trait CommentFactoryBase { this: MemberLookupBase =>
version0 = oneTag(SimpleTagKey("version")),
since0 = oneTag(SimpleTagKey("since")),
todo0 = allTags(SimpleTagKey("todo")),
- deprecated0 = oneTag(SimpleTagKey("deprecated")),
+ deprecated0 = oneTag(SimpleTagKey("deprecated"), filterEmpty = false),
note0 = allTags(SimpleTagKey("note")),
example0 = allTags(SimpleTagKey("example")),
constructor0 = oneTag(SimpleTagKey("constructor")),
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
index 6eee280267..f158aa7309 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
+++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css
@@ -210,6 +210,7 @@ dl.attributes > dd {
display: block;
padding-left: 10em;
margin-bottom: 5px;
+ min-height: 15px;
}
#template .values > h3 {
@@ -669,6 +670,7 @@ div.fullcomment dl.paramcmts > dd {
padding-left: 10px;
margin-bottom: 5px;
margin-left: 70px;
+ min-height: 15px;
}
/* Members filter tool */
diff --git a/test/files/neg/case-collision2.flags b/test/files/neg/case-collision2.flags
index 5bfa9da5c5..bea46902c9 100644
--- a/test/files/neg/case-collision2.flags
+++ b/test/files/neg/case-collision2.flags
@@ -1 +1 @@
--Ynooptimize -Ybackend:GenBCode -Xfatal-warnings
+-Ybackend:GenBCode -Xfatal-warnings
diff --git a/test/files/neg/inlineMaxSize.check b/test/files/neg/inlineMaxSize.check
new file mode 100644
index 0000000000..d218a8b6e2
--- /dev/null
+++ b/test/files/neg/inlineMaxSize.check
@@ -0,0 +1,9 @@
+inlineMaxSize.scala:7: warning: C::i()I is annotated @inline but could not be inlined:
+The size of the callsite method C::j()I
+would exceed the JVM method size limit after inlining C::i()I.
+
+ @inline final def j = i + i
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/inlineMaxSize.flags b/test/files/neg/inlineMaxSize.flags
new file mode 100644
index 0000000000..9c6b811622
--- /dev/null
+++ b/test/files/neg/inlineMaxSize.flags
@@ -0,0 +1 @@
+-Ybackend:GenBCode -Ydelambdafy:method -Yopt:l:classpath -Yopt-warnings -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/inlineMaxSize.scala b/test/files/neg/inlineMaxSize.scala
new file mode 100644
index 0000000000..16dc0d9538
--- /dev/null
+++ b/test/files/neg/inlineMaxSize.scala
@@ -0,0 +1,8 @@
+// not a JUnit test because of https://github.com/scala-opt/scala/issues/23
+class C {
+ @inline final def f = 0
+ @inline final def g = f + f + f + f + f + f + f + f + f + f
+ @inline final def h = g + g + g + g + g + g + g + g + g + g
+ @inline final def i = h + h + h + h + h + h + h + h + h + h
+ @inline final def j = i + i
+}
diff --git a/test/files/neg/t0899.check b/test/files/neg/t0899.check
index 8b71be8e0c..28cb06ae5a 100644
--- a/test/files/neg/t0899.check
+++ b/test/files/neg/t0899.check
@@ -1,10 +1,10 @@
-t0899.scala:9: error: super may be not be used on value o
+t0899.scala:9: error: super may not be used on value o
override val o = "Ha! " + super.o
^
-t0899.scala:11: error: super may be not be used on variable v
+t0899.scala:11: error: super may not be used on variable v
super.v = "aa"
^
-t0899.scala:12: error: super may be not be used on variable v
+t0899.scala:12: error: super may not be used on variable v
println(super.v)
^
three errors found
diff --git a/test/files/neg/t562.check b/test/files/neg/t562.check
index 8c3823642a..95be075af1 100644
--- a/test/files/neg/t562.check
+++ b/test/files/neg/t562.check
@@ -1,4 +1,4 @@
-t562.scala:10: error: super may be not be used on value y
+t562.scala:10: error: super may not be used on value y
override val y = super.y;
^
one error found
diff --git a/test/files/pos/t6942.flags b/test/files/pos/t6942.flags
index e8fb65d50c..0f96f1f872 100644
--- a/test/files/pos/t6942.flags
+++ b/test/files/pos/t6942.flags
@@ -1 +1 @@
--Xfatal-warnings \ No newline at end of file
+-nowarn \ No newline at end of file
diff --git a/test/files/pos/t9181.flags b/test/files/pos/t9181.flags
new file mode 100644
index 0000000000..0f96f1f872
--- /dev/null
+++ b/test/files/pos/t9181.flags
@@ -0,0 +1 @@
+-nowarn \ No newline at end of file
diff --git a/test/files/pos/t9181.scala b/test/files/pos/t9181.scala
new file mode 100644
index 0000000000..2edf6fe4a3
--- /dev/null
+++ b/test/files/pos/t9181.scala
@@ -0,0 +1,806 @@
+sealed trait C
+case object C1 extends C
+case object C2 extends C
+case object C3 extends C
+case object C4 extends C
+case object C5 extends C
+case object C6 extends C
+case object C7 extends C
+case object C8 extends C
+case object C9 extends C
+case object C10 extends C
+case object C11 extends C
+case object C12 extends C
+case object C13 extends C
+case object C14 extends C
+case object C15 extends C
+case object C16 extends C
+case object C17 extends C
+case object C18 extends C
+case object C19 extends C
+case object C20 extends C
+case object C21 extends C
+case object C22 extends C
+case object C23 extends C
+case object C24 extends C
+case object C25 extends C
+case object C26 extends C
+case object C27 extends C
+case object C28 extends C
+case object C29 extends C
+case object C30 extends C
+case object C31 extends C
+case object C32 extends C
+case object C33 extends C
+case object C34 extends C
+case object C35 extends C
+case object C36 extends C
+case object C37 extends C
+case object C38 extends C
+case object C39 extends C
+case object C40 extends C
+case object C41 extends C
+case object C42 extends C
+case object C43 extends C
+case object C44 extends C
+case object C45 extends C
+case object C46 extends C
+case object C47 extends C
+case object C48 extends C
+case object C49 extends C
+case object C50 extends C
+case object C51 extends C
+case object C52 extends C
+case object C53 extends C
+case object C54 extends C
+case object C55 extends C
+case object C56 extends C
+case object C57 extends C
+case object C58 extends C
+case object C59 extends C
+case object C60 extends C
+case object C61 extends C
+case object C62 extends C
+case object C63 extends C
+case object C64 extends C
+case object C65 extends C
+case object C66 extends C
+case object C67 extends C
+case object C68 extends C
+case object C69 extends C
+case object C70 extends C
+case object C71 extends C
+case object C72 extends C
+case object C73 extends C
+case object C74 extends C
+case object C75 extends C
+case object C76 extends C
+case object C77 extends C
+case object C78 extends C
+case object C79 extends C
+case object C80 extends C
+case object C81 extends C
+case object C82 extends C
+case object C83 extends C
+case object C84 extends C
+case object C85 extends C
+case object C86 extends C
+case object C87 extends C
+case object C88 extends C
+case object C89 extends C
+case object C90 extends C
+case object C91 extends C
+case object C92 extends C
+case object C93 extends C
+case object C94 extends C
+case object C95 extends C
+case object C96 extends C
+case object C97 extends C
+case object C98 extends C
+case object C99 extends C
+case object C100 extends C
+case object C101 extends C
+case object C102 extends C
+case object C103 extends C
+case object C104 extends C
+case object C105 extends C
+case object C106 extends C
+case object C107 extends C
+case object C108 extends C
+case object C109 extends C
+case object C110 extends C
+case object C111 extends C
+case object C112 extends C
+case object C113 extends C
+case object C114 extends C
+case object C115 extends C
+case object C116 extends C
+case object C117 extends C
+case object C118 extends C
+case object C119 extends C
+case object C120 extends C
+case object C121 extends C
+case object C122 extends C
+case object C123 extends C
+case object C124 extends C
+case object C125 extends C
+case object C126 extends C
+case object C127 extends C
+case object C128 extends C
+case object C129 extends C
+case object C130 extends C
+case object C131 extends C
+case object C132 extends C
+case object C133 extends C
+case object C134 extends C
+case object C135 extends C
+case object C136 extends C
+case object C137 extends C
+case object C138 extends C
+case object C139 extends C
+case object C140 extends C
+case object C141 extends C
+case object C142 extends C
+case object C143 extends C
+case object C144 extends C
+case object C145 extends C
+case object C146 extends C
+case object C147 extends C
+case object C148 extends C
+case object C149 extends C
+case object C150 extends C
+case object C151 extends C
+case object C152 extends C
+case object C153 extends C
+case object C154 extends C
+case object C155 extends C
+case object C156 extends C
+case object C157 extends C
+case object C158 extends C
+case object C159 extends C
+case object C160 extends C
+case object C161 extends C
+case object C162 extends C
+case object C163 extends C
+case object C164 extends C
+case object C165 extends C
+case object C166 extends C
+case object C167 extends C
+case object C168 extends C
+case object C169 extends C
+case object C170 extends C
+case object C171 extends C
+case object C172 extends C
+case object C173 extends C
+case object C174 extends C
+case object C175 extends C
+case object C176 extends C
+case object C177 extends C
+case object C178 extends C
+case object C179 extends C
+case object C180 extends C
+case object C181 extends C
+case object C182 extends C
+case object C183 extends C
+case object C184 extends C
+case object C185 extends C
+case object C186 extends C
+case object C187 extends C
+case object C188 extends C
+case object C189 extends C
+case object C190 extends C
+case object C191 extends C
+case object C192 extends C
+case object C193 extends C
+case object C194 extends C
+case object C195 extends C
+case object C196 extends C
+case object C197 extends C
+case object C198 extends C
+case object C199 extends C
+case object C200 extends C
+case object C201 extends C
+case object C202 extends C
+case object C203 extends C
+case object C204 extends C
+case object C205 extends C
+case object C206 extends C
+case object C207 extends C
+case object C208 extends C
+case object C209 extends C
+case object C210 extends C
+case object C211 extends C
+case object C212 extends C
+case object C213 extends C
+case object C214 extends C
+case object C215 extends C
+case object C216 extends C
+case object C217 extends C
+case object C218 extends C
+case object C219 extends C
+case object C220 extends C
+case object C221 extends C
+case object C222 extends C
+case object C223 extends C
+case object C224 extends C
+case object C225 extends C
+case object C226 extends C
+case object C227 extends C
+case object C228 extends C
+case object C229 extends C
+case object C230 extends C
+case object C231 extends C
+case object C232 extends C
+case object C233 extends C
+case object C234 extends C
+case object C235 extends C
+case object C236 extends C
+case object C237 extends C
+case object C238 extends C
+case object C239 extends C
+case object C240 extends C
+case object C241 extends C
+case object C242 extends C
+case object C243 extends C
+case object C244 extends C
+case object C245 extends C
+case object C246 extends C
+case object C247 extends C
+case object C248 extends C
+case object C249 extends C
+case object C250 extends C
+case object C251 extends C
+case object C252 extends C
+case object C253 extends C
+case object C254 extends C
+case object C255 extends C
+case object C256 extends C
+case object C257 extends C
+case object C258 extends C
+case object C259 extends C
+case object C260 extends C
+case object C261 extends C
+case object C262 extends C
+case object C263 extends C
+case object C264 extends C
+case object C265 extends C
+case object C266 extends C
+case object C267 extends C
+case object C268 extends C
+case object C269 extends C
+case object C270 extends C
+case object C271 extends C
+case object C272 extends C
+case object C273 extends C
+case object C274 extends C
+case object C275 extends C
+case object C276 extends C
+case object C277 extends C
+case object C278 extends C
+case object C279 extends C
+case object C280 extends C
+case object C281 extends C
+case object C282 extends C
+case object C283 extends C
+case object C284 extends C
+case object C285 extends C
+case object C286 extends C
+case object C287 extends C
+case object C288 extends C
+case object C289 extends C
+case object C290 extends C
+case object C291 extends C
+case object C292 extends C
+case object C293 extends C
+case object C294 extends C
+case object C295 extends C
+case object C296 extends C
+case object C297 extends C
+case object C298 extends C
+case object C299 extends C
+case object C300 extends C
+case object C301 extends C
+case object C302 extends C
+case object C303 extends C
+case object C304 extends C
+case object C305 extends C
+case object C306 extends C
+case object C307 extends C
+case object C308 extends C
+case object C309 extends C
+case object C310 extends C
+case object C311 extends C
+case object C312 extends C
+case object C313 extends C
+case object C314 extends C
+case object C315 extends C
+case object C316 extends C
+case object C317 extends C
+case object C318 extends C
+case object C319 extends C
+case object C320 extends C
+case object C321 extends C
+case object C322 extends C
+case object C323 extends C
+case object C324 extends C
+case object C325 extends C
+case object C326 extends C
+case object C327 extends C
+case object C328 extends C
+case object C329 extends C
+case object C330 extends C
+case object C331 extends C
+case object C332 extends C
+case object C333 extends C
+case object C334 extends C
+case object C335 extends C
+case object C336 extends C
+case object C337 extends C
+case object C338 extends C
+case object C339 extends C
+case object C340 extends C
+case object C341 extends C
+case object C342 extends C
+case object C343 extends C
+case object C344 extends C
+case object C345 extends C
+case object C346 extends C
+case object C347 extends C
+case object C348 extends C
+case object C349 extends C
+case object C350 extends C
+case object C351 extends C
+case object C352 extends C
+case object C353 extends C
+case object C354 extends C
+case object C355 extends C
+case object C356 extends C
+case object C357 extends C
+case object C358 extends C
+case object C359 extends C
+case object C360 extends C
+case object C361 extends C
+case object C362 extends C
+case object C363 extends C
+case object C364 extends C
+case object C365 extends C
+case object C366 extends C
+case object C367 extends C
+case object C368 extends C
+case object C369 extends C
+case object C370 extends C
+case object C371 extends C
+case object C372 extends C
+case object C373 extends C
+case object C374 extends C
+case object C375 extends C
+case object C376 extends C
+case object C377 extends C
+case object C378 extends C
+case object C379 extends C
+case object C380 extends C
+case object C381 extends C
+case object C382 extends C
+case object C383 extends C
+case object C384 extends C
+case object C385 extends C
+case object C386 extends C
+case object C387 extends C
+case object C388 extends C
+case object C389 extends C
+case object C390 extends C
+case object C391 extends C
+case object C392 extends C
+case object C393 extends C
+case object C394 extends C
+case object C395 extends C
+case object C396 extends C
+case object C397 extends C
+case object C398 extends C
+case object C399 extends C
+case object C400 extends C
+
+object M {
+ def f(c: C): Int = c match {
+ case C1 => 1
+ case C2 => 2
+ case C3 => 3
+ case C4 => 4
+ case C5 => 5
+ case C6 => 6
+ case C7 => 7
+ case C8 => 8
+ case C9 => 9
+ case C10 => 10
+ case C11 => 11
+ case C12 => 12
+ case C13 => 13
+ case C14 => 14
+ case C15 => 15
+ case C16 => 16
+ case C17 => 17
+ case C18 => 18
+ case C19 => 19
+ case C20 => 20
+ case C21 => 21
+ case C22 => 22
+ case C23 => 23
+ case C24 => 24
+ case C25 => 25
+ case C26 => 26
+ case C27 => 27
+ case C28 => 28
+ case C29 => 29
+ case C30 => 30
+ case C31 => 31
+ case C32 => 32
+ case C33 => 33
+ case C34 => 34
+ case C35 => 35
+ case C36 => 36
+ case C37 => 37
+ case C38 => 38
+ case C39 => 39
+ case C40 => 40
+ case C41 => 41
+ case C42 => 42
+ case C43 => 43
+ case C44 => 44
+ case C45 => 45
+ case C46 => 46
+ case C47 => 47
+ case C48 => 48
+ case C49 => 49
+ case C50 => 50
+ case C51 => 51
+ case C52 => 52
+ case C53 => 53
+ case C54 => 54
+ case C55 => 55
+ case C56 => 56
+ case C57 => 57
+ case C58 => 58
+ case C59 => 59
+ case C60 => 60
+ case C61 => 61
+ case C62 => 62
+ case C63 => 63
+ case C64 => 64
+ case C65 => 65
+ case C66 => 66
+ case C67 => 67
+ case C68 => 68
+ case C69 => 69
+ case C70 => 70
+ case C71 => 71
+ case C72 => 72
+ case C73 => 73
+ case C74 => 74
+ case C75 => 75
+ case C76 => 76
+ case C77 => 77
+ case C78 => 78
+ case C79 => 79
+ case C80 => 80
+ case C81 => 81
+ case C82 => 82
+ case C83 => 83
+ case C84 => 84
+ case C85 => 85
+ case C86 => 86
+ case C87 => 87
+ case C88 => 88
+ case C89 => 89
+ case C90 => 90
+ case C91 => 91
+ case C92 => 92
+ case C93 => 93
+ case C94 => 94
+ case C95 => 95
+ case C96 => 96
+ case C97 => 97
+ case C98 => 98
+ case C99 => 99
+ case C100 => 100
+ case C101 => 101
+ case C102 => 102
+ case C103 => 103
+ case C104 => 104
+ case C105 => 105
+ case C106 => 106
+ case C107 => 107
+ case C108 => 108
+ case C109 => 109
+ case C110 => 110
+ case C111 => 111
+ case C112 => 112
+ case C113 => 113
+ case C114 => 114
+ case C115 => 115
+ case C116 => 116
+ case C117 => 117
+ case C118 => 118
+ case C119 => 119
+ case C120 => 120
+ case C121 => 121
+ case C122 => 122
+ case C123 => 123
+ case C124 => 124
+ case C125 => 125
+ case C126 => 126
+ case C127 => 127
+ case C128 => 128
+ case C129 => 129
+ case C130 => 130
+ case C131 => 131
+ case C132 => 132
+ case C133 => 133
+ case C134 => 134
+ case C135 => 135
+ case C136 => 136
+ case C137 => 137
+ case C138 => 138
+ case C139 => 139
+ case C140 => 140
+ case C141 => 141
+ case C142 => 142
+ case C143 => 143
+ case C144 => 144
+ case C145 => 145
+ case C146 => 146
+ case C147 => 147
+ case C148 => 148
+ case C149 => 149
+ case C150 => 150
+ case C151 => 151
+ case C152 => 152
+ case C153 => 153
+ case C154 => 154
+ case C155 => 155
+ case C156 => 156
+ case C157 => 157
+ case C158 => 158
+ case C159 => 159
+ case C160 => 160
+ case C161 => 161
+ case C162 => 162
+ case C163 => 163
+ case C164 => 164
+ case C165 => 165
+ case C166 => 166
+ case C167 => 167
+ case C168 => 168
+ case C169 => 169
+ case C170 => 170
+ case C171 => 171
+ case C172 => 172
+ case C173 => 173
+ case C174 => 174
+ case C175 => 175
+ case C176 => 176
+ case C177 => 177
+ case C178 => 178
+ case C179 => 179
+ case C180 => 180
+ case C181 => 181
+ case C182 => 182
+ case C183 => 183
+ case C184 => 184
+ case C185 => 185
+ case C186 => 186
+ case C187 => 187
+ case C188 => 188
+ case C189 => 189
+ case C190 => 190
+ case C191 => 191
+ case C192 => 192
+ case C193 => 193
+ case C194 => 194
+ case C195 => 195
+ case C196 => 196
+ case C197 => 197
+ case C198 => 198
+ case C199 => 199
+ case C200 => 200
+ case C201 => 201
+ case C202 => 202
+ case C203 => 203
+ case C204 => 204
+ case C205 => 205
+ case C206 => 206
+ case C207 => 207
+ case C208 => 208
+ case C209 => 209
+ case C210 => 210
+ case C211 => 211
+ case C212 => 212
+ case C213 => 213
+ case C214 => 214
+ case C215 => 215
+ case C216 => 216
+ case C217 => 217
+ case C218 => 218
+ case C219 => 219
+ case C220 => 220
+ case C221 => 221
+ case C222 => 222
+ case C223 => 223
+ case C224 => 224
+ case C225 => 225
+ case C226 => 226
+ case C227 => 227
+ case C228 => 228
+ case C229 => 229
+ case C230 => 230
+ case C231 => 231
+ case C232 => 232
+ case C233 => 233
+ case C234 => 234
+ case C235 => 235
+ case C236 => 236
+ case C237 => 237
+ case C238 => 238
+ case C239 => 239
+ case C240 => 240
+ case C241 => 241
+ case C242 => 242
+ case C243 => 243
+ case C244 => 244
+ case C245 => 245
+ case C246 => 246
+ case C247 => 247
+ case C248 => 248
+ case C249 => 249
+ case C250 => 250
+ case C251 => 251
+ case C252 => 252
+ case C253 => 253
+ case C254 => 254
+ case C255 => 255
+ case C256 => 256
+ case C257 => 257
+ case C258 => 258
+ case C259 => 259
+ case C260 => 260
+ case C261 => 261
+ case C262 => 262
+ case C263 => 263
+ case C264 => 264
+ case C265 => 265
+ case C266 => 266
+ case C267 => 267
+ case C268 => 268
+ case C269 => 269
+ case C270 => 270
+ case C271 => 271
+ case C272 => 272
+ case C273 => 273
+ case C274 => 274
+ case C275 => 275
+ case C276 => 276
+ case C277 => 277
+ case C278 => 278
+ case C279 => 279
+ case C280 => 280
+ case C281 => 281
+ case C282 => 282
+ case C283 => 283
+ case C284 => 284
+ case C285 => 285
+ case C286 => 286
+ case C287 => 287
+ case C288 => 288
+ case C289 => 289
+ case C290 => 290
+ case C291 => 291
+ case C292 => 292
+ case C293 => 293
+ case C294 => 294
+ case C295 => 295
+ case C296 => 296
+ case C297 => 297
+ case C298 => 298
+ case C299 => 299
+ case C300 => 300
+ case C301 => 301
+ case C302 => 302
+ case C303 => 303
+ case C304 => 304
+ case C305 => 305
+ case C306 => 306
+ case C307 => 307
+ case C308 => 308
+ case C309 => 309
+ case C310 => 310
+ case C311 => 311
+ case C312 => 312
+ case C313 => 313
+ case C314 => 314
+ case C315 => 315
+ case C316 => 316
+ case C317 => 317
+ case C318 => 318
+ case C319 => 319
+ case C320 => 320
+ case C321 => 321
+ case C322 => 322
+ case C323 => 323
+ case C324 => 324
+ case C325 => 325
+ case C326 => 326
+ case C327 => 327
+ case C328 => 328
+ case C329 => 329
+ case C330 => 330
+ case C331 => 331
+ case C332 => 332
+ case C333 => 333
+ case C334 => 334
+ case C335 => 335
+ case C336 => 336
+ case C337 => 337
+ case C338 => 338
+ case C339 => 339
+ case C340 => 340
+ case C341 => 341
+ case C342 => 342
+ case C343 => 343
+ case C344 => 344
+ case C345 => 345
+ case C346 => 346
+ case C347 => 347
+ case C348 => 348
+ case C349 => 349
+ case C350 => 350
+ case C351 => 351
+ case C352 => 352
+ case C353 => 353
+ case C354 => 354
+ case C355 => 355
+ case C356 => 356
+ case C357 => 357
+ case C358 => 358
+ case C359 => 359
+ case C360 => 360
+ case C361 => 361
+ case C362 => 362
+ case C363 => 363
+ case C364 => 364
+ case C365 => 365
+ case C366 => 366
+ case C367 => 367
+ case C368 => 368
+ case C369 => 369
+ case C370 => 370
+ case C371 => 371
+ case C372 => 372
+ case C373 => 373
+ case C374 => 374
+ case C375 => 375
+ case C376 => 376
+ case C377 => 377
+ case C378 => 378
+ case C379 => 379
+ case C380 => 380
+ case C381 => 381
+ case C382 => 382
+ case C383 => 383
+ case C384 => 384
+ case C385 => 385
+ case C386 => 386
+ case C387 => 387
+ case C388 => 388
+ case C389 => 389
+ case C390 => 390
+ case C391 => 391
+ case C392 => 392
+ case C393 => 393
+ case C394 => 394
+ case C395 => 395
+ case C396 => 396
+ case C397 => 397
+ case C398 => 398
+ case C399 => 399
+ case C400 => 400
+ }
+}
diff --git a/test/files/run/t7407.flags b/test/files/run/t7407.flags
index be4ef0798a..ffc65f4b81 100644
--- a/test/files/run/t7407.flags
+++ b/test/files/run/t7407.flags
@@ -1 +1 @@
--Ynooptimise -Yopt:l:none -Ybackend:GenBCode
+-Yopt:l:none -Ybackend:GenBCode
diff --git a/test/files/run/t7407b.flags b/test/files/run/t7407b.flags
index c8547a27dc..c30091d3de 100644
--- a/test/files/run/t7407b.flags
+++ b/test/files/run/t7407b.flags
@@ -1 +1 @@
--Ynooptimise -Ybackend:GenBCode
+-Ybackend:GenBCode
diff --git a/test/files/run/t8845.flags b/test/files/run/t8845.flags
index aada25f80d..c30091d3de 100644
--- a/test/files/run/t8845.flags
+++ b/test/files/run/t8845.flags
@@ -1 +1 @@
--Ybackend:GenBCode -Ynooptimize
+-Ybackend:GenBCode
diff --git a/test/files/run/t8925.flags b/test/files/run/t8925.flags
index be4ef0798a..ffc65f4b81 100644
--- a/test/files/run/t8925.flags
+++ b/test/files/run/t8925.flags
@@ -1 +1 @@
--Ynooptimise -Yopt:l:none -Ybackend:GenBCode
+-Yopt:l:none -Ybackend:GenBCode
diff --git a/test/files/run/t9252.check b/test/files/run/t9252.check
new file mode 100644
index 0000000000..b00d748f7f
--- /dev/null
+++ b/test/files/run/t9252.check
@@ -0,0 +1 @@
+class [Lscala.runtime.BoxedUnit;
diff --git a/test/files/run/t9252.scala b/test/files/run/t9252.scala
new file mode 100644
index 0000000000..da698948e1
--- /dev/null
+++ b/test/files/run/t9252.scala
@@ -0,0 +1,5 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ println(rootMirror.runtimeClass(typeOf[Array[Unit]]))
+} \ No newline at end of file
diff --git a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
index 5d5215d887..d0ffd06b01 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/CodeGenTools.scala
@@ -8,7 +8,6 @@ import scala.reflect.io.VirtualDirectory
import scala.tools.asm.Opcodes
import scala.tools.asm.tree.{ClassNode, MethodNode}
import scala.tools.cmd.CommandLineParser
-import scala.tools.nsc.backend.jvm.opt.LocalOpt
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.reporters.StoreReporter
import scala.tools.nsc.settings.MutableSettings
@@ -157,12 +156,6 @@ object CodeGenTools {
assertTrue(h.start == insVec(startIndex) && h.end == insVec(endIndex) && h.handler == insVec(handlerIndex))
}
- val localOpt = {
- val settings = new MutableSettings(msg => throw new IllegalArgumentException(msg))
- settings.processArguments(List("-Yopt:l:method"), processAll = true)
- new LocalOpt(settings)
- }
-
import scala.language.implicitConversions
implicit def aliveInstruction(ins: Instruction): (Instruction, Boolean) = (ins, true)
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
index 7b0504fec0..cb01f3d164 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyExceptionHandlersTest.scala
@@ -40,7 +40,7 @@ class EmptyExceptionHandlersTest extends ClearAfterClass {
Op(RETURN)
)
assertTrue(convertMethod(asmMethod).handlers.length == 1)
- localOpt.removeEmptyExceptionHandlers(asmMethod)
+ LocalOptImpls.removeEmptyExceptionHandlers(asmMethod)
assertTrue(convertMethod(asmMethod).handlers.isEmpty)
}
@@ -61,7 +61,7 @@ class EmptyExceptionHandlersTest extends ClearAfterClass {
Op(RETURN)
)
assertTrue(convertMethod(asmMethod).handlers.length == 1)
- localOpt.removeEmptyExceptionHandlers(asmMethod)
+ LocalOptImpls.removeEmptyExceptionHandlers(asmMethod)
assertTrue(convertMethod(asmMethod).handlers.isEmpty)
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
index 8c0168826e..7283e20745 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/EmptyLabelsAndLineNumbersTest.scala
@@ -42,14 +42,14 @@ class EmptyLabelsAndLineNumbersTest {
)
val method = genMethod()(ops.map(_._1): _*)
- assertTrue(localOpt.removeEmptyLineNumbers(method))
+ assertTrue(LocalOptImpls.removeEmptyLineNumbers(method))
assertSameCode(instructionsFromMethod(method), ops.filter(_._2).map(_._1))
}
@Test
def badlyLocatedLineNumbers(): Unit = {
def t(ops: Instruction*) =
- assertThrows[AssertionError](localOpt.removeEmptyLineNumbers(genMethod()(ops: _*)))
+ assertThrows[AssertionError](LocalOptImpls.removeEmptyLineNumbers(genMethod()(ops: _*)))
// line numbers have to be right after their referenced label node
t(LineNumber(0, Label(1)), Label(1))
@@ -88,7 +88,7 @@ class EmptyLabelsAndLineNumbersTest {
)
val method = genMethod(handlers = handler)(ops(2, 3, 8, 8, 9, 11).map(_._1): _*)
- assertTrue(localOpt.removeEmptyLabelNodes(method))
+ assertTrue(LocalOptImpls.removeEmptyLabelNodes(method))
val m = convertMethod(method)
assertSameCode(m.instructions, ops(1, 1, 7, 7, 7, 10).filter(_._2).map(_._1))
assertTrue(m.handlers match {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
index fedc074a15..029caa995c 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlineWarningTest.scala
@@ -143,4 +143,52 @@ class InlineWarningTest extends ClearAfterClass {
compileClasses(newCompiler(extraArgs = InlineWarningTest.argsNoWarn + " -Yopt-warnings:no-inline-mixed"))(scalaCode, List((javaCode, "A.java")), allowMessage = i => {c += 1; warns.exists(i.msg contains _)})
assert(c == 2, c)
}
+
+ @Test
+ def cannotInlinePrivateCallIntoDifferentClass(): Unit = {
+ val code =
+ """class M {
+ | @inline final def f = {
+ | @noinline def nested = 0
+ | nested
+ | }
+ |
+ | def t = f // ok
+ |}
+ |
+ |class N {
+ | def t(a: M) = a.f // not possible
+ |}
+ """.stripMargin
+
+ val warn =
+ """M::f()I is annotated @inline but could not be inlined:
+ |The callee M::f()I contains the instruction INVOKESPECIAL M.nested$1 ()I
+ |that would cause an IllegalAccessError when inlined into class N""".stripMargin
+
+ var c = 0
+ compile(code, allowMessage = i => { c += 1; i.msg contains warn })
+ assert(c == 1, c)
+ }
+
+ @Test
+ def cannotMixStrictfp(): Unit = {
+ val code =
+ """import annotation.strictfp
+ |class C {
+ | @strictfp @inline final def f = 0
+ | @strictfp def t1 = f
+ | def t2 = f
+ |}
+ """.stripMargin
+
+ val warn =
+ """C::f()I is annotated @inline but could not be inlined:
+ |The callsite method C::t2()I
+ |does not have the same strictfp mode as the callee C::f()I.""".stripMargin
+
+ var c = 0
+ compile(code, allowMessage = i => { c += 1; i.msg contains warn })
+ assert(c == 1, c)
+ }
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
index 39fb28570e..17724aecb1 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
@@ -152,7 +152,7 @@ class InlinerTest extends ClearAfterClass {
assertSameCode(convertMethod(g).instructions.dropNonOp.take(4), expectedInlined)
- localOpt.methodOptimizations(g, "C")
+ compiler.genBCode.bTypes.localOpt.methodOptimizations(g, "C")
assertSameCode(convertMethod(g).instructions.dropNonOp,
expectedInlined ++ List(VarOp(ASTORE, 2), VarOp(ALOAD, 2), Op(ATHROW)))
}
@@ -950,4 +950,29 @@ class InlinerTest extends ClearAfterClass {
assertInvoke(getSingleMethod(t, "t3"), "B", "<init>")
assertInvoke(getSingleMethod(t, "t4"), "B", "<init>")
}
+
+ @Test
+ def dontInlineNative(): Unit = {
+ val code =
+ """class C {
+ | def t = System.arraycopy(null, 0, null, 0, 0)
+ |}
+ """.stripMargin
+ val List(c) = compileClasses(newCompiler(extraArgs = InlinerTest.args + " -Yopt-inline-heuristics:everything"))(code)
+ assertInvoke(getSingleMethod(c, "t"), "java/lang/System", "arraycopy")
+ }
+
+ @Test
+ def inlineMayRenderCodeDead(): Unit = {
+ val code =
+ """class C {
+ | @inline final def f: String = throw new Error("")
+ | @inline final def g: String = "a" + f + "b" // after inlining f, need to run DCE, because the rest of g becomes dead.
+ | def t = g // the inliner requires no dead code when inlining g (uses an Analyzer).
+ |}
+ """.stripMargin
+
+ val List(c) = compile(code)
+ assertInvoke(getSingleMethod(c, "t"), "java/lang/Error", "<init>")
+ }
}
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 360fa1d23d..a685ae7dd5 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/SimplifyJumpsTest.scala
@@ -26,7 +26,7 @@ class SimplifyJumpsTest {
Op(RETURN)
)
val method = genMethod()(ops: _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), Op(RETURN) :: ops.tail)
}
@@ -45,7 +45,7 @@ class SimplifyJumpsTest {
Jump(GOTO, Label(2)) :: // replaced by ATHROW
rest: _*
)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), Op(ACONST_NULL) :: Op(ATHROW) :: rest)
}
@@ -66,11 +66,11 @@ class SimplifyJumpsTest {
Op(RETURN)
)
val method = genMethod(handlers = handler)(initialInstrs: _*)
- assertFalse(localOpt.simplifyJumps(method))
+ assertFalse(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), initialInstrs)
val optMethod = genMethod()(initialInstrs: _*) // no handler
- assertTrue(localOpt.simplifyJumps(optMethod))
+ assertTrue(LocalOptImpls.simplifyJumps(optMethod))
assertSameCode(instructionsFromMethod(optMethod).take(3), List(Label(1), Op(ACONST_NULL), Op(ATHROW)))
}
@@ -91,7 +91,7 @@ class SimplifyJumpsTest {
Op(IRETURN)
)
val method = genMethod()(begin ::: rest: _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(
instructionsFromMethod(method),
List(VarOp(ILOAD, 1), Jump(IFLT, Label(3))) ::: rest.tail )
@@ -99,7 +99,7 @@ class SimplifyJumpsTest {
// 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(localOpt.simplifyJumps(nonOptMethod))
+ assertFalse(LocalOptImpls.simplifyJumps(nonOptMethod))
}
@Test
@@ -116,7 +116,7 @@ class SimplifyJumpsTest {
// ensures that the goto is safely removed. ASM supports removing while iterating, but not the
// next element of the current. Here, the current is the IFGE, the next is the GOTO.
val method = genMethod()(code(Jump(IFGE, Label(2)), Jump(GOTO, Label(3))): _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), code(Jump(IFLT, Label(3))))
}
@@ -131,7 +131,7 @@ class SimplifyJumpsTest {
Op(IRETURN)
)
val method = genMethod()(ops: _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), ops.tail)
}
@@ -157,7 +157,7 @@ class SimplifyJumpsTest {
Op(IRETURN)
)
val method = genMethod()(ops(1, 2, 3): _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), ops(3, 3, 3))
}
@@ -181,7 +181,7 @@ class SimplifyJumpsTest {
)
val method = genMethod()(ops(2): _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), ops(3))
}
@@ -202,7 +202,7 @@ class SimplifyJumpsTest {
)
val method = genMethod()(ops(Jump(IFGE, Label(1))): _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), ops(Op(POP)))
}
@@ -215,7 +215,7 @@ class SimplifyJumpsTest {
Jump(GOTO, Label(1))
)
val method = genMethod()(ops(List(Jump(IF_ICMPGE, Label(1)))): _*)
- assertTrue(localOpt.simplifyJumps(method))
+ assertTrue(LocalOptImpls.simplifyJumps(method))
assertSameCode(instructionsFromMethod(method), ops(List(Op(POP), Op(POP))))
}
}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
index da9853148b..902af7b7fa 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/opt/UnreachableCodeTest.scala
@@ -44,7 +44,7 @@ class UnreachableCodeTest extends ClearAfterClass {
def assertEliminateDead(code: (Instruction, Boolean)*): Unit = {
val method = genMethod()(code.map(_._1): _*)
- localOpt.removeUnreachableCodeImpl(method, "C")
+ LocalOptImpls.removeUnreachableCodeImpl(method, "C")
val nonEliminated = instructionsFromMethod(method)
val expectedLive = code.filter(_._2).map(_._1).toList
assertSameCode(nonEliminated, expectedLive)
diff --git a/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala
index 1fff9c9a32..1fe7b19056 100644
--- a/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala
+++ b/test/junit/scala/tools/nsc/transform/patmat/SolvingTest.scala
@@ -6,6 +6,7 @@ import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import scala.collection.mutable
+import scala.reflect.internal.util.Position
import scala.tools.nsc.{Global, Settings}
object TestSolver extends Logic with Solving {
@@ -72,6 +73,8 @@ object TestSolver extends Logic with Solving {
def prepareNewAnalysis() = {}
+ def uncheckedWarning(pos: Position, msg: String) = sys.error(msg)
+
def reportWarning(msg: String) = sys.error(msg)
/**
diff --git a/test/scaladoc/run/t5795.check b/test/scaladoc/run/t5795.check
new file mode 100644
index 0000000000..d08ab619ed
--- /dev/null
+++ b/test/scaladoc/run/t5795.check
@@ -0,0 +1,4 @@
+newSource:16: warning: Could not find any member to link for "Exception".
+ /**
+ ^
+Done.
diff --git a/test/scaladoc/run/t5795.scala b/test/scaladoc/run/t5795.scala
new file mode 100644
index 0000000000..767e4f1a72
--- /dev/null
+++ b/test/scaladoc/run/t5795.scala
@@ -0,0 +1,63 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+
+ override def code = """
+/**
+ * Only the 'deprecated' tag should stay.
+ *
+ * @author
+ * @since
+ * @todo
+ * @note
+ * @see
+ * @version
+ * @deprecated
+ * @example
+ * @constructor
+ */
+object Test {
+ /**
+ * Only the 'throws' tag should stay.
+ * @param foo
+ * @param bar
+ * @param baz
+ * @return
+ * @throws Exception
+ * @tparam T
+ */
+ def foo[T](foo: Any, bar: Any, baz: Any): Int = 1
+}
+ """
+
+ def scaladocSettings = ""
+
+ def test(b: Boolean, text: => String): Unit = if (!b) println(text)
+
+ def testModel(root: Package) = {
+ import access._
+ val obj = root._object("Test")
+ val c = obj.comment.get
+
+ test(c.authors.isEmpty, s"expected no authors, found: ${c.authors}")
+ test(!c.since.isDefined, s"expected no since tag, found: ${c.since}")
+ test(c.todo.isEmpty, s"expected no todos, found: ${c.todo}")
+ test(c.note.isEmpty, s"expected no note, found: ${c.note}")
+ test(c.see.isEmpty, s"expected no see, found: ${c.see}")
+ test(!c.version.isDefined, s"expected no version tag, found: ${c.version}")
+ // deprecated stays
+ test(c.deprecated.isDefined, s"expected deprecated tag, found none")
+ test(c.example.isEmpty, s"expected no example, found: ${c.example}")
+ test(!c.constructor.isDefined, s"expected no constructor tag, found: ${c.constructor}")
+
+ val method = obj._method("foo")
+ val mc = method.comment.get
+
+ test(mc.valueParams.isEmpty, s"expected empty value params, found: ${mc.valueParams}")
+ test(mc.typeParams.isEmpty, s"expected empty type params, found: ${mc.typeParams}")
+ test(!mc.result.isDefined, s"expected no result tag, found: ${mc.result}")
+ // throws stay
+ test(!mc.throws.isEmpty, s"expected an exception tag, found: ${mc.throws}")
+ }
+}
diff --git a/test/scaladoc/scalacheck/CommentFactoryTest.scala b/test/scaladoc/scalacheck/CommentFactoryTest.scala
index ff64a25602..d30b78087c 100644
--- a/test/scaladoc/scalacheck/CommentFactoryTest.scala
+++ b/test/scaladoc/scalacheck/CommentFactoryTest.scala
@@ -24,8 +24,11 @@ class Factory(val g: Global, val s: doc.Settings)
}
}
+ def getComment(s: String): Comment =
+ parse(s, "", scala.tools.nsc.util.NoPosition, null)
+
def parseComment(s: String): Option[Inline] =
- strip(parse(s, "", scala.tools.nsc.util.NoPosition, null))
+ strip(getComment(s))
def createBody(s: String) =
parse(s, "", scala.tools.nsc.util.NoPosition, null).body
@@ -166,4 +169,19 @@ object Test extends Properties("CommentFactory") {
}
}
+ property("Empty parameter text should be empty") = {
+ // used to fail with
+ // body == Body(List(Paragraph(Chain(List(Summary(Text('\n')))))))
+ factory.getComment(
+ """
+/**
+ * @deprecated
+ */
+ """).deprecated match {
+ case Some(Body(l)) if l.isEmpty => true
+ case other =>
+ println(other)
+ false
+ }
+ }
}
diff --git a/test/scaladoc/scalacheck/HtmlFactoryTest.scala b/test/scaladoc/scalacheck/HtmlFactoryTest.scala
index 6b59355991..98a601bb20 100644
--- a/test/scaladoc/scalacheck/HtmlFactoryTest.scala
+++ b/test/scaladoc/scalacheck/HtmlFactoryTest.scala
@@ -685,7 +685,7 @@ object Test extends Properties("HtmlFactory") {
case node: scala.xml.Node => {
val s = node.toString
s.contains("<h6>Author:</h6>") &&
- s.contains("<p>The Only Author\n</p>")
+ s.contains("<p>The Only Author</p>")
}
case _ => false
}
@@ -699,7 +699,7 @@ object Test extends Properties("HtmlFactory") {
val s = node.toString
s.contains("<h6>Authors:</h6>") &&
s.contains("<p>The First Author</p>") &&
- s.contains("<p>The Second Author\n</p>")
+ s.contains("<p>The Second Author</p>")
}
case _ => false
}
diff --git a/versions.properties b/versions.properties
index 84e9078815..49e7b2730b 100644
--- a/versions.properties
+++ b/versions.properties
@@ -27,7 +27,7 @@ actors-migration.version.number=1.1.0
jline.version=2.12.1
# external modules, used internally (not shipped)
-partest.version.number=1.0.5
+partest.version.number=1.0.6
scalacheck.version.number=1.11.4
# TODO: modularize the compiler