diff options
137 files changed, 2115 insertions, 490 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 @@ -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' @@ -978,6 +978,7 @@ TODO: <pathelement location="${test.junit.classes}"/> <path refid="quick.compiler.build.path"/> <path refid="quick.repl.build.path"/> + <path refid="quick.scaladoc.build.path"/> <path refid="quick.partest-extras.build.path"/> <path refid="junit.classpath"/> </path> diff --git a/src/compiler/scala/reflect/quasiquotes/Holes.scala b/src/compiler/scala/reflect/quasiquotes/Holes.scala index 38b05f9d4b..6fa6b9b37a 100644 --- a/src/compiler/scala/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/reflect/quasiquotes/Holes.scala @@ -132,7 +132,7 @@ trait Holes { self: Quasiquotes => private def mapF(tree: Tree, f: Tree => Tree): Tree = if (f(Ident(TermName("x"))) equalsStructure Ident(TermName("x"))) tree else { - val x: TermName = c.freshName() + val x = TermName(c.freshName()) // q"$tree.map { $x => ${f(Ident(x))} }" Apply(Select(tree, nme.map), Function(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree) :: Nil, @@ -187,7 +187,7 @@ trait Holes { self: Quasiquotes => lazy val tree = tptopt.map { tpt => val TypeDef(_, _, _, typedTpt) = - try c.typeCheck(TypeDef(NoMods, TypeName("T"), Nil, tpt)) + try c.typecheck(TypeDef(NoMods, TypeName("T"), Nil, tpt)) catch { case TypecheckException(pos, msg) => c.abort(pos.asInstanceOf[c.Position], msg) } val tpe = typedTpt.tpe val (iterableRank, _) = stripIterable(tpe) diff --git a/src/compiler/scala/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/reflect/quasiquotes/Reifiers.scala index cc98717c4e..7c0e7dfbb8 100644 --- a/src/compiler/scala/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/reflect/quasiquotes/Reifiers.scala @@ -247,7 +247,7 @@ trait Reifiers { self: Quasiquotes => hole.tree case Placeholder(hole: UnapplyHole) => hole.treeNoUnlift case FreshName(prefix) if prefix != nme.QUASIQUOTE_NAME_PREFIX => - def fresh() = c.freshName[TermName](nme.QUASIQUOTE_NAME_PREFIX) + def fresh() = c.freshName(TermName(nme.QUASIQUOTE_NAME_PREFIX)) def introduceName() = { val n = fresh(); nameMap(name) += n; n} def result(n: Name) = if (isReifyingExpressions) Ident(n) else Bind(n, Ident(nme.WILDCARD)) if (isReifyingPatterns) result(introduceName()) diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 52ddcb154b..e41fbf042a 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -39,7 +39,7 @@ trait GenSymbols { else if (sym.isModuleClass) if (sym.sourceModule.isLocatable) Select(Select(reify(sym.sourceModule), nme.asModule), nme.moduleClass) else reifySymDef(sym) - else if (sym.isPackage) + else if (sym.hasPackageFlag) mirrorMirrorCall(nme.staticPackage, reify(sym.fullName)) else if (sym.isLocatable) { /* This is a fancy conundrum that stems from the fact that Scala allows diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 743fe131c4..f34d75140b 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -153,7 +153,7 @@ trait GenTrees { else mirrorCall(nme.Ident, reify(name)) case Select(qual, name) => - if (qual.symbol != null && qual.symbol.isPackage) { + if (qual.symbol != null && qual.symbol.hasPackageFlag) { mirrorBuildCall(nme.mkIdent, reify(sym)) } else { val effectiveName = if (sym != null && sym != NoSymbol) sym.name else name @@ -199,7 +199,7 @@ trait GenTrees { } } else tree match { - case Select(qual, name) if !qual.symbol.isPackage => + case Select(qual, name) if !qual.symbol.hasPackageFlag => if (reifyDebug) println(s"reifying Select($qual, $name)") mirrorCall(nme.Select, reify(qual), reify(name)) case SelectFromTypeTree(qual, name) => diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala index de9fec0df5..b5b0f93750 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala @@ -15,7 +15,7 @@ trait GenUtils { def reifyProduct(prefix: String, elements: List[Any]): Tree = { // reflection would be more robust, but, hey, this is a hot path if (prefix.startsWith("Tuple")) scalaFactoryCall(prefix, (elements map reify).toList: _*) - else mirrorCall(prefix, (elements map reify): _*) + else mirrorCall(TermName(prefix), (elements map reify): _*) } // helper functions @@ -49,16 +49,16 @@ trait GenUtils { call("" + nme.MIRROR_PREFIX + name, args: _*) def mirrorFactoryCall(value: Product, args: Tree*): Tree = - mirrorFactoryCall(value.productPrefix, args: _*) + mirrorFactoryCall(TermName(value.productPrefix), args: _*) def mirrorFactoryCall(prefix: TermName, args: Tree*): Tree = - mirrorCall("" + prefix, args: _*) + mirrorCall(TermName("" + prefix), args: _*) def scalaFactoryCall(name: TermName, args: Tree*): Tree = call(s"scala.$name.apply", args: _*) def scalaFactoryCall(name: String, args: Tree*): Tree = - scalaFactoryCall(name: TermName, args: _*) + scalaFactoryCall(TermName(name), args: _*) def mkList(args: List[Tree]): Tree = scalaFactoryCall("collection.immutable.List", args: _*) diff --git a/src/compiler/scala/tools/ant/FastScalac.scala b/src/compiler/scala/tools/ant/FastScalac.scala index c3eb9eef9c..6f0a30aa9d 100644 --- a/src/compiler/scala/tools/ant/FastScalac.scala +++ b/src/compiler/scala/tools/ant/FastScalac.scala @@ -15,7 +15,7 @@ import org.apache.tools.ant.types.Path import scala.tools.nsc.Settings import scala.tools.nsc.io.File import scala.tools.nsc.settings.FscSettings -import scala.tools.nsc.util.ScalaClassLoader +import scala.reflect.internal.util.ScalaClassLoader /** An Ant task to compile with the fast Scala compiler (`fsc`). * diff --git a/src/compiler/scala/tools/ant/sabbus/Compiler.scala b/src/compiler/scala/tools/ant/sabbus/Compiler.scala index 65cd9f41c2..81cd1f3196 100644 --- a/src/compiler/scala/tools/ant/sabbus/Compiler.scala +++ b/src/compiler/scala/tools/ant/sabbus/Compiler.scala @@ -12,7 +12,7 @@ package scala.tools.ant.sabbus import java.io.File import java.net.URL import java.lang.reflect.InvocationTargetException -import scala.tools.nsc.util.ScalaClassLoader +import scala.reflect.internal.util.ScalaClassLoader class Compiler(classpath: Array[URL], val settings: Settings) { diff --git a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala index 595b45ae51..cde827ba54 100644 --- a/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala +++ b/src/compiler/scala/tools/ant/sabbus/ScalacFork.scala @@ -16,7 +16,7 @@ import org.apache.tools.ant.taskdefs.Java import org.apache.tools.ant.util.{ GlobPatternMapper, SourceFileScanner } import org.apache.tools.ant.BuildException import scala.tools.nsc.io -import scala.tools.nsc.util.ScalaClassLoader +import scala.reflect.internal.util.ScalaClassLoader /** An Ant task to compile with the new Scala compiler (NSC). * diff --git a/src/compiler/scala/tools/nsc/EvalLoop.scala b/src/compiler/scala/tools/nsc/EvalLoop.scala index 15a296c836..73f4b9a119 100644 --- a/src/compiler/scala/tools/nsc/EvalLoop.scala +++ b/src/compiler/scala/tools/nsc/EvalLoop.scala @@ -6,6 +6,7 @@ package scala.tools.nsc import scala.annotation.tailrec +import scala.io.StdIn import java.io.EOFException trait EvalLoop { @@ -14,7 +15,7 @@ trait EvalLoop { def loop(action: (String) => Unit) { @tailrec def inner() { Console.print(prompt) - val line = try Console.readLine() catch { case _: EOFException => null } + val line = try StdIn.readLine() catch { case _: EOFException => null } if (line != null && line != "") { action(line) inner() diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala index dbdeec809f..2584054686 100644 --- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala +++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala @@ -6,6 +6,7 @@ package scala.tools.nsc import GenericRunnerCommand._ +import scala.reflect.internal.util.ScalaClassLoader /** A command for ScriptRunner */ class GenericRunnerCommand( @@ -32,7 +33,7 @@ extends CompilerCommand(args, settings) { private def guessHowToRun(target: String): GenericRunnerCommand.HowToRun = { if (!ok) Error else if (io.Jar.isJarOrZip(target)) AsJar - else if (util.ScalaClassLoader.classExists(settings.classpathURLs, target)) AsObject + else if (ScalaClassLoader.classExists(settings.classpathURLs, target)) AsObject else { val f = io.File(target) if (!f.hasExtension("class", "jar", "zip") && f.canRead) AsScript diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 7c14f4943f..8e01418e8b 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -7,8 +7,8 @@ package scala.tools.nsc import java.net.URL -import util.ScalaClassLoader import util.Exceptional.unwrap +import scala.reflect.internal.util.ScalaClassLoader trait CommonRunner { /** Run a given object, specified by name, using a 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/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 9c8e13a1a9..6fe85cde7a 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -9,6 +9,7 @@ package ast import scala.compat.Platform.EOL import symtab.Flags._ import scala.language.postfixOps +import scala.reflect.internal.util.ListOfNil /** The object `nodePrinter` converts the internal tree * representation to a string. diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 3a502bdb7a..934257092f 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -308,7 +308,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // Erasing locally-defined symbols is useful to prevent tree corruption, but erasing external bindings is not, // therefore we want to retain those bindings, especially given that restoring them can be impossible // if we move these trees into lexical contexts different from their original locations. - if (dupl.hasSymbol) { + if (dupl.hasSymbolField) { val sym = dupl.symbol val vetoScope = !brutally && !(locals contains sym) && !(locals contains sym.deSkolemize) val vetoThis = dupl.isInstanceOf[This] && sym.isPackageClass diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 4663810003..67e91ae857 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -13,7 +13,7 @@ import scala.collection.{ mutable, immutable } import mutable.{ ListBuffer, StringBuilder } import scala.reflect.internal.{ Precedence, ModifierFlags => Flags } import scala.reflect.internal.Chars.{ isScalaLetter } -import scala.reflect.internal.util.{ SourceFile, Position, FreshNameCreator } +import scala.reflect.internal.util.{ SourceFile, Position, FreshNameCreator, ListOfNil } import Tokens._ /** Historical note: JavaParsers started life as a direct copy of Parsers @@ -2788,7 +2788,7 @@ self => */ def packageObjectDef(start: Offset): PackageDef = { val defn = objectDef(in.offset, NoMods) - val pidPos = o2p(defn.pos.startOrPoint) + val pidPos = o2p(defn.pos.start) val pkgPos = r2p(start, pidPos.point) gen.mkPackageObject(defn, pidPos, pkgPos) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 8cd915bf22..d2a999cdec 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -8,6 +8,7 @@ package ast.parser import scala.collection.{ mutable, immutable } import symtab.Flags.MUTABLE +import scala.reflect.internal.util.ListOfNil import scala.reflect.internal.util.StringOps.splitWhere /** This class builds instance of `Tree` that represent XML. diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index cf52ad6636..137954b52d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -876,13 +876,20 @@ abstract class GenICode extends SubComponent { genLoadModule(ctx, tree) generatedType = toTypeKind(sym.info) } else { - try { - val Some(l) = ctx.method.lookupLocal(sym) - ctx.bb.emit(LOAD_LOCAL(l), tree.pos) - generatedType = l.kind - } catch { - case ex: MatchError => - abort("symbol " + sym + " does not exist in " + ctx.method) + ctx.method.lookupLocal(sym) match { + case Some(l) => + ctx.bb.emit(LOAD_LOCAL(l), tree.pos) + generatedType = l.kind + case None => + val saved = settings.uniqid + settings.uniqid.value = true + 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/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 3b7dbc18da..18468f5ae3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -780,8 +780,8 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { var fieldList = List[String]() for (f <- fieldSymbols if f.hasGetter; - g = f.getter(cls); - s = f.setter(cls); + g = f.getterIn(cls); + s = f.setterIn(cls); if g.isPublic && !(f.name startsWith "$") ) { // inserting $outer breaks the bean 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/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 86a69b92ea..f866c0d038 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -689,7 +689,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => null else { val outerName = javaName(innerSym.rawowner) - if (isTopLevelModule(innerSym.rawowner)) "" + nme.stripModuleSuffix(newTermName(outerName)) + if (isTopLevelModule(innerSym.rawowner)) "" + TermName(outerName).dropModule else outerName } } @@ -2054,7 +2054,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => seen ::= LocVarEntry(lv, start, end) case _ => // TODO SI-6049 track down the cause for these. - debugwarn(s"$iPos: Visited SCOPE_EXIT before visiting corresponding SCOPE_ENTER. SI-6191") + devWarning(s"$iPos: Visited SCOPE_EXIT before visiting corresponding SCOPE_ENTER. SI-6191") } } @@ -2424,7 +2424,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH. // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range" else if (newNormal.isJumpOnly(b) && m.exh.exists(eh => eh.covers(b))) { - debugwarn("Had a jump only block that wasn't collapsed") + devWarning("Had a jump only block that wasn't collapsed") emit(asm.Opcodes.NOP) } @@ -2883,8 +2883,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => var fieldList = List[String]() for (f <- clasz.fields if f.symbol.hasGetter; - g = f.symbol.getter(clasz.symbol); - s = f.symbol.setter(clasz.symbol) + g = f.symbol.getterIn(clasz.symbol); + s = f.symbol.setterIn(clasz.symbol) if g.isPublic && !(f.symbol.name startsWith "$") ) { // inserting $outer breaks the bean @@ -3136,13 +3136,13 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => val (remappings, cycles) = detour partition {case (source, target) => source != target} for ((source, target) <- remappings) { debuglog(s"Will elide jump only block $source because it can be jumped around to get to $target.") - if (m.startBlock == source) debugwarn("startBlock should have been re-wired by now") + if (m.startBlock == source) devWarning("startBlock should have been re-wired by now") } val sources = remappings.keySet val targets = remappings.values.toSet val intersection = sources intersect targets - if (intersection.nonEmpty) debugwarn(s"contradiction: we seem to have some source and target overlap in blocks ${intersection.mkString}. Map was ${detour.mkString}") + if (intersection.nonEmpty) devWarning(s"contradiction: we seem to have some source and target overlap in blocks ${intersection.mkString}. Map was ${detour.mkString}") for ((source, _) <- cycles) { debuglog(s"Block $source is in a do-nothing infinite loop. Did the user write 'while(true){}'?") 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/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 9433ddcf31..d34c14be0f 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -13,6 +13,7 @@ import symtab.Flags import JavaTokens._ import scala.language.implicitConversions import scala.reflect.internal.util.Position +import scala.reflect.internal.util.ListOfNil trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val global : Global @@ -125,7 +126,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def makeSyntheticParam(count: Int, tpt: Tree): ValDef = makeParam(nme.syntheticParamName(count), tpt) def makeParam(name: String, tpt: Tree): ValDef = - makeParam(name: TermName, tpt) + makeParam(TermName(name), tpt) def makeParam(name: TermName, tpt: Tree): ValDef = ValDef(Modifiers(Flags.JAVA | Flags.PARAM), name, tpt, EmptyTree) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 7837f9a11a..1a5529140c 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package plugins import scala.tools.nsc.io.{ Jar } -import scala.tools.nsc.util.ScalaClassLoader +import scala.reflect.internal.util.ScalaClassLoader import scala.reflect.io.{ Directory, File, Path } import java.io.InputStream import java.util.zip.ZipException @@ -60,6 +60,8 @@ abstract class Plugin { * @return true to continue, or false to opt out */ def init(options: List[String], error: String => Unit): Boolean = { + // call to deprecated method required here, we must continue to support + // code that subclasses that override `processOptions`. processOptions(options, error) true } 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/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 4d08be3c24..994bcd8359 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -15,6 +15,7 @@ import scala.collection.mutable.{ ListBuffer, ArrayBuffer } import scala.annotation.switch import scala.reflect.internal.{ JavaAccFlags } import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs} +import scala.reflect.io.NoAbstractFile import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.ClassFileLookup @@ -807,10 +808,10 @@ abstract class ClassfileParser { val c = pool.getConstant(u2) val c1 = convertTo(c, symtype) if (c1 ne null) sym.setInfo(ConstantType(c1)) - else debugwarn(s"failure to convert $c to $symtype") + else devWarning(s"failure to convert $c to $symtype") case tpnme.ScalaSignatureATTR => if (!isScalaAnnot) { - debugwarn(s"symbol ${sym.fullName} has pickled signature in attribute") + devWarning(s"symbol ${sym.fullName} has pickled signature in attribute") unpickler.unpickle(in.buf, in.bp, clazz, staticModule, in.file.name) } in.skip(attrLen) @@ -1022,11 +1023,18 @@ abstract class ClassfileParser { val sflags = jflags.toScalaFlags val owner = ownerForFlags(jflags) val scope = getScope(jflags) - val innerClass = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer - val innerModule = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer + def newStub(name: Name) = + owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found").setFlag(JAVA) - innerModule.moduleClass setInfo loaders.moduleClassLoader - List(innerClass, innerModule.moduleClass) foreach (_.associatedFile = file) + val (innerClass, innerModule) = if (file == NoAbstractFile) { + (newStub(name.toTypeName), newStub(name.toTermName)) + } else { + val cls = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer + val mod = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer + mod.moduleClass setInfo loaders.moduleClassLoader + List(cls, mod.moduleClass) foreach (_.associatedFile = file) + (cls, mod) + } scope enter innerClass scope enter innerModule @@ -1046,10 +1054,8 @@ abstract class ClassfileParser { for (entry <- innerClasses.entries) { // create a new class member for immediate inner classes if (entry.outerName == currentClass) { - val file = classFileLookup.findClassFile(entry.externalName.toString) getOrElse { - throw new AssertionError(s"Class file for ${entry.externalName} not found") - } - enterClassAndModule(entry, file) + val file = classFileLookup.findClassFile(entry.externalName.toString) + enterClassAndModule(entry, file.getOrElse(NoAbstractFile)) } } } @@ -1103,7 +1109,7 @@ abstract class ClassfileParser { def enclosing = if (jflags.isStatic) enclModule else enclClass // The name of the outer class, without its trailing $ if it has one. - private def strippedOuter = nme stripModuleSuffix outerName + private def strippedOuter = outerName.dropModule private def isInner = innerClasses contains strippedOuter private def enclClass = if (isInner) innerClasses innerSymbol strippedOuter else classNameToSymbol(strippedOuter) private def enclModule = enclClass.companionModule @@ -1123,7 +1129,7 @@ abstract class ClassfileParser { def add(entry: InnerClassEntry): Unit = { inners get entry.externalName foreach (existing => - debugwarn(s"Overwriting inner class entry! Was $existing, now $entry") + devWarning(s"Overwriting inner class entry! Was $existing, now $entry") ) inners(entry.externalName) = entry } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index bd1fa4e707..ea46116976 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -74,7 +74,7 @@ abstract class ICodeReader extends ClassfileParser { first != CONSTANT_METHODREF && first != CONSTANT_INTFMETHODREF) errorBadTag(start) val ownerTpe = getClassOrArrayType(in.getChar(start + 1).toInt) - debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.originalName) + debuglog("getMemberSymbol(static: " + static + "): owner type: " + ownerTpe + " " + ownerTpe.typeSymbol.unexpandedName) val (name0, tpe0) = getNameAndType(in.getChar(start + 3).toInt, ownerTpe) debuglog("getMemberSymbol: name and tpe: " + name0 + ": " + tpe0) diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 3591372bbe..79776485de 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -207,7 +207,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => } def transformMixinInfo(tp: Type): Type = tp match { - case ClassInfoType(parents, decls, clazz) => + case ClassInfoType(parents, decls, clazz) if clazz.isPackageClass || !clazz.isJavaDefined => if (clazz.needsImplClass) implClass(clazz setFlag lateINTERFACE) // generate an impl class diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 362cbde04f..d0fca12e6a 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -8,6 +8,7 @@ package transform import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer +import scala.reflect.internal.util.ListOfNil import symtab.Flags._ /** This phase converts classes with parameters into Java-like classes with diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 438d39bc86..9fdc3a9d72 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -1038,7 +1038,7 @@ abstract class Erasure extends AddInterfaces // See SI-5568. tree setSymbol Object_getClass } else { - debugwarn(s"The symbol '${fn.symbol}' was interecepted but didn't match any cases, that means the intercepted methods set doesn't match the code") + devWarning(s"The symbol '${fn.symbol}' was interecepted but didn't match any cases, that means the intercepted methods set doesn't match the code") tree } } else qual match { diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 6225b486c2..540de2cfe1 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -207,7 +207,7 @@ abstract class ExplicitOuter extends InfoTransform // class needs to have a common naming scheme, independently of whether // the field was accessed from an inner class or not. See #2946 if (sym.owner.isTrait && sym.isLocalToThis && - (sym.getter(sym.owner.toInterface) == NoSymbol)) + (sym.getterIn(sym.owner.toInterface) == NoSymbol)) sym.makeNotPrivate(sym.owner) tp } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 7927875583..408f4466e1 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -232,13 +232,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { for (member <- impl.info.decls) { if (!member.isMethod && !member.isModule && !member.isModuleVar) { assert(member.isTerm && !member.isDeferred, member) - if (member.getter(impl).isPrivate) { + if (member.getterIn(impl).isPrivate) { member.makeNotPrivate(clazz) // this will also make getter&setter not private } - val getter = member.getter(clazz) + val getter = member.getterIn(clazz) if (getter == NoSymbol) addMember(clazz, newGetter(member)) if (!member.tpe.isInstanceOf[ConstantType] && !member.isLazy) { - val setter = member.setter(clazz) + val setter = member.setterIn(clazz) if (setter == NoSymbol) addMember(clazz, newSetter(member)) } } @@ -267,7 +267,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { /* Mix in members of implementation class mixinClass into class clazz */ def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) { - if (!mixinClass.isImplClass) debugwarn ("Impl class flag is not set " + + if (!mixinClass.isImplClass) devWarning ("Impl class flag is not set " + ((mixinClass.debugLocationString, mixinInterface.debugLocationString))) for (member <- mixinClass.info.decls ; if isForwarded(member)) { @@ -872,7 +872,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { } def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = { - val sym = fieldSym.getter(fieldSym.owner) + val sym = fieldSym.getterIn(fieldSym.owner) val bitmapSym = bitmapFor(clazz, offset, sym) val kind = bitmapKind(sym) val mask = maskForOffset(offset, sym, kind) @@ -921,7 +921,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { deriveDefDef(stat)(addInitBits(clazz, _)) } else if (settings.checkInit && !clazz.isTrait && sym.isSetter) { - val getter = sym.getter(clazz) + val getter = sym.getterIn(clazz) if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter)) deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))), UNIT)) else stat @@ -1057,7 +1057,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def isOverriddenSetter(sym: Symbol) = nme.isTraitSetterName(sym.name) && { val other = sym.nextOverriddenSymbol - isOverriddenAccessor(other.getter(other.owner), clazz.info.baseClasses) + isOverriddenAccessor(other.getterIn(other.owner), clazz.info.baseClasses) } // for all symbols `sym` in the class definition, which are mixed in: @@ -1232,7 +1232,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // refer to fields in some implementation class via an abstract // getter in the interface. val iface = toInterface(sym.owner.tpe).typeSymbol - val ifaceGetter = sym getter iface + val ifaceGetter = sym getterIn iface if (ifaceGetter == NoSymbol) abort("No getter for " + sym + " in " + iface) else typedPos(tree.pos)((qual DOT ifaceGetter)()) @@ -1240,7 +1240,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { case Assign(Apply(lhs @ Select(qual, _), List()), rhs) => // assign to fields in some implementation class via an abstract // setter in the interface. - def setter = lhs.symbol.setter(toInterface(lhs.symbol.owner.tpe).typeSymbol) setPos lhs.pos + def setter = lhs.symbol.setterIn(toInterface(lhs.symbol.owner.tpe).typeSymbol) setPos lhs.pos typedPos(tree.pos)((qual DOT setter)(rhs)) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 1691b01e3e..086512677e 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -699,7 +699,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else if (m.isValue && !m.isMethod && !m.hasFlag(LAZY)) { // concrete value definition def mkAccessor(field: Symbol, name: Name) = { - val newFlags = (SPECIALIZED | m.getter(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR) + val newFlags = (SPECIALIZED | m.getterIn(clazz).flags) & ~(LOCAL | CASEACCESSOR | PARAMACCESSOR) // we rely on the super class to initialize param accessors val sym = sClass.newMethod(name.toTermName, field.pos, newFlags) info(sym) = SpecializedAccessor(field) @@ -720,7 +720,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (nme.isLocalName(m.name)) { val specGetter = mkAccessor(specVal, specVal.getterName) setInfo MethodType(Nil, specVal.info) - val origGetter = overrideIn(sClass, m.getter(clazz)) + val origGetter = overrideIn(sClass, m.getterIn(clazz)) info(origGetter) = Forward(specGetter) enterMember(specGetter) enterMember(origGetter) @@ -733,12 +733,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { debuglog("override case field accessor %s -> %s".format(m.name.decode, cfaGetter.name.decode)) } - if (specVal.isVariable && m.setter(clazz) != NoSymbol) { + if (specVal.isVariable && m.setterIn(clazz) != NoSymbol) { val specSetter = mkAccessor(specVal, specGetter.setterName) .resetFlag(STABLE) specSetter.setInfo(MethodType(specSetter.newSyntheticValueParams(List(specVal.info)), UnitTpe)) - val origSetter = overrideIn(sClass, m.setter(clazz)) + val origSetter = overrideIn(sClass, m.setterIn(clazz)) info(origSetter) = Forward(specSetter) enterMember(specSetter) enterMember(origSetter) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index e1cf53059a..3330fbcae2 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -10,6 +10,7 @@ package transform import symtab.Flags._ import scala.collection.{ mutable, immutable } import scala.language.postfixOps +import scala.reflect.internal.util.ListOfNil /*<export> */ /** - uncurry all symbol and tree types (@see UnCurryPhase) -- this includes normalizing all proper types. @@ -206,7 +207,7 @@ abstract class UnCurry extends InfoTransform // (() => Int) { def apply(): Int @typeConstraint } case RefinedType(List(funTp), decls) => debuglog(s"eliminate refinement from function type ${fun.tpe}") - fun.tpe = funTp + fun.setType(funTp) case _ => () } 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/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index b703b5bc6d..e1fe220556 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -577,8 +577,6 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { lengthMax3(casesNoSubstOnly) > 2 } val requireSwitch = hasSwitchAnnotation && exceedsTwoCasesOrAlts - if (hasSwitchAnnotation && !requireSwitch) - reporter.warning(scrut.pos, "matches with two cases or fewer are emitted using if-then-else instead of switch") (suppression, requireSwitch) case _ => (Suppression.NoSuppression, false) 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/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index d3cd26f256..5ecca5abce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -276,7 +276,7 @@ trait Implicits { /** An extractor for types of the form ? { name: (? >: argtpe <: Any*)restp } */ object HasMethodMatching { - val dummyMethod = NoSymbol.newTermSymbol("typer$dummy") setInfo NullaryMethodType(AnyTpe) + val dummyMethod = NoSymbol.newTermSymbol(TermName("typer$dummy")) setInfo NullaryMethodType(AnyTpe) def templateArgType(argtpe: Type) = new BoundedWildcardType(TypeBounds.lower(argtpe)) @@ -893,7 +893,7 @@ trait Implicits { try improves(firstPending, alt) catch { case e: CyclicReference => - debugwarn(s"Discarding $firstPending during implicit search due to cyclic reference.") + devWarning(s"Discarding $firstPending during implicit search due to cyclic reference.") true } ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index cf97474d9a..27e17fc65f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -553,9 +553,8 @@ trait Infer extends Checkable { // ...or lower bound of a type param, since they're asking for it. def canWarnAboutAny = { val loBounds = tparams map (_.info.bounds.lo) - val hasAny = pt :: restpe :: formals ::: argtpes ::: loBounds exists (t => - (t contains AnyClass) || (t contains AnyValClass) - ) + def containsAny(t: Type) = (t contains AnyClass) || (t contains AnyValClass) + val hasAny = pt :: restpe :: formals ::: argtpes ::: loBounds exists (_.dealiasWidenChain exists containsAny) !hasAny } def argumentPosition(idx: Int): Position = context.tree match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index da7b8b09aa..10aefae20b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -3,13 +3,14 @@ package typechecker import java.lang.Math.min import symtab.Flags._ -import scala.tools.nsc.util._ +import scala.reflect.internal.util.ScalaClassLoader import scala.reflect.runtime.ReflectionUtils import scala.collection.mutable.ListBuffer import scala.reflect.ClassTag import scala.reflect.internal.util.Statistics import scala.reflect.macros.util._ import scala.util.control.ControlThrowable +import scala.reflect.internal.util.ListOfNil import scala.reflect.macros.runtime.{AbortMacroException, MacroRuntimes} import scala.reflect.runtime.{universe => ru} import scala.reflect.macros.compiler.DefaultMacroCompiler diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 0aa62d771e..f90e32ce8a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -8,6 +8,7 @@ package typechecker import symtab.Flags._ import scala.reflect.internal.util.StringOps.{ ojoin } import scala.reflect.ClassTag +import scala.reflect.internal.util.ListOfNil import scala.reflect.runtime.{ universe => ru } import scala.language.higherKinds @@ -384,7 +385,7 @@ trait MethodSynthesis { } } case class Getter(tree: ValDef) extends BaseGetter(tree) { - override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getter(enclClass) + override def derivedSym = if (mods.isDeferred) basisSym else basisSym.getterIn(enclClass) private def derivedRhs = if (mods.isDeferred) EmptyTree else fieldSelection private def derivedTpt = { // For existentials, don't specify a type for the getter, even one derived @@ -451,7 +452,7 @@ trait MethodSynthesis { def flagsMask = SetterFlags def flagsExtra = ACCESSOR - override def derivedSym = basisSym.setter(enclClass) + override def derivedSym = basisSym.setterIn(enclClass) } case class Field(tree: ValDef) extends DerivedFromValDef { def name = tree.localName diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 711cfba24d..24238b8e41 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -10,6 +10,7 @@ import scala.collection.mutable import scala.annotation.tailrec import symtab.Flags._ import scala.language.postfixOps +import scala.reflect.internal.util.ListOfNil /** This trait declares methods to create symbols and to enter them into scopes. * @@ -464,7 +465,7 @@ trait Namers extends MethodSynthesis { def enterModuleSymbol(tree : ModuleDef): Symbol = { var m: Symbol = context.scope lookupModule tree.name val moduleFlags = tree.mods.flags | MODULE - if (m.isModule && !m.isPackage && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) { + if (m.isModule && !m.hasPackageFlag && inCurrentScope(m) && (currentRun.canRedefine(m) || m.isSynthetic)) { // This code accounts for the way the package objects found in the classpath are opened up // early by the completer of the package itself. If the `packageobjects` phase then finds // the same package object in sources, we have to clean the slate and remove package object @@ -487,7 +488,7 @@ trait Namers extends MethodSynthesis { m.moduleClass setFlag moduleClassFlags(moduleFlags) setPrivateWithin(tree, m.moduleClass) } - if (m.isTopLevel && !m.isPackage) { + if (m.isTopLevel && !m.hasPackageFlag) { m.moduleClass.associatedFile = contextFile currentRun.symSource(m) = m.moduleClass.sourceFile registerTopLevelSym(m) @@ -844,7 +845,7 @@ trait Namers extends MethodSynthesis { private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type = { val getter = if (sym.isValue && sym.owner.isClass && sym.isPrivate) - sym.getter(sym.owner) + sym.getterIn(sym.owner) else sym def isHidden(tp: Type): Boolean = tp match { case SingleType(pre, sym) => @@ -1305,7 +1306,7 @@ trait Namers extends MethodSynthesis { // by martin: the null case can happen in IDE; this is really an ugly hack on top of an ugly hack but it seems to work case Some(cda) => if (cda.companionModuleClassNamer == null) { - debugwarn(s"SI-6576 The companion module namer for $meth was unexpectedly null") + devWarning(s"SI-6576 The companion module namer for $meth was unexpectedly null") return } val p = (cda.classWithDefault, cda.companionModuleClassNamer) diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index fa4a764f1b..8a66c7d274 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -268,7 +268,7 @@ trait PatternTypers { def freshArgType(tp: Type): Type = tp match { case MethodType(param :: _, _) => param.tpe - case PolyType(tparams, restpe) => createFromClonedSymbols(tparams, freshArgType(restpe))(polyType) + case PolyType(tparams, restpe) => createFromClonedSymbols(tparams, freshArgType(restpe))(genPolyType) case OverloadedType(_, _) => OverloadedUnapplyError(fun) ; ErrorType case _ => UnapplyWithSingleArgError(fun) ; ErrorType } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d2931ff9e1..5abfbe850f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -718,7 +718,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // Check the remainder for invalid absoverride. for (member <- rest ; if (member.isAbstractOverride && member.isIncompleteIn(clazz))) { - val other = member.superSymbol(clazz) + val other = member.superSymbolIn(clazz) val explanation = if (other != NoSymbol) " and overrides incomplete superclass member " + infoString(other) else ", but no concrete implementation could be found in a base class" @@ -1684,9 +1684,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case _ => } if (skipBounds) { - tree.tpe = tree.tpe.map { + tree.setType(tree.tpe.map { _.filterAnnotations(_.symbol != UncheckedBoundsClass) - } + }) } tree 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/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index d2046a158c..966e8f1abe 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -344,7 +344,7 @@ trait SyntheticMethods extends ast.TreeDSL { // Without a means to suppress this warning, I've thought better of it. if (settings.warnValueOverrides) { (clazz.info nonPrivateMember m.name) filter (m => (m.owner != AnyClass) && (m.owner != clazz) && !m.isDeferred) andAlso { m => - currentUnit.warning(clazz.pos, s"Implementation of ${m.name} inherited from ${m.owner} overridden in $clazz to enforce value class semantics") + typer.context.warning(clazz.pos, s"Implementation of ${m.name} inherited from ${m.owner} overridden in $clazz to enforce value class semantics") } } true diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index 02356580cc..a7d48ceb89 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -300,8 +300,8 @@ abstract class TreeCheckers extends Analyzer { checkSym(tree) /* XXX: lots of syms show up here with accessed == NoSymbol. */ if (accessed != NoSymbol) { - val agetter = accessed.getter(sym.owner) - val asetter = accessed.setter(sym.owner) + val agetter = accessed.getterIn(sym.owner) + val asetter = accessed.setterIn(sym.owner) assertFn(agetter == sym || asetter == sym, sym + " is getter or setter, but accessed sym " + accessed + " shows " + agetter + " and " + asetter @@ -311,7 +311,7 @@ abstract class TreeCheckers extends Analyzer { } case ValDef(_, _, _, _) => if (sym.hasGetter && !sym.isOuterField && !sym.isOuterAccessor) { - assertFn(sym.getter(sym.owner) != NoSymbol, ownerstr(sym) + " has getter but cannot be found. " + sym.ownerChain) + assertFn(sym.getterIn(sym.owner) != NoSymbol, ownerstr(sym) + " has getter but cannot be found. " + sym.ownerChain) } case Apply(fn, args) => if (args exists (_ == EmptyTree)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 0f90c6a478..059981aa37 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -141,8 +141,8 @@ trait TypeDiagnostics { if (!member.hasAccessorFlag) member else if (!member.isDeferred) member.accessed else { - val getter = if (member.isSetter) member.getter(member.owner) else member - val flags = if (getter.setter(member.owner) != NoSymbol) DEFERRED.toLong | MUTABLE else DEFERRED + val getter = if (member.isSetter) member.getterIn(member.owner) else member + val flags = if (getter.setterIn(member.owner) != NoSymbol) DEFERRED.toLong | MUTABLE else DEFERRED getter.owner.newValue(getter.name.toTermName, getter.pos, flags) setInfo getter.tpe.resultType } @@ -439,7 +439,7 @@ trait TypeDiagnostics { context.warning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString)) object checkUnused { - val ignoreNames = Set[TermName]("readResolve", "readObject", "writeObject", "writeReplace") + val ignoreNames: Set[TermName] = Set(TermName("readResolve"), TermName("readObject"), TermName("writeObject"), TermName("writeReplace")) class UnusedPrivates extends Traverser { val defnTrees = ListBuffer[MemberDef]() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d01e4f84ba..391ef9e337 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -14,7 +14,7 @@ package tools.nsc package typechecker import scala.collection.{mutable, immutable} -import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance } +import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance, ListOfNil } import mutable.ListBuffer import symtab.Flags._ import Mode._ @@ -245,7 +245,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case TypeRef(_, sym, _) if sym.isAliasType => val tp0 = tp.dealias if (tp eq tp0) { - debugwarn(s"dropExistential did not progress dealiasing $tp, see SI-7126") + devWarning(s"dropExistential did not progress dealiasing $tp, see SI-7126") tp } else { val tp1 = dropExistential(tp0) @@ -2044,7 +2044,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (mexists(vparamss)(_.symbol == superArg.symbol)) { val alias = ( superAcc.initialize.alias - orElse (superAcc getter superAcc.owner) + orElse (superAcc getterIn superAcc.owner) filter (alias => superClazz.info.nonPrivateMember(alias.name) == alias) ) if (alias.exists && !alias.accessed.isVariable && !isRepeatedParamType(alias.accessed.info)) { @@ -2565,7 +2565,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val default = methodSym newValueParameter (newTermName("default"), tree.pos.focus, SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe) val paramSyms = List(x, default) - methodSym setInfo polyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) + methodSym setInfo genPolyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) if (!paramSynthetic) methodBodyTyper.context.scope enter x @@ -2865,7 +2865,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ClassDef(Modifiers(FINAL), tpnme.ANON_FUN_NAME, tparams = Nil, gen.mkTemplate( parents = TypeTree(samClassTpFullyDefined) :: serializableParentAddendum, - self = emptyValDef, + self = noSelfType, constrMods = NoMods, vparamss = ListOfNil, body = List(samDef), @@ -2934,7 +2934,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper var issuedMissingParameterTypeError = false foreach2(fun.vparams, argpts) { (vparam, argpt) => if (vparam.tpt.isEmpty) { - vparam.tpt.tpe = + val vparamType = if (isFullyDefined(argpt)) argpt else { fun match { @@ -2953,6 +2953,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper issuedMissingParameterTypeError = true ErrorType } + vparam.tpt.setType(vparamType) if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus } } @@ -3387,7 +3388,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // defaults are needed. they are added to the argument list in named style as // calls to the default getters. Example: // foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a)) - checkNotMacro() // SI-8111 transformNamedApplication eagerly shuffles around the application to preserve // evaluation order. During this process, it calls `changeOwner` on symbols that @@ -3434,6 +3434,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper duplErrTree } else if (lencmp2 == 0) { // useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]() + checkNotMacro() context.diagUsedDefaults = true doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt) } else { @@ -4365,7 +4366,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def narrowRhs(tp: Type) = { val sym = context.tree.symbol context.tree match { case ValDef(mods, _, _, Apply(Select(`tree`, _), _)) if !mods.isMutable && sym != null && sym != NoSymbol => - val sym1 = if (sym.owner.isClass && sym.getter(sym.owner) != NoSymbol) sym.getter(sym.owner) + val sym1 = if (sym.owner.isClass && sym.getterIn(sym.owner) != NoSymbol) sym.getterIn(sym.owner) else sym.lazyAccessorOrSelf val pre = if (sym1.owner.isClass) sym1.owner.thisType else NoPrefix intersectionType(List(tp, singleType(pre, sym1))) @@ -5198,15 +5199,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def warn(message: String) = context.warning(lit.pos, s"possible missing interpolator: $message") def suspiciousSym(name: TermName) = context.lookupSymbol(name, _ => true).symbol def suspiciousExpr = InterpolatorCodeRegex findFirstIn s - def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(s drop 1)) + def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(TermName(s drop 1))) - // heuristics - no warning on e.g. a string with only "$asInstanceOf" - if (s contains ' ') ( - if (suspiciousExpr.nonEmpty) - warn("detected an interpolated expression") // "${...}" - else - suspiciousIdents find isPlausible foreach (sym => warn(s"detected interpolated identifier `$$${sym.name}`")) // "$id" - ) + if (suspiciousExpr.nonEmpty) + warn("detected an interpolated expression") // "${...}" + else + suspiciousIdents find isPlausible foreach (sym => warn(s"detected interpolated identifier `$$${sym.name}`")) // "$id" } lit match { case Literal(Constant(s: String)) if !isRecognizablyNotForInterpolation => maybeWarn(s) @@ -5384,8 +5382,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ) def runTyper(): Tree = { if (retypingOk) { - tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol + tree.setType(null) + if (tree.hasSymbolField) tree.symbol = NoSymbol } val alreadyTyped = tree.tpe ne null val shouldPrint = !alreadyTyped && !phase.erasedTypes diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index fc1f45e358..22fb0728e6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package typechecker import symtab.Flags._ +import scala.reflect.internal.util.ListOfNil /* * @author Martin Odersky diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 1643e0061f..47c88f2c00 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -7,7 +7,7 @@ import scala.tools.nsc.Global import scala.tools.nsc.reporters._ import scala.tools.nsc.CompilerCommand import scala.tools.nsc.io.{AbstractFile, VirtualDirectory} -import scala.tools.nsc.util.AbstractFileClassLoader +import scala.reflect.internal.util.AbstractFileClassLoader import scala.reflect.internal.Flags._ import scala.reflect.internal.util.{BatchSourceFile, NoSourceFile, NoFile} import java.lang.{Class => jClass} diff --git a/src/library/scala/annotation/switch.scala b/src/library/scala/annotation/switch.scala index 23e3923407..00124cf88b 100644 --- a/src/library/scala/annotation/switch.scala +++ b/src/library/scala/annotation/switch.scala @@ -22,6 +22,9 @@ package scala.annotation } }}} * + * Note: for pattern matches with one or two cases, the compiler generates jump instructions. + * Annotating such a match with `@switch` does not issue any warning. + * * @author Paul Phillips * @since 2.8 */ diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 8c7c754af8..f77462ce88 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -278,7 +278,7 @@ trait GenTraversableOnce[+A] extends Any { * * @param op the binary operator. * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceLeft(op)` is this $coll is nonempty, + * @return an option value containing the result of `reduceLeft(op)` if this $coll is nonempty, * `None` otherwise. */ def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] @@ -290,7 +290,7 @@ trait GenTraversableOnce[+A] extends Any { * * @param op the binary operator. * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceRight(op)` is this $coll is nonempty, + * @return an option value containing the result of `reduceRight(op)` if this $coll is nonempty, * `None` otherwise. */ def reduceRightOption[B >: A](op: (A, B) => B): Option[B] diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 32d31f0be8..96374ef653 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/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 82a3b00ac4..9cb1dee41c 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -28,7 +28,7 @@ import scala.math.ScalaNumber; * @version 2.0 */ public final class BoxesRunTime { - private static final int CHAR = 0, BYTE = 1, SHORT = 2, INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7; + private static final int CHAR = 0, /* BYTE = 1, SHORT = 2, */ INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7; /** We don't need to return BYTE and SHORT, as everything which might * care widens to INT. @@ -43,10 +43,6 @@ public final class BoxesRunTime return OTHER; } - private static String boxDescription(Object a) { - return "" + a.getClass().getSimpleName() + "(" + a + ")"; - } - /* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */ public static java.lang.Boolean boxToBoolean(boolean b) { diff --git a/src/reflect/scala/reflect/api/Names.scala b/src/reflect/scala/reflect/api/Names.scala index 472da60338..cc01225287 100644 --- a/src/reflect/scala/reflect/api/Names.scala +++ b/src/reflect/scala/reflect/api/Names.scala @@ -30,15 +30,15 @@ import scala.language.implicitConversions */ trait Names { /** An implicit conversion from String to TermName. - * Enables an alternative notation `"map": TermName` as opposed to `TermName("map")`. - * @group Names + * Enables an alternative notation `"map": TermName` as opposed to `TermName("map")`. + * @group Names */ @deprecated("Use explicit `TermName(s)` instead", "2.11.0") implicit def stringToTermName(s: String): TermName = TermName(s) /** An implicit conversion from String to TypeName. - * Enables an alternative notation `"List": TypeName` as opposed to `TypeName("List")`. - * @group Names + * Enables an alternative notation `"List": TypeName` as opposed to `TypeName("List")`. + * @group Names */ @deprecated("Use explicit `TypeName(s)` instead", "2.11.0") implicit def stringToTypeName(s: String): TypeName = TypeName(s) diff --git a/src/reflect/scala/reflect/api/StandardLiftables.scala b/src/reflect/scala/reflect/api/StandardLiftables.scala index 66ac62cc9e..ebf15e4f57 100644 --- a/src/reflect/scala/reflect/api/StandardLiftables.scala +++ b/src/reflect/scala/reflect/api/StandardLiftables.scala @@ -230,6 +230,6 @@ trait StandardLiftables { self: Universe => val Symbol = TermName("Symbol") val util = TermName("util") val Vector = TermName("Vector") - val WILDCARD = self.nme.WILDCARD + val WILDCARD = self.termNames.WILDCARD } } diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 9ecd87c17e..2bf407ee19 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -2661,7 +2661,7 @@ trait Trees { self: Universe => * @group Traversal */ abstract class ModifiersExtractor { - def apply(): Modifiers = Modifiers(NoFlags, tpnme.EMPTY, List()) + def apply(): Modifiers = Modifiers(NoFlags, typeNames.EMPTY, List()) def apply(flags: FlagSet, privateWithin: Name, annotations: List[Tree]): Modifiers def unapply(mods: Modifiers): Option[(FlagSet, Name, List[Tree])] } @@ -2674,7 +2674,7 @@ trait Trees { self: Universe => /** The factory for `Modifiers` instances. * @group Traversal */ - def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, tpnme.EMPTY) + def Modifiers(flags: FlagSet): Modifiers = Modifiers(flags, typeNames.EMPTY) /** An empty `Modifiers` object: no flags, empty visibility annotation and no Scala annotations. * @group Traversal diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index f6995dd5de..cd7648a44a 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -469,7 +469,7 @@ trait Types { def unapply(tpe: SingleType): Option[(Type, Symbol)] /** @see [[InternalApi.singleType]] */ - @deprecated("Use `ClassSymbol.thisPrefix` or `internal.singleType` instead") + @deprecated("Use `ClassSymbol.thisPrefix` or `internal.singleType` instead", "2.11.0") def apply(pre: Type, sym: Symbol)(implicit token: CompatToken): Type = internal.singleType(pre, sym) } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 9f4ec3e6d1..756ed870ca 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -156,11 +156,11 @@ trait Definitions extends api.StandardDefinitions { // It becomes tricky to create dedicated objects for other symbols because // of initialization order issues. - lazy val JavaLangPackage = getPackage("java.lang") + lazy val JavaLangPackage = getPackage(TermName("java.lang")) lazy val JavaLangPackageClass = JavaLangPackage.moduleClass.asClass - lazy val ScalaPackage = getPackage("scala") + lazy val ScalaPackage = getPackage(TermName("scala")) lazy val ScalaPackageClass = ScalaPackage.moduleClass.asClass - lazy val RuntimePackage = getPackage("scala.runtime") + lazy val RuntimePackage = getPackage(TermName("scala.runtime")) lazy val RuntimePackageClass = RuntimePackage.moduleClass.asClass def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { @@ -453,7 +453,7 @@ trait Definitions extends api.StandardDefinitions { // XML lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope") - lazy val ScalaXmlPackage = getPackageIfDefined("scala.xml") + lazy val ScalaXmlPackage = getPackageIfDefined(TermName("scala.xml")) // scala.reflect lazy val ReflectPackage = requiredModule[scala.reflect.`package`.type] @@ -1148,7 +1148,7 @@ trait Definitions extends api.StandardDefinitions { // Trying to allow for deprecated locations sym.isAliasType && isMetaAnnotation(sym.info.typeSymbol) ) - lazy val metaAnnotations: Set[Symbol] = getPackage("scala.annotation.meta").info.members filter (_ isSubClass StaticAnnotationClass) toSet + lazy val metaAnnotations: Set[Symbol] = getPackage(TermName("scala.annotation.meta")).info.members filter (_ isSubClass StaticAnnotationClass) toSet // According to the scala.annotation.meta package object: // * By default, annotations on (`val`-, `var`- or plain) constructor parameters @@ -1462,7 +1462,7 @@ trait Definitions extends api.StandardDefinitions { ) lazy val TagSymbols = TagMaterializers.keySet lazy val Predef_conforms = (getMemberIfDefined(PredefModule, nme.conforms) - orElse getMemberMethod(PredefModule, "conforms": TermName)) // TODO: predicate on -Xsource:2.10 (for now, needed for transition from M8 -> RC1) + orElse getMemberMethod(PredefModule, TermName("conforms"))) // TODO: predicate on -Xsource:2.10 (for now, needed for transition from M8 -> RC1) lazy val Predef_classOf = getMemberMethod(PredefModule, nme.classOf) lazy val Predef_implicitly = getMemberMethod(PredefModule, nme.implicitly) lazy val Predef_wrapRefArray = getMemberMethod(PredefModule, nme.wrapRefArray) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index dc4ad25ef2..494f62af06 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -301,7 +301,7 @@ trait Importers { to: SymbolTable => case (their: from.TypeTree, my: to.TypeTree) => if (their.wasEmpty) my.defineType(importType(their.tpe)) else my.setType(importType(their.tpe)) case (_, _) => - my.tpe = importType(their.tpe) + my.setType(importType(their.tpe)) } } } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 98b2c48379..b44c4022f6 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -1006,7 +1006,7 @@ trait Printers extends api.Printers { self: SymbolTable => printSuper(st, printedName(qual), checkSymbol = false) case th @ This(qual) => - if (tree.hasExistingSymbol && tree.symbol.isPackage) print(tree.symbol.fullName) + if (tree.hasExistingSymbol && tree.symbol.hasPackageFlag) print(tree.symbol.fullName) else printThis(th, printedName(qual)) // remove this prefix from constructor invocation in typechecked trees: this.this -> this @@ -1023,7 +1023,7 @@ trait Printers extends api.Printers { self: SymbolTable => }) && (tr match { // check that Select contains package case Select(q, _) => checkRootPackage(q) case _: Ident | _: This => val sym = tr.symbol - tr.hasExistingSymbol && sym.isPackage && sym.name != nme.ROOTPKG + tr.hasExistingSymbol && sym.hasPackageFlag && sym.name != nme.ROOTPKG case _ => false }) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index d23a102b28..d85ec22a84 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -155,11 +155,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => def toTypeConstructor: Type = typeConstructor def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this } - def getter: Symbol = getter(owner) - def setter: Symbol = setter(owner) + def getter: Symbol = getterIn(owner) + def setter: Symbol = setterIn(owner) def companion: Symbol = { - if (isModule && !isPackage) companionSymbol + if (isModule && !hasPackageFlag) companionSymbol else if (isModuleClass && !isPackageClass) sourceModule.companionSymbol else if (isClass && !isModuleClass && !isPackageClass) companionSymbol else NoSymbol @@ -1047,7 +1047,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isIncompleteIn(base: Symbol): Boolean = this.isDeferred || (this hasFlag ABSOVERRIDE) && { - val supersym = superSymbol(base) + val supersym = superSymbolIn(base) supersym == NoSymbol || supersym.isIncompleteIn(base) } @@ -2375,13 +2375,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => Nil ) + @deprecated("Use `superSymbolIn` instead", "2.11.0") + final def superSymbol(base: Symbol): Symbol = superSymbolIn(base) + /** The symbol accessed by a super in the definition of this symbol when * seen from class `base`. This symbol is always concrete. * pre: `this.owner` is in the base class sequence of `base`. */ - @deprecated("Use `superSymbolIn` instead", "2.11.0") - final def superSymbol(base: Symbol): Symbol = superSymbolIn(base) - final def superSymbolIn(base: Symbol): Symbol = { var bcs = base.info.baseClasses dropWhile (owner != _) drop 1 var sym: Symbol = NoSymbol @@ -2393,12 +2393,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => sym } - /** The getter of this value or setter definition in class `base`, or NoSymbol if - * none exists. - */ @deprecated("Use `getterIn` instead", "2.11.0") final def getter(base: Symbol): Symbol = getterIn(base) + /** The getter of this value or setter definition in class `base`, or NoSymbol if none exists. */ final def getterIn(base: Symbol): Symbol = base.info decl getterName filter (_.hasAccessorFlag) @@ -2406,11 +2404,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => def setterName: TermName = name.setterName def localName: TermName = name.localName - /** The setter of this value or getter definition, or NoSymbol if none exists */ @deprecated("Use `setterIn` instead", "2.11.0") final def setter(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol = setterIn(base, hasExpandedName) + /** The setter of this value or getter definition, or NoSymbol if none exists. */ final def setterIn(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol = base.info decl setterNameInBase(base, hasExpandedName) filter (_.hasAccessorFlag) @@ -2538,7 +2536,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (isInstanceOf[FreeTermSymbol]) ("free term", "free term", "FTE") else if (isInstanceOf[FreeTypeSymbol]) ("free type", "free type", "FTY") else if (isPackageClass) ("package class", "package", "PKC") - else if (isPackage) ("package", "package", "PK") + else if (hasPackageFlag) ("package", "package", "PK") else if (isPackageObject) ("package object", "package", "PKO") else if (isPackageObjectClass) ("package object class", "package", "PKOC") else if (isAnonymousClass) ("anonymous class", "anonymous class", "AC") @@ -2822,7 +2820,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def outerSource: Symbol = // SI-6888 Approximate the name to workaround the deficiencies in `nme.originalName` // in the face of classes named '$'. SI-2806 remains open to address the deeper problem. - if (originalName endsWith (nme.OUTER)) initialize.referenced + if (unexpandedName endsWith (nme.OUTER)) initialize.referenced else NoSymbol def setModuleClass(clazz: Symbol): TermSymbol = { @@ -2852,8 +2850,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => accessed.expandName(base) } else if (hasGetter) { - getter(owner).expandName(base) - setter(owner).expandName(base) + getterIn(owner).expandName(base) + setterIn(owner).expandName(base) } name = nme.expandedName(name.toTermName, base) } diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index b3e11a826e..75a1969d22 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -362,7 +362,7 @@ abstract class TreeGen { if (body forall treeInfo.isInterfaceMember) None else Some( atPos(wrappingPos(superPos, lvdefs)) ( - DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(lvdefs, Literal(Constant()))))) + DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(lvdefs, Literal(Constant(())))))) } else { // convert (implicit ... ) to ()(implicit ... ) if its the only parameter section @@ -376,7 +376,7 @@ abstract class TreeGen { // therefore here we emit a dummy which gets populated when the template is named and typechecked Some( atPos(wrappingPos(superPos, lvdefs ::: vparamss1.flatten).makeTransparent) ( - DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant()))))) + DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant(())))))) } } constr foreach (ensureNonOverlapping(_, parents ::: gvdefs, focus = false)) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index fd918b8595..e3f95f9fd8 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -87,7 +87,7 @@ trait Trees extends api.Trees { private[scala] def copyAttrs(tree: Tree): this.type = { rawatt = tree.rawatt - tpe = tree.tpe + setType(tree.tpe) if (hasSymbolField) symbol = tree.symbol this } diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 8f114caac0..86a53a1b02 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -209,7 +209,7 @@ trait Types case object UnmappableTree extends TermTree { override def toString = "<unmappable>" - super.tpe_=(NoType) + super.setType(NoType) override def tpe_=(t: Type) = if (t != NoType) { throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>") } @@ -247,7 +247,7 @@ trait Types def companion = { val sym = typeSymbolDirect - if (sym.isModule && !sym.isPackage) sym.companionSymbol.tpe + if (sym.isModule && !sym.hasPackageFlag) sym.companionSymbol.tpe else if (sym.isModuleClass && !sym.isPackageClass) sym.sourceModule.companionSymbol.tpe else if (sym.isClass && !sym.isModuleClass && !sym.isPackageClass) sym.companionSymbol.info else NoType diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 3b497227e7..237efd004f 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -142,7 +142,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive object ConstantArg { def enumToSymbol(enum: Enum[_]): Symbol = { val staticPartOfEnum = classToScala(enum.getClass).companionSymbol - staticPartOfEnum.info.declaration(enum.name: TermName) + staticPartOfEnum.info.declaration(TermName(enum.name)) } def unapply(schemaAndValue: (jClass[_], Any)): Option[Any] = schemaAndValue match { @@ -172,7 +172,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive // currently I'm simply sorting the methods to guarantee stability of the output override lazy val assocs: List[(Name, ClassfileAnnotArg)] = ( jann.annotationType.getDeclaredMethods.sortBy(_.getName).toList map (m => - (m.getName: TermName) -> toAnnotArg(m.getReturnType -> m.invoke(jann)) + TermName(m.getName) -> toAnnotArg(m.getReturnType -> m.invoke(jann)) ) ) } @@ -940,7 +940,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive val ownerModule: ModuleSymbol = if (split > 0) packageNameToScala(fullname take split) else this.RootPackage val owner = ownerModule.moduleClass - val name = (fullname: TermName) drop split + 1 + val name = TermName(fullname) drop split + 1 val opkg = owner.info decl name if (opkg.hasPackageFlag) opkg.asModule @@ -991,7 +991,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive if (name.startsWith(nme.NAME_JOIN_STRING)) coreLookup(name drop 1) else NoSymbol } if (nme.isModuleName(simpleName)) - coreLookup(nme.stripModuleSuffix(simpleName).toTermName) map (_.moduleClass) + coreLookup(simpleName.dropModule.toTermName) map (_.moduleClass) else coreLookup(simpleName) } @@ -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/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala index 50ea8d9868..9ce6331e33 100644 --- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala +++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala @@ -107,7 +107,8 @@ private[reflect] trait SymbolLoaders { self: SymbolTable => if (isCompilerUniverse) super.enter(sym) else { val existing = super.lookupEntry(sym.name) - assert(existing == null || existing.sym.isMethod, s"pkgClass = $pkgClass, sym = $sym, existing = $existing") + def eitherIsMethod(sym1: Symbol, sym2: Symbol) = sym1.isMethod || sym2.isMethod + assert(existing == null || eitherIsMethod(existing.sym, sym), s"pkgClass = $pkgClass, sym = $sym, existing = $existing") super.enter(sym) } } diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index e240bed0a7..77eb610a84 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -30,9 +30,9 @@ package runtime { import c.universe._ val runtimeClass = c.reifyEnclosingRuntimeClass if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class") - val scalaPackage = Select(Ident(newTermName("_root_")), newTermName("scala")) - val runtimeUniverse = Select(Select(Select(scalaPackage, newTermName("reflect")), newTermName("runtime")), newTermName("universe")) - val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader")))) + val scalaPackage = Select(Ident(TermName("_root_")), TermName("scala")) + val runtimeUniverse = Select(Select(Select(scalaPackage, TermName("reflect")), TermName("runtime")), TermName("universe")) + val currentMirror = Apply(Select(runtimeUniverse, TermName("runtimeMirror")), List(Select(runtimeClass, TermName("getClassLoader")))) c.Expr[Nothing](currentMirror)(c.WeakTypeTag.Nothing) } } diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 0347622cf4..c281126d5f 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -309,7 +309,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def shift[T](op: => T): T = exitingFlatten(op) } - def originalPath(name: String): String = originalPath(name: TermName) + def originalPath(name: String): String = originalPath(TermName(name)) def originalPath(name: Name): String = typerOp path name def originalPath(sym: Symbol): String = typerOp path sym def flatPath(sym: Symbol): String = flatOp shift sym.javaClassName @@ -1106,8 +1106,8 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def tryTwice(op: => Symbol): Symbol = exitingTyper(op) orElse exitingFlatten(op) def symbolOfIdent(id: String): Symbol = symbolOfType(id) orElse symbolOfTerm(id) - def symbolOfType(id: String): Symbol = tryTwice(replScope lookup (id: TypeName)) - def symbolOfTerm(id: String): Symbol = tryTwice(replScope lookup (id: TermName)) + def symbolOfType(id: String): Symbol = tryTwice(replScope lookup TypeName(id)) + def symbolOfTerm(id: String): Symbol = tryTwice(replScope lookup TermName(id)) def symbolOfName(id: Name): Symbol = replScope lookup id def runtimeClassAndTypeOfTerm(id: String): Option[(JClass, Type)] = { 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/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala index ce75749859..86155845b0 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala @@ -206,25 +206,42 @@ abstract class HtmlPage extends Page { thisPage => case tpl :: tpls => templateToHtml(tpl) ++ sep ++ templatesToHtml(tpls, sep) } - /** Returns the _big image name corresponding to the DocTemplate Entity (upper left icon) */ - def docEntityKindToBigImage(ety: DocTemplateEntity) = - if (ety.isTrait && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "trait_to_object_big.png" - else if (ety.isTrait) "trait_big.png" - else if (ety.isClass && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "class_to_object_big.png" - else if (ety.isClass) "class_big.png" - else if ((ety.isAbstractType || ety.isAliasType) && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None) "type_to_object_big.png" - else if ((ety.isAbstractType || ety.isAliasType)) "type_big.png" - else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isClass) "object_to_class_big.png" - else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && ety.companion.get.isTrait) "object_to_trait_big.png" - else if (ety.isObject && !ety.companion.isEmpty && ety.companion.get.visibility.isPublic && ety.companion.get.inSource != None && (ety.companion.get.isAbstractType || ety.companion.get.isAliasType)) "object_to_trait_big.png" - else if (ety.isObject) "object_big.png" - else if (ety.isPackage) "package_big.png" - else "class_big.png" // FIXME: an entity *should* fall into one of the above categories, but AnyRef is somehow not + object Image extends Enumeration { + val Trait, Class, Type, Object, Package = Value + } + + /** Returns the _big image name and the alt attribute + * corresponding to the DocTemplate Entity (upper left icon) */ + def docEntityKindToBigImage(ety: DocTemplateEntity) = { + def entityToImage(e: DocTemplateEntity) = + if (e.isTrait) Image.Trait + else if (e.isClass) Image.Class + else if (e.isAbstractType || e.isAliasType) Image.Type + else if (e.isObject) Image.Object + else if (e.isPackage) Image.Package + else { + // FIXME: an entity *should* fall into one of the above categories, + // but AnyRef is somehow not + Image.Class + } + + val image = entityToImage(ety) + val companionImage = ety.companion filter { + e => e.visibility.isPublic && ! e.inSource.isEmpty + } map { entityToImage } + + (image, companionImage) match { + case (from, Some(to)) => + ((from + "_to_" + to + "_big.png").toLowerCase, from + "/" + to) + case (from, None) => + ((from + "_big.png").toLowerCase, from.toString) + } + } def permalink(template: Entity, isSelf: Boolean = true): Elem = <span class="permalink"> <a href={ memberToUrl(template, isSelf) } title="Permalink" target="_top"> - <img src={ relativeLinkTo(List("permalink.png", "lib")) } /> + <img src={ relativeLinkTo(List("permalink.png", "lib")) } alt="Permalink" /> </a> </span> diff --git a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala index 910148532d..9ab3999447 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala @@ -52,7 +52,7 @@ private[html] object SyntaxHigh { "Triple", "TypeTag", "Unit") def apply(data: String): NodeSeq = { - val buf = data.getBytes + val buf = data.toCharArray val out = new StringBuilder def compare(offset: Int, key: String): Int = { @@ -60,7 +60,7 @@ private[html] object SyntaxHigh { var j = 0 val l = key.length while (i < buf.length && j < l) { - val bch = buf(i).toChar + val bch = buf(i) val kch = key charAt j if (bch < kch) return -1 else if (bch > kch) return 1 @@ -94,13 +94,13 @@ private[html] object SyntaxHigh { def line(i: Int): Int = if (i == buf.length || buf(i) == '\n') i else { - out append buf(i).toChar + out append buf(i) line(i+1) } var level = 0 def multiline(i: Int, star: Boolean): Int = { if (i == buf.length) return i - val ch = buf(i).toChar + val ch = buf(i) out append ch ch match { case '*' => @@ -127,7 +127,7 @@ private[html] object SyntaxHigh { if (i == buf.length) i else if (i > j+6) { out setLength 0; j } else { - val ch = buf(i).toChar + val ch = buf(i) out append ch ch match { case '\\' => @@ -148,7 +148,7 @@ private[html] object SyntaxHigh { val out = new StringBuilder("\"") def strlit0(i: Int, bslash: Boolean): Int = { if (i == buf.length) return i - val ch = buf(i).toChar + val ch = buf(i) out append ch ch match { case '\\' => @@ -167,7 +167,7 @@ private[html] object SyntaxHigh { val out = new StringBuilder def intg(i: Int): Int = { if (i == buf.length) return i - val ch = buf(i).toChar + val ch = buf(i) ch match { case '.' => out append ch @@ -181,7 +181,7 @@ private[html] object SyntaxHigh { } def frac(i: Int): Int = { if (i == buf.length) return i - val ch = buf(i).toChar + val ch = buf(i) ch match { case 'e' | 'E' => out append ch @@ -195,7 +195,7 @@ private[html] object SyntaxHigh { } def expo(i: Int, signed: Boolean): Int = { if (i == buf.length) return i - val ch = buf(i).toChar + val ch = buf(i) ch match { case '+' | '-' if !signed => out append ch @@ -222,7 +222,7 @@ private[html] object SyntaxHigh { case '&' => parse("&", i+1) case '<' if i+1 < buf.length => - val ch = buf(i+1).toChar + val ch = buf(i+1) if (ch == '-' || ch == ':' || ch == '%') parse("<span class=\"kw\"><"+ch+"</span>", i+2) else @@ -236,19 +236,19 @@ private[html] object SyntaxHigh { if (i+1 < buf.length && buf(i+1) == '>') parse("<span class=\"kw\">=></span>", i+2) else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) case '/' => if (i+1 < buf.length && (buf(i+1) == '/' || buf(i+1) == '*')) { val c = comment(i+1) parse("<span class=\"cmt\">"+c+"</span>", i+c.length) } else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) case '\'' => val s = charlit(i+1) if (s.length > 0) parse("<span class=\"lit\">"+s+"</span>", i+s.length) else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) case '"' => val s = strlit(i+1) parse("<span class=\"lit\">"+s+"</span>", i+s.length) @@ -257,9 +257,9 @@ private[html] object SyntaxHigh { if (k >= 0) parse("<span class=\"ano\">@"+annotations(k)+"</span>", i+annotations(k).length+1) else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) case _ => - if (i == 0 || (i >= 1 && !Character.isJavaIdentifierPart(buf(i-1).toChar))) { + if (i == 0 || (i >= 1 && !Character.isJavaIdentifierPart(buf(i-1)))) { if (Character.isDigit(buf(i).toInt) || (buf(i) == '.' && i + 1 < buf.length && Character.isDigit(buf(i+1).toInt))) { val s = numlit(i) @@ -273,11 +273,11 @@ private[html] object SyntaxHigh { if (k >= 0) parse("<span class=\"std\">"+standards(k)+"</span>", i+standards(k).length) else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) } } } else - parse(buf(i).toChar.toString, i+1) + parse(buf(i).toString, i+1) } } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index e10c54a414..c384ed7034 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -103,11 +103,13 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <body class={ if (tpl.isType) "type" else "value" }> <div id="definition"> { + val (src, alt) = docEntityKindToBigImage(tpl) + tpl.companion match { case Some(companion) if (companion.visibility.isPublic && companion.inSource != None) => - <a href={relativeLinkTo(companion)} title={docEntityKindToCompanionTitle(tpl)}><img src={ relativeLinkTo(List(docEntityKindToBigImage(tpl), "lib")) }/></a> + <a href={relativeLinkTo(companion)} title={docEntityKindToCompanionTitle(tpl)}><img alt={alt} src={ relativeLinkTo(List(src, "lib")) }/></a> case _ => - <img src={ relativeLinkTo(List(docEntityKindToBigImage(tpl), "lib")) }/> + <img alt={alt} src={ relativeLinkTo(List(src, "lib")) }/> }} { owner } <h1>{ displayName }</h1>{ 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 e129e6cf6a..e84d7c1ca6 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/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js index 1ebcb67f04..798a2d430b 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js @@ -179,7 +179,7 @@ $(document).ready(function(){ filter(); }); - $("#visbl > ol > li.public").click(function() { + $("#order > ol > li.alpha").click(function() { if ($(this).hasClass("out")) { orderAlpha(); } diff --git a/test/files/jvm/t8689.scala b/test/files/jvm/t8689.scala index ef43a1df63..3ee20d711a 100644 --- a/test/files/jvm/t8689.scala +++ b/test/files/jvm/t8689.scala @@ -4,10 +4,15 @@ object Test { import ExecutionContext.Implicits.global val source1 = Promise[Int]() val source2 = Promise[Int]() + val done = Promise[Unit]() source2.completeWith(source1.future).future.onComplete { - case _ => print("success") + case _ => + print("success") + done.success(()) } source2.tryFailure(new TimeoutException) source1.success(123) + import duration._ + Await.result(done.future, 120.seconds) } -}
\ No newline at end of file +} 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/macro-invalidusage-badargs.check b/test/files/neg/macro-invalidusage-badargs.check index 4c1115418b..19ac6528d3 100644 --- a/test/files/neg/macro-invalidusage-badargs.check +++ b/test/files/neg/macro-invalidusage-badargs.check @@ -9,7 +9,8 @@ Macros_Test_2.scala:6: error: too few argument lists for macro invocation Macros_Test_2.scala:7: error: Int does not take parameters foo(4)(2) ^ -Macros_Test_2.scala:8: error: macro applications do not support named and/or default arguments +Macros_Test_2.scala:8: error: not enough arguments for macro method foo: (x: Int)Int. +Unspecified value parameter x. foo() ^ Macros_Test_2.scala:9: error: too many arguments for macro method foo: (x: Int)Int diff --git a/test/files/neg/reflection-names-neg.check b/test/files/neg/reflection-names-neg.check deleted file mode 100644 index f941ec8dc1..0000000000 --- a/test/files/neg/reflection-names-neg.check +++ /dev/null @@ -1,13 +0,0 @@ -reflection-names-neg.scala:5: error: type mismatch; - found : String("abc") - required: reflect.runtime.universe.Name -Note that implicit conversions are not applicable because they are ambiguous: - both method stringToTermName in trait Names of type (s: String)reflect.runtime.universe.TermName - and method stringToTypeName in trait Names of type (s: String)reflect.runtime.universe.TypeName - are possible conversion functions from String("abc") to reflect.runtime.universe.Name - val x2 = ("abc": Name) drop 1 // error - ^ -reflection-names-neg.scala:5: error: value drop is not a member of reflect.runtime.universe.Name - val x2 = ("abc": Name) drop 1 // error - ^ -two errors found diff --git a/test/files/neg/reflection-names-neg.scala b/test/files/neg/reflection-names-neg.scala deleted file mode 100644 index 7283d16db9..0000000000 --- a/test/files/neg/reflection-names-neg.scala +++ /dev/null @@ -1,6 +0,0 @@ -import scala.reflect.runtime.universe._ - -object Test { - val x1 = "abc" drop 1 // "bc": String - val x2 = ("abc": Name) drop 1 // error -} 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/neg/t7157.check b/test/files/neg/t7157.check index c6a7af9a23..3988460d4b 100644 --- a/test/files/neg/t7157.check +++ b/test/files/neg/t7157.check @@ -7,7 +7,8 @@ Test_2.scala:6: error: too many arguments for macro method m1_0_0: ()Unit Test_2.scala:7: error: too many arguments for macro method m1_0_0: ()Unit m1_0_0(1, 2, 3) ^ -Test_2.scala:9: error: macro applications do not support named and/or default arguments +Test_2.scala:9: error: not enough arguments for macro method m1_1_1: (x: Int)Unit. +Unspecified value parameter x. m1_1_1() ^ Test_2.scala:11: error: too many arguments for macro method m1_1_1: (x: Int)Unit @@ -16,22 +17,27 @@ Test_2.scala:11: error: too many arguments for macro method m1_1_1: (x: Int)Unit Test_2.scala:12: error: too many arguments for macro method m1_1_1: (x: Int)Unit m1_1_1(1, 2, 3) ^ -Test_2.scala:14: error: macro applications do not support named and/or default arguments +Test_2.scala:14: error: not enough arguments for macro method m1_2_2: (x: Int, y: Int)Unit. +Unspecified value parameters x, y. m1_2_2() ^ -Test_2.scala:15: error: macro applications do not support named and/or default arguments +Test_2.scala:15: error: not enough arguments for macro method m1_2_2: (x: Int, y: Int)Unit. +Unspecified value parameter y. m1_2_2(1) ^ Test_2.scala:17: error: too many arguments for macro method m1_2_2: (x: Int, y: Int)Unit m1_2_2(1, 2, 3) ^ -Test_2.scala:24: error: macro applications do not support named and/or default arguments +Test_2.scala:24: error: not enough arguments for macro method m1_1_inf: (x: Int, y: Int*)Unit. +Unspecified value parameters x, y. m1_1_inf() ^ -Test_2.scala:29: error: macro applications do not support named and/or default arguments +Test_2.scala:29: error: not enough arguments for macro method m1_2_inf: (x: Int, y: Int, z: Int*)Unit. +Unspecified value parameters x, y, z. m1_2_inf() ^ -Test_2.scala:30: error: macro applications do not support named and/or default arguments +Test_2.scala:30: error: not enough arguments for macro method m1_2_inf: (x: Int, y: Int, z: Int*)Unit. +Unspecified value parameters y, z. m1_2_inf(1) ^ Test_2.scala:35: error: too many arguments for macro method m2_0_0: ()Unit @@ -43,7 +49,8 @@ Test_2.scala:36: error: too many arguments for macro method m2_0_0: ()Unit Test_2.scala:37: error: too many arguments for macro method m2_0_0: ()Unit m2_0_0()(1, 2, 3) ^ -Test_2.scala:39: error: macro applications do not support named and/or default arguments +Test_2.scala:39: error: not enough arguments for macro method m2_1_1: (x: Int)Unit. +Unspecified value parameter x. m2_1_1()() ^ Test_2.scala:41: error: too many arguments for macro method m2_1_1: (x: Int)Unit @@ -52,22 +59,27 @@ Test_2.scala:41: error: too many arguments for macro method m2_1_1: (x: Int)Unit Test_2.scala:42: error: too many arguments for macro method m2_1_1: (x: Int)Unit m2_1_1()(1, 2, 3) ^ -Test_2.scala:44: error: macro applications do not support named and/or default arguments +Test_2.scala:44: error: not enough arguments for macro method m2_2_2: (x: Int, y: Int)Unit. +Unspecified value parameters x, y. m2_2_2()() ^ -Test_2.scala:45: error: macro applications do not support named and/or default arguments +Test_2.scala:45: error: not enough arguments for macro method m2_2_2: (x: Int, y: Int)Unit. +Unspecified value parameter y. m2_2_2()(1) ^ Test_2.scala:47: error: too many arguments for macro method m2_2_2: (x: Int, y: Int)Unit m2_2_2()(1, 2, 3) ^ -Test_2.scala:54: error: macro applications do not support named and/or default arguments +Test_2.scala:54: error: not enough arguments for macro method m2_1_inf: (x: Int, y: Int*)Unit. +Unspecified value parameters x, y. m2_1_inf()() ^ -Test_2.scala:59: error: macro applications do not support named and/or default arguments +Test_2.scala:59: error: not enough arguments for macro method m2_2_inf: (x: Int, y: Int, z: Int*)Unit. +Unspecified value parameters x, y, z. m2_2_inf()() ^ -Test_2.scala:60: error: macro applications do not support named and/or default arguments +Test_2.scala:60: error: not enough arguments for macro method m2_2_inf: (x: Int, y: Int, z: Int*)Unit. +Unspecified value parameters y, z. m2_2_inf()(1) ^ 24 errors found diff --git a/test/files/neg/t7848-interp-warn.check b/test/files/neg/t7848-interp-warn.check index 4cf9d55ffd..637fc8941a 100644 --- a/test/files/neg/t7848-interp-warn.check +++ b/test/files/neg/t7848-interp-warn.check @@ -4,9 +4,12 @@ t7848-interp-warn.scala:8: warning: possible missing interpolator: detected inte t7848-interp-warn.scala:12: warning: possible missing interpolator: detected an interpolated expression "A doubly important ${foo * 2} message!" ^ +t7848-interp-warn.scala:15: warning: possible missing interpolator: detected interpolated identifier `$bar` + def i = s"Try using '${ "$bar" }' instead." // was: no warn on space test + ^ t7848-interp-warn.scala:16: warning: possible missing interpolator: detected interpolated identifier `$bar` def j = s"Try using '${ "something like $bar" }' instead." // warn ^ error: No warnings can be incurred under -Xfatal-warnings. -three warnings found +four warnings found one error found diff --git a/test/files/neg/t7848-interp-warn.scala b/test/files/neg/t7848-interp-warn.scala index 3887aff8de..a76141041d 100644 --- a/test/files/neg/t7848-interp-warn.scala +++ b/test/files/neg/t7848-interp-warn.scala @@ -12,7 +12,7 @@ object Test { "A doubly important ${foo * 2} message!" } def h = s"Try using '$$bar' instead." // no warn - def i = s"Try using '${ "$bar" }' instead." // no warn on space test + def i = s"Try using '${ "$bar" }' instead." // was: no warn on space test def j = s"Try using '${ "something like $bar" }' instead." // warn def k = f"Try using '$bar' instead." // no warn on other std interps } diff --git a/test/files/neg/t8731.check b/test/files/neg/t8731.check index 2a9af475fc..d47bd55b45 100644 --- a/test/files/neg/t8731.check +++ b/test/files/neg/t8731.check @@ -1,9 +1,6 @@ -t8731.scala:5: warning: matches with two cases or fewer are emitted using if-then-else instead of switch - def f(x: Int) = (x: @annotation.switch) match { - ^ t8731.scala:10: warning: could not emit switch for @switch annotated match def g(x: Int) = (x: @annotation.switch) match { ^ error: No warnings can be incurred under -Xfatal-warnings. -two warnings found +one warning found one error found diff --git a/test/files/neg/t9127.check b/test/files/neg/t9127.check new file mode 100644 index 0000000000..2ecf8af464 --- /dev/null +++ b/test/files/neg/t9127.check @@ -0,0 +1,12 @@ +t9127.scala:4: warning: possible missing interpolator: detected interpolated identifier `$s` + val t = "$s" + ^ +t9127.scala:5: warning: possible missing interpolator: detected an interpolated expression + val u = "a${s}b" + ^ +t9127.scala:6: warning: possible missing interpolator: detected interpolated identifier `$s` + val v = "a$s b" + ^ +error: No warnings can be incurred under -Xfatal-warnings. +three warnings found +one error found diff --git a/test/files/neg/t9127.flags b/test/files/neg/t9127.flags new file mode 100644 index 0000000000..b0d7bc25cb --- /dev/null +++ b/test/files/neg/t9127.flags @@ -0,0 +1 @@ +-Xlint:missing-interpolator -Xfatal-warnings diff --git a/test/files/neg/t9127.scala b/test/files/neg/t9127.scala new file mode 100644 index 0000000000..c0746144eb --- /dev/null +++ b/test/files/neg/t9127.scala @@ -0,0 +1,7 @@ + +trait X { + val s = "hello" + val t = "$s" + val u = "a${s}b" + val v = "a$s b" +} 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/t8861.flags b/test/files/pos/t8861.flags new file mode 100644 index 0000000000..99a6391058 --- /dev/null +++ b/test/files/pos/t8861.flags @@ -0,0 +1 @@ +-Xlint:infer-any -Xfatal-warnings diff --git a/test/files/pos/t8861.scala b/test/files/pos/t8861.scala new file mode 100644 index 0000000000..816d15700e --- /dev/null +++ b/test/files/pos/t8861.scala @@ -0,0 +1,11 @@ + +trait Test { + type R = PartialFunction[Any, Unit] + + val x: R = { case "" => } + val y: R = { case "" => } + + val z: R = x orElse y + val zz = x orElse y +} + 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/t7741a/GroovyInterface$1Dump.java b/test/files/run/t7741a/GroovyInterface$1Dump.java new file mode 100644 index 0000000000..0c0eab3f1b --- /dev/null +++ b/test/files/run/t7741a/GroovyInterface$1Dump.java @@ -0,0 +1,222 @@ +import java.util.*; +import scala.tools.asm.*; + +// generated with +// git clone alewando/scala_groovy_interop +// SCALA_HOME=... GROOVY_HOME=... ant +// cd /code/scala2 +// java -classpath build/asm/classes:/Users/jason/code/scala_groovy_interop/classes:/code/scala2/build/pack/lib/scala-library.jar:/usr/local/Cellar/groovy/2.4.1/libexec/embeddable/groovy-all-2.4.1.jar scala.tools.asm.util.ASMifier 'GroovyInterface$1' +// java -classpath build/asm/classes:/Users/jason/code/scala_groovy_interop/classes:/code/scala2/build/pack/lib/scala-library.jar:/usr/local/Cellar/groovy/2.4.1/libexec/embeddable/groovy-all-2.4.1.jar scala.tools.asm.util.ASMifier 'GroovyInterface$1' +public class GroovyInterface$1Dump implements Opcodes { + + public static byte[] dump () throws Exception { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(V1_5, ACC_SUPER + ACC_SYNTHETIC, "GroovyInterface$1", null, "java/lang/Object", new String[] {}); + + cw.visitInnerClass("GroovyInterface$1", "GroovyInterface", "1", ACC_SYNTHETIC); + + { + fv = cw.visitField(ACC_STATIC + ACC_SYNTHETIC, "$class$GroovyInterface", "Ljava/lang/Class;", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$staticClassInfo", "Lorg/codehaus/groovy/reflection/ClassInfo;", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PUBLIC + ACC_STATIC + ACC_TRANSIENT + ACC_SYNTHETIC, "__$stMC", "Z", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_TRANSIENT + ACC_SYNTHETIC, "metaClass", "Lgroovy/lang/MetaClass;", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$callSiteArray", "Ljava/lang/ref/SoftReference;", null, null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + mv.visitMethodInsn(INVOKESTATIC, "GroovyInterface$1", "$getCallSiteArray", "()[Lorg/codehaus/groovy/runtime/callsite/CallSite;", false); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "GroovyInterface$1", "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitVarInsn(ASTORE, 2); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(SWAP); + mv.visitFieldInsn(PUTFIELD, "GroovyInterface$1", "metaClass", "Lgroovy/lang/MetaClass;"); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(POP); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 3); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PROTECTED + ACC_SYNTHETIC, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); + mv.visitLdcInsn(Type.getType("LGroovyInterface$1;")); + Label l0 = new Label(); + mv.visitJumpInsn(IF_ACMPEQ, l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/ScriptBytecodeAdapter", "initMetaClass", "(Ljava/lang/Object;)Lgroovy/lang/MetaClass;", false); + mv.visitInsn(ARETURN); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, "GroovyInterface$1", "$staticClassInfo", "Lorg/codehaus/groovy/reflection/ClassInfo;"); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); + Label l1 = new Label(); + mv.visitJumpInsn(IFNONNULL, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/reflection/ClassInfo", "getClassInfo", "(Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;", false); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 1); + mv.visitFieldInsn(PUTSTATIC, "GroovyInterface$1", "$staticClassInfo", "Lorg/codehaus/groovy/reflection/ClassInfo;"); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "org/codehaus/groovy/reflection/ClassInfo", "getMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "getMetaClass", "()Lgroovy/lang/MetaClass;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, "GroovyInterface$1", "metaClass", "Lgroovy/lang/MetaClass;"); + mv.visitInsn(DUP); + Label l0 = new Label(); + mv.visitJumpInsn(IFNULL, l0); + mv.visitInsn(ARETURN); + mv.visitLabel(l0); + mv.visitInsn(POP); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKEVIRTUAL, "GroovyInterface$1", "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitFieldInsn(PUTFIELD, "GroovyInterface$1", "metaClass", "Lgroovy/lang/MetaClass;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, "GroovyInterface$1", "metaClass", "Lgroovy/lang/MetaClass;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "setMetaClass", "(Lgroovy/lang/MetaClass;)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, "GroovyInterface$1", "metaClass", "Lgroovy/lang/MetaClass;"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "invokeMethod", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "GroovyInterface$1", "getMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "invokeMethod", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", true); + mv.visitInsn(ARETURN); + mv.visitMaxs(4, 3); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "getProperty", "(Ljava/lang/String;)Ljava/lang/Object;", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "GroovyInterface$1", "getMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "getProperty", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", true); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "setProperty", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "GroovyInterface$1", "getMetaClass", "()Lgroovy/lang/MetaClass;", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "setProperty", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 3); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); + mv.visitCode(); + mv.visitLdcInsn(Type.getType("LGroovyInterface;")); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(PUTSTATIC, "GroovyInterface$1", "$class$GroovyInterface", "Ljava/lang/Class;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(POP); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$createCallSiteArray", "()Lorg/codehaus/groovy/runtime/callsite/CallSiteArray;", null, null); + mv.visitCode(); + mv.visitLdcInsn(new Integer(0)); + mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + mv.visitVarInsn(ASTORE, 0); + mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/callsite/CallSiteArray"); + mv.visitInsn(DUP); + mv.visitLdcInsn(Type.getType("LGroovyInterface$1;")); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/callsite/CallSiteArray", "<init>", "(Ljava/lang/Class;[Ljava/lang/String;)V", false); + mv.visitInsn(ARETURN); + mv.visitMaxs(4, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC, "$getCallSiteArray", "()[Lorg/codehaus/groovy/runtime/callsite/CallSite;", null, null); + mv.visitCode(); + mv.visitFieldInsn(GETSTATIC, "GroovyInterface$1", "$callSiteArray", "Ljava/lang/ref/SoftReference;"); + Label l0 = new Label(); + mv.visitJumpInsn(IFNULL, l0); + mv.visitFieldInsn(GETSTATIC, "GroovyInterface$1", "$callSiteArray", "Ljava/lang/ref/SoftReference;"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, "org/codehaus/groovy/runtime/callsite/CallSiteArray"); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 0); + Label l1 = new Label(); + mv.visitJumpInsn(IFNONNULL, l1); + mv.visitLabel(l0); + mv.visitMethodInsn(INVOKESTATIC, "GroovyInterface$1", "$createCallSiteArray", "()Lorg/codehaus/groovy/runtime/callsite/CallSiteArray;", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "<init>", "(Ljava/lang/Object;)V", false); + mv.visitFieldInsn(PUTSTATIC, "GroovyInterface$1", "$callSiteArray", "Ljava/lang/ref/SoftReference;"); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, "org/codehaus/groovy/runtime/callsite/CallSiteArray", "array", "[Lorg/codehaus/groovy/runtime/callsite/CallSite;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } +} diff --git a/test/files/run/t7741a/GroovyInterfaceDump.java b/test/files/run/t7741a/GroovyInterfaceDump.java new file mode 100644 index 0000000000..87c09e272f --- /dev/null +++ b/test/files/run/t7741a/GroovyInterfaceDump.java @@ -0,0 +1,51 @@ +import java.util.*; +import scala.tools.asm.*; + +// generated with +// git clone alewando/scala_groovy_interop +// SCALA_HOME=... GROOVY_HOME=... ant +// cd /code/scala2 +// java -classpath build/asm/classes:/Users/jason/code/scala_groovy_interop/classes:/code/scala2/build/pack/lib/scala-library.jar:/usr/local/Cellar/groovy/2.4.1/libexec/embeddable/groovy-all-2.4.1.jar scala.tools.asm.util.ASMifier 'GroovyInterface$1' +// java -classpath build/asm/classes:/Users/jason/code/scala_groovy_interop/classes:/code/scala2/build/pack/lib/scala-library.jar:/usr/local/Cellar/groovy/2.4.1/libexec/embeddable/groovy-all-2.4.1.jar scala.tools.asm.util.ASMifier 'GroovyInterface$1' +public class GroovyInterfaceDump implements Opcodes { + + public static byte[] dump () throws Exception { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "GroovyInterface", null, "java/lang/Object", null); + + cw.visitInnerClass("GroovyInterface$1", "GroovyInterface", "1", ACC_SYNTHETIC); + + cw.visitInnerClass("GroovyInterface$__clinit__closure1", null, null, 0); + + { + fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "closure", "Ljava/lang/Object;", null, null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); + mv.visitCode(); + mv.visitTypeInsn(NEW, "GroovyInterface$__clinit__closure1"); + mv.visitInsn(DUP); + mv.visitFieldInsn(GETSTATIC, "GroovyInterface$1", "$class$GroovyInterface", "Ljava/lang/Class;"); + mv.visitFieldInsn(GETSTATIC, "GroovyInterface$1", "$class$GroovyInterface", "Ljava/lang/Class;"); + mv.visitMethodInsn(INVOKESPECIAL, "GroovyInterface$__clinit__closure1", "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(PUTSTATIC, "GroovyInterface", "closure", "Ljava/lang/Object;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(POP); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } +} + diff --git a/test/files/run/t7741a/Test.scala b/test/files/run/t7741a/Test.scala new file mode 100644 index 0000000000..a75cb6c9eb --- /dev/null +++ b/test/files/run/t7741a/Test.scala @@ -0,0 +1,47 @@ +import java.io.{ByteArrayInputStream, FileOutputStream, BufferedOutputStream} +import java.util + +import java.io.File + +import scala.tools.partest.DirectTest + +object Test extends DirectTest { + + def code = "" + + override def show(): Unit = { + + val class1: Array[Byte] = GroovyInterfaceDump.dump() + val class2: Array[Byte] = GroovyInterface$1Dump.dump() + def writeFile(contents: Array[Byte], f: java.io.File): Unit = { + val out = new BufferedOutputStream(new FileOutputStream(f)) + try { + out.write(contents) + } finally out.close() + } + + val outdir = testOutput.jfile + + // interface GroovyInterface { + // + // // This is the line that causes scalac to choke. + // // It results in a GroovyInterface$1 class, which is a non-static inner class but it's constructor does not + // // include the implicit parameter that is the immediate enclosing instance. + // // See http://jira.codehaus.org/browse/GROOVY-7312 + // // + // // Scalac error: + // // [scalac] error: error while loading 1, class file '..../scala_groovy_interop/classes/com/example/groovy/GroovyInterface$1.class' is broken + // // [scalac] (class java.util.NoSuchElementException/head of empty list) + // final static def closure = { x -> "banana" } + // + // } + writeFile(GroovyInterfaceDump.dump(), new File(outdir, "GroovyInterface.class")) + writeFile(GroovyInterface$1Dump.dump(), new File(outdir, "GroovyInterface$1.class")) + compileCode("object Test { def foo(g: GroovyInterface) = g.toString }") + } + + def compileCode(code: String) = { + val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") + compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code) + } +} diff --git a/test/files/run/t7741b.check b/test/files/run/t7741b.check new file mode 100644 index 0000000000..a19e54aa3a --- /dev/null +++ b/test/files/run/t7741b.check @@ -0,0 +1,3 @@ +1. Don't refer to Inner +2. Refering to Inner +pos: NoPosition Class file for HasInner$Inner not found ERROR diff --git a/test/files/run/t7741b/HasInner.java b/test/files/run/t7741b/HasInner.java new file mode 100644 index 0000000000..a1d0d0d81a --- /dev/null +++ b/test/files/run/t7741b/HasInner.java @@ -0,0 +1,3 @@ +class HasInner { + class Inner {} +} diff --git a/test/files/run/t7741b/Test.scala b/test/files/run/t7741b/Test.scala new file mode 100644 index 0000000000..569ae6b679 --- /dev/null +++ b/test/files/run/t7741b/Test.scala @@ -0,0 +1,29 @@ +import java.io.File + +import scala.tools.partest.StoreReporterDirectTest + +object Test extends StoreReporterDirectTest { + + def code = "" + + override def show(): Unit = { + deleteClass("HasInner$Inner") + println("1. Don't refer to Inner") + compileCode("class Test { def test(x: HasInner) = x }") + assert(filteredInfos.isEmpty, filteredInfos) + println("2. Refering to Inner") + compileCode("class Test { def test(x: HasInner#Inner) = x }") + println(filteredInfos.mkString("\n")) + } + + def deleteClass(name: String) { + val classFile = new File(testOutput.path, name + ".class") + assert(classFile.exists) + assert(classFile.delete()) + } + + def compileCode(code: String) = { + val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") + compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code) + } +} 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/t9182.check b/test/files/run/t9182.check new file mode 100644 index 0000000000..80e8b6c558 --- /dev/null +++ b/test/files/run/t9182.check @@ -0,0 +1,3 @@ +constructor package +method A +object A diff --git a/test/files/run/t9182.scala b/test/files/run/t9182.scala new file mode 100644 index 0000000000..1768aa688e --- /dev/null +++ b/test/files/run/t9182.scala @@ -0,0 +1,12 @@ +// Main.scala +package object ops { + object A + def A(a: Any) = () +} + +object Test { + def main(args: Array[String]): Unit = { + val pack = scala.reflect.runtime.currentMirror.staticModule("ops.package") + println(pack.info.decls.toList.map(_.toString).sorted.mkString("\n")) + } +} 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/doc/html/HtmlDocletTest.scala b/test/junit/scala/tools/nsc/doc/html/HtmlDocletTest.scala new file mode 100644 index 0000000000..13a955b55d --- /dev/null +++ b/test/junit/scala/tools/nsc/doc/html/HtmlDocletTest.scala @@ -0,0 +1,22 @@ +package scala.tools.nsc.doc.html + +import org.junit.Test +import org.junit.Assert._ +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.AssertUtil._ + +@RunWith(classOf[JUnit4]) +class HtmlDocletTest { + @Test + def testSyntaxHighlightningUnicode() { + val in = "unicode: …" + + val out = SyntaxHigh(in).toString + + // SI-9038, this failed with + // "unicode: …" != "unicode: ¬タᆭ" + assertEquals(in, out) + } +} diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala index 895ad9d683..5a921a5eda 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableTest.scala @@ -33,10 +33,10 @@ class SymbolTableTest { import symbolTable._ symbolTable.definitions.init() val rootClass = symbolTable.rootMirror.RootClass - val fooSymbol = rootClass.newClassSymbol("Foo": TypeName, NoPosition, 0) + val fooSymbol = rootClass.newClassSymbol(TypeName("Foo"), NoPosition, 0) val fooType = new ClassInfoType(Nil, EmptyScope, fooSymbol) fooSymbol.info = fooType - val barSymbol = rootClass.newClassSymbol("Bar": TypeName, NoPosition, 0) + val barSymbol = rootClass.newClassSymbol(TypeName("Bar"), NoPosition, 0) val fooTypeRef = TypeRef(fooSymbol.owner.tpe, fooSymbol, Nil) val barType = new ClassInfoType(List(fooTypeRef), EmptyScope, barSymbol) barSymbol.info = barType 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 51633be440..6a6b1f8901 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 096108a21f..2ecfd23800 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 |