diff options
Diffstat (limited to 'src')
122 files changed, 1174 insertions, 2423 deletions
diff --git a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala b/src/compiler/scala/reflect/macros/runtime/Reifiers.scala index 8bb388be8f..7ec3457c6a 100644 --- a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala +++ b/src/compiler/scala/reflect/macros/runtime/Reifiers.scala @@ -60,15 +60,15 @@ trait Reifiers { def logFreeVars(symtab: SymbolTable): Unit = // logging free vars only when they are untyped prevents avalanches of duplicate messages symtab.syms map (sym => symtab.symDef(sym)) foreach { - case FreeTermDef(_, _, binding, _, origin) if universe.settings.logFreeTerms.value && binding.tpe == null => + case FreeTermDef(_, _, binding, _, origin) if universe.settings.logFreeTerms && binding.tpe == null => reporter.echo(position, "free term: %s %s".format(showRaw(binding), origin)) - case FreeTypeDef(_, _, binding, _, origin) if universe.settings.logFreeTypes.value && binding.tpe == null => + case FreeTypeDef(_, _, binding, _, origin) if universe.settings.logFreeTypes && binding.tpe == null => reporter.echo(position, "free type: %s %s".format(showRaw(binding), origin)) case _ => // do nothing } - if (universe.settings.logFreeTerms.value || universe.settings.logFreeTypes.value) + if (universe.settings.logFreeTerms || universe.settings.logFreeTypes) reification match { case ReifiedTree(_, _, symtab, _, _, _, _) => logFreeVars(symtab) case ReifiedType(_, _, symtab, _, _, _) => logFreeVars(symtab) diff --git a/src/compiler/scala/reflect/reify/Phases.scala b/src/compiler/scala/reflect/reify/Phases.scala index d43532090c..4572caeb36 100644 --- a/src/compiler/scala/reflect/reify/Phases.scala +++ b/src/compiler/scala/reflect/reify/Phases.scala @@ -25,7 +25,7 @@ trait Phases extends Reshape if (reifyDebug) println("[reshape phase]") tree = reshape.transform(tree) if (reifyDebug) println("[interlude]") - if (reifyDebug) println("reifee = " + (if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)) + if (reifyDebug) println("reifee = " + (if (settings.Xshowtrees || settings.XshowtreesCompact || settings.XshowtreesStringified) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)) if (reifyDebug) println("[calculate phase]") calculate.traverse(tree) diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala index 9cf069fe98..11857e2172 100644 --- a/src/compiler/scala/reflect/reify/Reifier.scala +++ b/src/compiler/scala/reflect/reify/Reifier.scala @@ -57,7 +57,7 @@ abstract class Reifier extends States val result = reifee match { case tree: Tree => - reifyTrace("reifying = ")(if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) + reifyTrace("reifying = ")(if (settings.Xshowtrees || settings.XshowtreesCompact || settings.XshowtreesStringified) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) reifyTrace("reifee is located at: ")(tree.pos) reifyTrace("universe = ")(universe) reifyTrace("mirror = ")(mirror) @@ -140,4 +140,4 @@ abstract class Reifier extends States throw new UnexpectedReificationException(defaultErrorPosition, "reification crashed", ex) } } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index d57188bf6e..7338df1f72 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -164,51 +164,30 @@ trait Extractors { } } - object FreeDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case FreeTermDef(uref, name, binding, flags, origin) => - Some((uref, name, binding, flags, origin)) - case FreeTypeDef(uref, name, binding, flags, origin) => - Some((uref, name, binding, flags, origin)) - case _ => - None - } - } - - object FreeTermDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case - ValDef(_, name, _, Apply( - Select(Select(uref1 @ Ident(_), build1), newFreeTerm), - List( - _, - _, - Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))), - Literal(Constant(origin: String))))) - if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm && - uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some((uref1, name, reifyBinding(tree), flags, origin)) - case _ => - None - } - } - - object FreeTypeDef { - def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match { - case - ValDef(_, name, _, Apply( - Select(Select(uref1 @ Ident(_), build1), newFreeType), - List( - _, - Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))), - Literal(Constant(origin: String))))) - if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeType == nme.newFreeType && - uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => - Some((uref1, name, reifyBinding(tree), flags, origin)) - case _ => - None + sealed abstract class FreeDefExtractor(acceptTerms: Boolean, acceptTypes: Boolean) { + def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = { + def acceptFreeTermFactory(name: Name) = { + (acceptTerms && name == nme.newFreeTerm) || + (acceptTypes && name == nme.newFreeType) + } + tree match { + case + ValDef(_, name, _, Apply( + Select(Select(uref1 @ Ident(_), build1), freeTermFactory), + _ :+ + Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))) :+ + Literal(Constant(origin: String)))) + if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && acceptFreeTermFactory(freeTermFactory) && + uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits => + Some((uref1, name, reifyBinding(tree), flags, origin)) + case _ => + None + } } } + object FreeDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = true) + object FreeTermDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = false) + object FreeTypeDef extends FreeDefExtractor(acceptTerms = false, acceptTypes = true) object FreeRef { def unapply(tree: Tree): Option[(Tree, TermName)] = tree match { diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala index c756a1b0d9..64f6758e73 100644 --- a/src/compiler/scala/tools/nsc/CompileClient.scala +++ b/src/compiler/scala/tools/nsc/CompileClient.scala @@ -26,12 +26,12 @@ class StandardCompileClient extends HasCompileSocket with CompileOutputCommon { val settings = new FscSettings(Console.println) val command = new OfflineCompilerCommand(args.toList, settings) val shutdown = settings.shutdown.value - val extraVmArgs = if (settings.preferIPv4.value) List("-D%s=true".format(preferIPv4Stack.key)) else Nil + val extraVmArgs = if (settings.preferIPv4) List("-D%s=true".format(preferIPv4Stack.key)) else Nil val vmArgs = settings.jvmargs.unparse ++ settings.defines.unparse ++ extraVmArgs val fscArgs = args.toList ++ command.extraFscArgs - if (settings.version.value) { + if (settings.version) { Console println versionMsg return true } diff --git a/src/compiler/scala/tools/nsc/Driver.scala b/src/compiler/scala/tools/nsc/Driver.scala index fc247600f6..fbfed6110f 100644 --- a/src/compiler/scala/tools/nsc/Driver.scala +++ b/src/compiler/scala/tools/nsc/Driver.scala @@ -41,7 +41,7 @@ abstract class Driver { command = new CompilerCommand(args.toList, ss) settings = command.settings - if (settings.version.value) { + if (settings.version) { reporter.echo(versionMsg) } else if (processSettingsHook()) { val compiler = newCompiler() diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c53d6cd11e..8b78ddd59d 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -221,7 +221,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def inform(msg: String) = reporter.echo(msg) override def globalError(msg: String) = reporter.error(NoPosition, msg) override def warning(msg: String) = - if (settings.fatalWarnings.value) globalError(msg) + if (settings.fatalWarnings) globalError(msg) else reporter.warning(NoPosition, msg) // Getting in front of Predef's asserts to supplement with more info. @@ -252,7 +252,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } @inline final def ifDebug(body: => Unit) { - if (settings.debug.value) + if (settings.debug) body } /** This is for WARNINGS which should reach the ears of scala developers @@ -262,7 +262,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) * to make them visually distinct. */ @inline final override def devWarning(msg: => String) { - if (settings.developer.value || settings.debug.value) + if (settings.developer || settings.debug) warning("!!! " + msg) else log("!!! " + msg) // such warnings always at least logged @@ -272,7 +272,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) msg + " in " + (currentTime - start) + "ms" def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg)) - def informProgress(msg: String) = if (settings.verbose.value) inform("[" + msg + "]") + def informProgress(msg: String) = if (settings.verbose) inform("[" + msg + "]") def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start)) def logError(msg: String, t: Throwable): Unit = () @@ -287,7 +287,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } @inline final override def debuglog(msg: => String) { - if (settings.debug.value) + if (settings.debug) log(msg) } @@ -332,7 +332,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - if (settings.verbose.value || settings.Ylogcp.value) { + if (settings.verbose || settings.Ylogcp) { // Uses the "do not truncate" inform informComplete("[search path for source files: " + classPath.sourcepaths.mkString(",") + "]") informComplete("[search path for class files: " + classPath.asClasspathString + "]") @@ -402,7 +402,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if ((unit ne null) && unit.exists) lastSeenSourceFile = unit.source - if (settings.debug.value && (settings.verbose.value || currentRun.size < 5)) + if (settings.debug && (settings.verbose || currentRun.size < 5)) inform("[running phase " + name + " on " + unit + "]") val unit0 = currentUnit @@ -736,7 +736,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val maxName = (0 /: phaseNames)(_ max _.length) val width = maxName min Limit val maxDesc = MaxCol - (width + 6) // descriptions not novels - val fmt = if (settings.verbose.value) s"%${maxName}s %2s %s%n" + val fmt = if (settings.verbose) s"%${maxName}s %2s %s%n" else s"%${width}.${width}s %2s %.${maxDesc}s%n" val line1 = fmt.format("phase name", "id", "description") @@ -1097,7 +1097,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val info3: List[String] = ( ( List("== Enclosing template or block ==", nodePrinters.nodeToString(enclosing).trim) ) ++ ( if (tpe eq null) Nil else List("== Expanded type of tree ==", typeDeconstruct.show(tpe)) ) - ++ ( if (!settings.debug.value) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) + ++ ( if (!settings.debug) Nil else List("== Current unit body ==", nodePrinters.nodeToString(currentUnit.body)) ) ++ ( List(errorMessage) ) ) @@ -1113,7 +1113,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def echoPhaseSummary(ph: Phase) = { /* Only output a summary message under debug if we aren't echoing each file. */ - if (settings.debug.value && !(settings.verbose.value || currentRun.size < 5)) + if (settings.debug && !(settings.verbose || currentRun.size < 5)) inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]") } @@ -1121,10 +1121,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) class ConditionalWarning(what: String, option: Settings#BooleanSetting) { val warnings = mutable.LinkedHashMap[Position, String]() def warn(pos: Position, msg: String) = - if (option.value) reporter.warning(pos, msg) + if (option) reporter.warning(pos, msg) else if (!(warnings contains pos)) warnings += ((pos, msg)) def summarize() = - if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings.value)) + if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) warning("there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name)) } @@ -1240,7 +1240,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def resetProjectClasses(root: Symbol): Unit = try { def unlink(sym: Symbol) = if (sym != NoSymbol) root.info.decls.unlink(sym) - if (settings.verbose.value) inform("[reset] recursing in "+root) + if (settings.verbose) inform("[reset] recursing in "+root) val toReload = mutable.Set[String]() for (sym <- root.info.decls) { if (sym.isInitialized && clearOnNextRun(sym)) @@ -1260,7 +1260,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) for (fullname <- toReload) classPath.findClass(fullname) match { case Some(classRep) => - if (settings.verbose.value) inform("[reset] reinit "+fullname) + if (settings.verbose) inform("[reset] reinit "+fullname) loaders.initializeFromClassPath(root, classRep) case _ => } @@ -1453,7 +1453,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } def reportCompileErrors() { - if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings.value) + if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings) globalError("No warnings can be incurred under -Xfatal-warnings.") if (reporter.hasErrors) { @@ -1492,7 +1492,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) catch { case ex: Throwable => - val shown = if (settings.verbose.value) + val shown = if (settings.verbose) stackTraceString(ex) else stackTraceHeadString(ex) // note that error stacktraces do not print in fsc @@ -1526,14 +1526,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (shouldWriteIcode) { // Write *.icode files when -Xprint-icode or -Xprint:<some-optimiz-phase> was given. writeICode() - } else if ((settings.Xprint containsPhase globalPhase) || settings.printLate.value && runIsAt(cleanupPhase)) { + } else if ((settings.Xprint containsPhase globalPhase) || settings.printLate && runIsAt(cleanupPhase)) { // print trees - if (settings.Xshowtrees.value || settings.XshowtreesCompact.value || settings.XshowtreesStringified.value) nodePrinters.printAll() + if (settings.Xshowtrees || settings.XshowtreesCompact || settings.XshowtreesStringified) nodePrinters.printAll() else printAllUnits() } // print the symbols presently attached to AST nodes - if (settings.Yshowsyms.value) + if (settings.Yshowsyms) trackerFactory.snapshot() // print members @@ -1552,7 +1552,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) runCheckers() // output collected statistics - if (settings.Ystatistics.value) + if (settings.Ystatistics) statistics.print(phase) advancePhase() @@ -1697,7 +1697,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) informProgress("wrote " + file) } catch { case ex: IOException => - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() globalError("could not write file " + file) } }) diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala index 00c6c37dfd..9f6f483ad8 100644 --- a/src/compiler/scala/tools/nsc/Main.scala +++ b/src/compiler/scala/tools/nsc/Main.scala @@ -17,7 +17,7 @@ class MainClass extends Driver with EvalLoop { override def newCompiler(): Global = Global(settings, reporter) override def doCompile(compiler: Global) { - if (settings.resident.value) resident(compiler) + if (settings.resident) resident(compiler) else super.doCompile(compiler) } } diff --git a/src/compiler/scala/tools/nsc/MainTokenMetric.scala b/src/compiler/scala/tools/nsc/MainTokenMetric.scala index 584805b37e..e2893204e0 100644 --- a/src/compiler/scala/tools/nsc/MainTokenMetric.scala +++ b/src/compiler/scala/tools/nsc/MainTokenMetric.scala @@ -42,7 +42,7 @@ object MainTokenMetric { tokenMetric(compiler, command.files) } catch { case ex @ FatalError(msg) => - if (command.settings.debug.value) + if (command.settings.debug) ex.printStackTrace() reporter.error(null, "fatal error: " + msg) } diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index 821e88e52e..5f8bc71449 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -95,7 +95,7 @@ class ScriptRunner extends HasCompileSocket { settings.outdir.value = compiledPath.path - if (settings.nc.value) { + if (settings.nc) { /* Setting settings.script.value informs the compiler this is not a * self contained compilation unit. */ @@ -114,7 +114,7 @@ class ScriptRunner extends HasCompileSocket { * not take place until there are no non-daemon threads running. Tickets #1955, #2006. */ util.waitingForThreads { - if (settings.save.value) { + if (settings.save) { val jarFile = jarFileFor(scriptFile) def jarOK = jarFile.canRead && (jarFile isFresher File(scriptFile)) diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 602366a201..caab299635 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -32,7 +32,7 @@ abstract class NodePrinters { } trait DefaultPrintAST extends PrintAST { - val printPos = settings.Xprintpos.value || settings.Yposdebug.value + val printPos = settings.Xprintpos || settings.Yposdebug def showNameAndPos(tree: NameTree) = showPosition(tree) + showName(tree.name) def showDefTreeName(tree: DefTree) = showName(tree.name) @@ -100,9 +100,9 @@ abstract class NodePrinters { def stringify(tree: Tree): String = { buf.clear() - if (settings.XshowtreesStringified.value) buf.append(tree.toString + EOL) - if (settings.XshowtreesCompact.value) { - buf.append(showRaw(tree, printIds = settings.uniqid.value, printTypes = settings.printtypes.value)) + if (settings.XshowtreesStringified) buf.append(tree.toString + EOL) + if (settings.XshowtreesCompact) { + buf.append(showRaw(tree, printIds = settings.uniqid, printTypes = settings.printtypes)) } else { level = 0 traverse(tree) diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index 66d75969e9..beab801edf 100644 --- a/src/compiler/scala/tools/nsc/ast/Positions.scala +++ b/src/compiler/scala/tools/nsc/ast/Positions.scala @@ -25,6 +25,6 @@ trait Positions extends scala.reflect.internal.Positions { } override protected[this] lazy val posAssigner: PosAssigner = - if (settings.Yrangepos.value && settings.debug.value || settings.Yposdebug.value) new ValidatingPosAssigner + if (settings.Yrangepos && settings.debug || settings.Yposdebug) new ValidatingPosAssigner else new DefaultPosAssigner } diff --git a/src/compiler/scala/tools/nsc/ast/Printers.scala b/src/compiler/scala/tools/nsc/ast/Printers.scala index 7fefb2ce0c..72538bac08 100644 --- a/src/compiler/scala/tools/nsc/ast/Printers.scala +++ b/src/compiler/scala/tools/nsc/ast/Printers.scala @@ -200,15 +200,15 @@ trait Printers extends scala.reflect.internal.Printers { this: Global => override def printTree(tree: Tree) { print(safe(tree)) } } - def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value) - def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value) + def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds) + def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds) def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true) def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer) def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer) override def newTreePrinter(writer: PrintWriter): TreePrinter = - if (settings.Ycompacttrees.value) newCompactTreePrinter(writer) + if (settings.Ycompacttrees) newCompactTreePrinter(writer) else newStandardTreePrinter(writer) override def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream)) override def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter)) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 68e198d071..7671912651 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2085,7 +2085,7 @@ self => val name = ident() var bynamemod = 0 val tpt = - if (settings.YmethodInfer.value && !owner.isTypeName && in.token != COLON) { + if (settings.YmethodInfer && !owner.isTypeName && in.token != COLON) { TypeTree() } else { // XX-METHOD-INFER accept(COLON) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index b485e862fd..eb31f7a66e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -446,7 +446,7 @@ trait Scanners extends ScannersCommon { * there a realistic situation where one would need it? */ if (isDigit(ch)) { - if (settings.future.value) syntaxError("Non-zero numbers may not have a leading zero.") + if (settings.future) syntaxError("Non-zero numbers may not have a leading zero.") else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.") } base = 8 @@ -990,7 +990,7 @@ trait Scanners extends ScannersCommon { /* As of scala 2.11, it isn't a number unless c here is a digit, so * settings.future.value excludes the rest of the logic. */ - if (settings.future.value && !isDigit(c)) + if (settings.future && !isDigit(c)) return setStrVal() val isDefinitelyNumber = (c: @switch) match { @@ -1217,7 +1217,7 @@ trait Scanners extends ScannersCommon { */ class SourceFileScanner(val source: SourceFile) extends Scanner { val buf = source.content - override val decodeUni: Boolean = !settings.nouescape.value + override val decodeUni: Boolean = !settings.nouescape // suppress warnings, throw exception on errors def deprecationWarning(off: Offset, msg: String): Unit = () diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 7cf5a07291..80d70e6428 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -32,7 +32,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse else newUnitParser(unit).smartParse() } - if (settings.Yrangepos.value && !reporter.hasErrors) + if (settings.Yrangepos && !reporter.hasErrors) validatePositions(unit.body) } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 89682e91d2..94fbba8066 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -331,7 +331,7 @@ trait BasicBlocks { assert(!closed || ignore, this) if (ignore) { - if (settings.debug.value) { + if (settings.debug) { /* Trying to pin down what it's likely to see after a block has been * put into ignore mode so we hear about it if there's a problem. */ @@ -405,11 +405,11 @@ trait BasicBlocks { * is discovered to be unreachable. */ def killIf(cond: Boolean) { - if (!settings.YdisableUnreachablePrevention.value && cond) { + if (!settings.YdisableUnreachablePrevention && cond) { debuglog(s"Killing block $this") assert(instructionList.isEmpty, s"Killing a non empty block $this") // only checked under debug because fetching predecessor list is moderately expensive - if (settings.debug.value) + if (settings.debug) assert(predecessors.isEmpty, s"Killing block $this which is referred to from ${predecessors.mkString}") close() diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 8ba75fbb46..31028e64d3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -39,7 +39,7 @@ abstract class GenICode extends SubComponent { override def newPhase(prev: Phase) = new ICodePhase(prev) @inline private def debugassert(cond: => Boolean, msg: => Any) { - if (settings.debug.value) + if (settings.debug) assert(cond, msg) } @@ -129,7 +129,7 @@ abstract class GenICode extends SubComponent { case Return(_) => () case EmptyTree => globalError("Concrete method has no definition: " + tree + ( - if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")" + if (settings.debug) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")" else "") ) case _ => if (ctx1.bb.isEmpty) @@ -710,7 +710,7 @@ abstract class GenICode extends SubComponent { debuglog("BOX : " + fun.symbol.fullName) val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe)) val nativeKind = toTypeKind(expr.tpe) - if (settings.Xdce.value) { + if (settings.Xdce) { // we store this boxed value to a local, even if not really needed. // boxing optimization might use it, and dead code elimination will // take care of unnecessary stores @@ -1483,7 +1483,7 @@ abstract class GenICode extends SubComponent { if (mustUseAnyComparator) { // when -optimise is on we call the @inline-version of equals, found in ScalaRunTime val equalsMethod = - if (!settings.optimise.value) { + if (!settings.optimise) { def default = platform.externalEquals platform match { case x: JavaPlatform => @@ -1507,7 +1507,7 @@ abstract class GenICode extends SubComponent { val ctx2 = genLoad(r, ctx1, ObjectReference) val branchesReachable = !ctx2.bb.ignore ctx2.bb.emitOnly( - CALL_METHOD(equalsMethod, if (settings.optimise.value) Dynamic else Static(onInstance = false)), + CALL_METHOD(equalsMethod, if (settings.optimise) Dynamic else Static(onInstance = false)), CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL) ) branchesReachable @@ -2032,7 +2032,7 @@ abstract class GenICode extends SubComponent { // Generate the catch-all exception handler that deals with uncaught exceptions coming // from the try or exception handlers. It catches the exception, runs the finally code, then rethrows // the exception - if (settings.YdisableUnreachablePrevention.value || !outerCtx.bb.ignore) { + if (settings.YdisableUnreachablePrevention || !outerCtx.bb.ignore) { if (finalizer != EmptyTree) { val exh = outerCtx.newExceptionHandler(NoSymbol, finalizer.pos) // finalizer covers exception handlers this.addActiveHandler(exh) // .. and body aswell diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index b7b07a579f..0cdf629ce1 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -94,7 +94,7 @@ abstract class ICodeCheckers { } def checkICodes(): Unit = { - if (settings.verbose.value) + if (settings.verbose) println("[[consistency check at the beginning of phase " + globalPhase.name + "]]") classes.values foreach check } @@ -444,7 +444,7 @@ abstract class ICodeCheckers { def checkBool(cond: Boolean, msg: String) = if (!cond) icodeError(msg) - if (settings.debug.value) { + if (settings.debug) { log("PC: " + instr) log("stack: " + stack) log("================") diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala index e2d387c65d..3f2141782a 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala @@ -35,7 +35,7 @@ abstract class ICodes extends AnyRef /** Debugging flag */ def shouldCheckIcode = settings.check contains global.genicode.phaseName - def checkerDebug(msg: String) = if (shouldCheckIcode && global.settings.debug.value) println(msg) + def checkerDebug(msg: String) = if (shouldCheckIcode && global.settings.debug) println(msg) /** The ICode linearizer. */ val linearizer: Linearizer = settings.Xlinearizer.value match { diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index e471f4256b..c1cda2c863 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -61,7 +61,7 @@ trait Members { startBlock = newBlock() def removeBlock(b: BasicBlock) { - if (settings.debug.value) { + if (settings.debug) { // only do this sanity check when debug is turned on because it's moderately expensive val referers = blocks filter (_.successors contains b) assert(referers.isEmpty, s"Trying to removing block $b (with preds ${b.predecessors.mkString}) but it is still refered to from block(s) ${referers.mkString}") @@ -172,6 +172,7 @@ trait Members { var returnType: TypeKind = _ var recursive: Boolean = false var bytecodeHasEHs = false // set by ICodeReader only, used by Inliner to prevent inlining (SI-6188) + var bytecodeHasInvokeDynamic = false // set by ICodeReader only, used by Inliner to prevent inlining until we have proper invoke dynamic support /** local variables and method parameters */ var locals: List[Local] = Nil diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index d8aac8e9db..ff118be3c4 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -394,6 +394,25 @@ trait Opcodes { self: ICodes => override def category = mthdsCat } + + /** + * A place holder entry that allows us to parse class files with invoke dynamic + * instructions. Because the compiler doesn't yet really understand the + * behavior of invokeDynamic, this op acts as a poison pill. Any attempt to analyze + * this instruction will cause a failure. The only optimization that + * should ever look at non-Scala generated icode is the inliner, and it + * has been modified to not examine any method with invokeDynamic + * instructions. So if this poison pill ever causes problems then + * there's been a serious misunderstanding + */ + // TODO do the real thing + case class INVOKE_DYNAMIC(poolEntry: Char) extends Instruction { + private def error = sys.error("INVOKE_DYNAMIC is not fully implemented and should not be analyzed") + override def consumed = error + override def produced = error + override def producedTypes = error + override def category = error + } case class BOX(boxType: TypeKind) extends Instruction { assert(boxType.isValueType && (boxType ne UNIT)) // documentation diff --git a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala index 5b47e3cfff..1fe33f78e7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Printers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Printers.scala @@ -110,7 +110,7 @@ trait Printers { self: ICodes => print(bb.label) if (bb.loopHeader) print("[loop header]") print(": ") - if (settings.debug.value) print("pred: " + bb.predecessors + " succs: " + bb.successors + " flags: " + bb.flagsString) + if (settings.debug) print("pred: " + bb.predecessors + " succs: " + bb.successors + " flags: " + bb.flagsString) indent(); println() bb.toList foreach printInstruction undent(); println() diff --git a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala index e92e61c957..10d57df4a3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Repository.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Repository.scala @@ -39,7 +39,7 @@ trait Repository { } catch { case e: Throwable => // possible exceptions are MissingRequirementError, IOException and TypeError -> no better common supertype log("Failed to load %s. [%s]".format(sym.fullName, e.getMessage)) - if (settings.debug.value) { e.printStackTrace } + if (settings.debug) { e.printStackTrace } false } diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 152a11ab1a..338a07c872 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -199,7 +199,7 @@ abstract class CopyPropagation { override def run() { forwardAnalysis(blockTransfer) - if (settings.debug.value) { + if (settings.debug) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(in(b) != lattice.bottom, "Block " + b + " in " + this.method + " has input equal to bottom -- not visited?")) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala index 14b57f287f..60f7857d0c 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/Liveness.scala @@ -74,7 +74,7 @@ abstract class Liveness { override def run() { backwardAnalysis(blockTransfer) - if (settings.debug.value) { + if (settings.debug) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(lattice.bottom != in(b), "Block " + b + " in " + this.method + " has input equal to bottom -- not visited?")) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala index 2d29e6b14f..26b7bc50d8 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/ReachingDefinitions.scala @@ -51,7 +51,7 @@ abstract class ReachingDefinitions { // it'd be nice not to call zip with mismatched sequences because // it makes it harder to spot the real problems. val result = (a.stack, b.stack).zipped map (_ ++ _) - if (settings.debug.value && (a.stack.length != b.stack.length)) + if (settings.debug && (a.stack.length != b.stack.length)) devWarning(s"Mismatched stacks in ReachingDefinitions#lub2: ${a.stack}, ${b.stack}, returning $result") result } @@ -141,7 +141,7 @@ abstract class ReachingDefinitions { override def run() { forwardAnalysis(blockTransfer) - if (settings.debug.value) { + if (settings.debug) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(lattice.bottom != in(b), "Block " + b + " in " + this.method + " has input equal to bottom -- not visited? " + in(b) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 227c1064ea..57380db7e7 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -136,7 +136,7 @@ abstract class TypeFlowAnalysis { // icodes.lubs0 = 0 forwardAnalysis(blockTransfer) timer.stop - if (settings.debug.value) { + if (settings.debug) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(visited.contains(b), "Block " + b + " in " + this.method + " has input equal to bottom -- not visited? .." + visited)) @@ -167,7 +167,7 @@ abstract class TypeFlowAnalysis { val bindings = out.vars val stack = out.stack - if (settings.debug.value) { + if (settings.debug) { // Console.println("[before] Stack: " + stack); // Console.println(i); } @@ -367,7 +367,7 @@ abstract class TypeFlowAnalysis { preCandidates += rc._2.bb } - if (settings.debug.value) { + if (settings.debug) { for(b <- callerLin; if (b != method.startBlock) && preCandidates(b)) { assert(visited.contains(b), "Block " + b + " in " + this.method + " has input equal to bottom -- not visited? .." + visited) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 78fb109b42..66a58870cc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -86,10 +86,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { override def run() { - if (settings.debug.value) + if (settings.debug) inform("[running phase " + name + " on icode]") - if (settings.Xdce.value) + if (settings.Xdce) for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) { log(s"Optimizer eliminated ${sym.fullNameString}") icodes.classes -= sym @@ -804,7 +804,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // without it. This is particularly bad because the availability of // generic information could disappear as a consequence of a seemingly // unrelated change. - settings.Ynogenericsig.value + settings.Ynogenericsig || sym.isArtifact || sym.isLiftedMethod || sym.isBridge @@ -834,7 +834,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { catch { case _: Throwable => false } } - if (settings.Xverify.value) { + if (settings.Xverify) { // Run the signature parser to catch bogus signatures. val isValidSignature = wrap { // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser) @@ -1362,7 +1362,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { for (constructor <- c.lookupStaticCtor) { addStaticInit(Some(constructor)) } - val skipStaticForwarders = (c.symbol.isInterface || settings.noForwarders.value) + val skipStaticForwarders = (c.symbol.isInterface || settings.noForwarders) if (!skipStaticForwarders) { val lmoc = c.symbol.companionModule // add static forwarders if there are no name conflicts; see bugs #363 and #1735 @@ -2251,16 +2251,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // info calls so that types are up to date; erasure may add lateINTERFACE to traits hostSymbol.info ; methodOwner.info - def isInterfaceCall(sym: Symbol) = ( - sym.isInterface && methodOwner != ObjectClass + def needsInterfaceCall(sym: Symbol) = ( + sym.isInterface || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass) ) // whether to reference the type of the receiver or - // the type of the method owner (if not an interface!) + // the type of the method owner val useMethodOwner = ( style != Dynamic - || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol) || hostSymbol.isBottomClass + || methodOwner == ObjectClass ) val receiver = if (useMethodOwner) methodOwner else hostSymbol val jowner = javaName(receiver) @@ -2283,11 +2283,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } style match { - case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype) - case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype) - case Dynamic if isInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype) - case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype) - case SuperCall(_) => + case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype) + case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype) + case Dynamic if needsInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype) + case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype) + case SuperCall(_) => dbg("invokespecial") jcode.invokespecial(jowner, jname, jtype) initModule() @@ -3220,7 +3220,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { val detour = computeDetour rephraseGotos(detour) - if (settings.debug.value) { + if (settings.debug) { 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.") @@ -3273,7 +3273,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } // remove the unusued exception handler references - if (settings.debug.value) + if (settings.debug) for (exh <- unusedExceptionHandlers) debuglog(s"eliding exception handler $exh because it does not cover any reachable blocks") m.exh = m.exh filterNot unusedExceptionHandlers @@ -3287,7 +3287,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { def normalize(m: IMethod) { if(!m.hasCode) { return } collapseJumpOnlyBlocks(m) - if (settings.optimise.value) + if (settings.optimise) elimUnreachableBlocks(m) icodes checkValid m } diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 8f439fc800..aaf2c55dcd 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -82,7 +82,7 @@ abstract class ClosureElimination extends SubComponent { * */ class ClosureElim { - def analyzeClass(cls: IClass): Unit = if (settings.Xcloselim.value) { + def analyzeClass(cls: IClass): Unit = if (settings.Xcloselim) { log(s"Analyzing ${cls.methods.size} methods in $cls.") cls.methods foreach { m => analyzeMethod(m) diff --git a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala index 7187bacb06..ff93206ffd 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ConstantOptimization.scala @@ -41,7 +41,7 @@ abstract class ConstantOptimization extends SubComponent { def name = phaseName override def apply(c: IClass) { - if (settings.YconstOptimization.value) { + if (settings.YconstOptimization) { val analyzer = new ConstantOptimizer analyzer optimizeClass c } diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index 7042d7a042..1026e95fac 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -33,7 +33,7 @@ abstract class DeadCodeElimination extends SubComponent { val dce = new DeadCode() override def apply(c: IClass) { - if (settings.Xdce.value) + if (settings.Xdce) dce.analyzeClass(c) } } diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index dcf0590951..cecabda171 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -88,7 +88,7 @@ abstract class InlineExceptionHandlers extends SubComponent { /** Apply exception handler inlining to a class */ override def apply(c: IClass): Unit = - if (settings.inlineHandlers.value) { + if (settings.inlineHandlers) { val startTime = System.currentTimeMillis currentClass = c diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 555c79e75e..a6eedbd07e 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -265,7 +265,7 @@ abstract class Inliners extends SubComponent { } def analyzeClass(cls: IClass): Unit = - if (settings.inline.value) { + if (settings.inline) { inlineLog("class", s"${cls.symbol.decodedName}", s"analyzing ${cls.methods.size} methods in $cls") this.currentIClazz = cls @@ -319,7 +319,7 @@ abstract class Inliners extends SubComponent { * */ def analyzeMethod(m: IMethod): Unit = { // m.normalize - if (settings.debug.value) + if (settings.debug) inlineLog("caller", ownedName(m.symbol), "in " + m.symbol.owner.fullName) val sizeBeforeInlining = m.code.blockCount @@ -383,7 +383,7 @@ abstract class Inliners extends SubComponent { def warnNoInline(reason: String): Boolean = { def msg = "Could not inline required method %s because %s.".format(i.method.unexpandedName.decode, reason) - if (settings.debug.value) + if (settings.debug) inlineLog("fail", i.method.fullName, reason) if (shouldWarn) warn(i.pos, msg) @@ -935,7 +935,7 @@ abstract class Inliners extends SubComponent { // add exception handlers of the callee caller addHandlers (inc.handlers map translateExh) assert(pending.isEmpty, "Pending NEW elements: " + pending) - if (settings.debug.value) icodes.checkValid(caller.m) + if (settings.debug) icodes.checkValid(caller.m) } def isStampedForInlining(stackLength: Int): InlineSafetyInfo = { @@ -958,6 +958,7 @@ abstract class Inliners extends SubComponent { if(isInlineForbidden) { rs ::= "is annotated @noinline" } if(inc.isSynchronized) { rs ::= "is synchronized method" } if(inc.m.bytecodeHasEHs) { rs ::= "bytecode contains exception handlers / finally clause" } // SI-6188 + if(inc.m.bytecodeHasInvokeDynamic) { rs ::= "bytecode contains invoke dynamic" } if(rs.isEmpty) null else rs.mkString("", ", and ", "") } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index cf40fe90fa..f1b1d1a9a7 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -755,13 +755,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val pos = in.currentPos val name = identForType() val (statics, body) = typeBody(AT, name) - def getValueMethodType(tree: Tree) = tree match { - case DefDef(_, nme.value, _, _, tpt, _) => Some(tpt.duplicate) - case _ => None - } - var templ = makeTemplate(annotationParents, body) - for (stat <- templ.body; tpt <- getValueMethodType(stat)) - templ = makeTemplate(annotationParents, makeConstructor(List(tpt)) :: templ.body) + val templ = makeTemplate(annotationParents, body) addCompanionObject(statics, atPos(pos) { ClassDef(mods, name, List(), templ) }) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 71b97e86a6..a591482392 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -62,7 +62,7 @@ trait Plugins { def withPlug = plug :: pick(tail, plugNames + plug.name, phaseNames ++ plugPhaseNames) lazy val commonPhases = phaseNames intersect plugPhaseNames - def note(msg: String): Unit = if (settings.verbose.value) inform(msg format plug.name) + def note(msg: String): Unit = if (settings.verbose) inform(msg format plug.name) def fail(msg: String) = { note(msg) ; withoutPlug } if (plugNames contains plug.name) diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index 44670ea578..a67c207820 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -43,7 +43,7 @@ abstract class AbstractReporter extends Reporter { if (!hidden || isPromptSet) { severity.count += 1 display(pos, msg, severity) - } else if (settings.debug.value) { + } else if (settings.debug) { severity.count += 1 display(pos, "[ suppressed ] " + msg, severity) } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 61ac07d18f..22482bf1b6 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -31,7 +31,7 @@ abstract class SymbolLoaders { } protected def signalError(root: Symbol, ex: Throwable) { - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() globalError(ex.getMessage() match { case null => "i/o error while loading " + root.name case msg => "error while loading " + root.name + ", " + msg @@ -136,10 +136,10 @@ abstract class SymbolLoaders { ((classRep.binary, classRep.source) : @unchecked) match { case (Some(bin), Some(src)) if platform.needCompile(bin, src) && !binaryOnly(owner, classRep.name) => - if (settings.verbose.value) inform("[symloader] picked up newer source file for " + src.path) + if (settings.verbose) inform("[symloader] picked up newer source file for " + src.path) global.loaders.enterToplevelsFromSource(owner, classRep.name, src) case (None, Some(src)) => - if (settings.verbose.value) inform("[symloader] no class, picked up source file for " + src.path) + if (settings.verbose) inform("[symloader] no class, picked up source file for " + src.path) global.loaders.enterToplevelsFromSource(owner, classRep.name, src) case (Some(bin), _) => global.loaders.enterClassAndModule(owner, classRep.name, platform.newClassLoader(bin)) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala index 035244e421..daaa625164 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala @@ -127,7 +127,7 @@ trait SymbolTrackers { else " (" + Flags.flagsToString(masked) + ")" } def symString(sym: Symbol) = ( - if (settings.debug.value && sym.hasCompleteInfo) { + if (settings.debug && sym.hasCompleteInfo) { val s = sym.defString take 240 if (s.length == 240) s + "..." else s } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 1206748b24..a8a47205dd 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -12,9 +12,11 @@ import java.lang.Integer.toHexString import scala.collection.{ mutable, immutable } import scala.collection.mutable.{ ListBuffer, ArrayBuffer } import scala.annotation.switch +import scala.reflect.internal.{ JavaAccFlags } import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs} import scala.tools.nsc.io.AbstractFile + /** This abstract class implements a class file parser. * * @author Martin Odersky @@ -23,6 +25,7 @@ import scala.tools.nsc.io.AbstractFile abstract class ClassfileParser { val global: Global import global._ + import definitions._ import scala.reflect.internal.ClassfileConstants._ import Flags._ @@ -40,21 +43,41 @@ abstract class ClassfileParser { protected var classTParams = Map[Name,Symbol]() protected var srcfile0 : Option[AbstractFile] = None protected def moduleClass: Symbol = staticModule.moduleClass + private var sawPrivateConstructor = false + + private def ownerForFlags(jflags: JavaAccFlags) = if (jflags.isStatic) moduleClass else clazz def srcfile = srcfile0 + private def optimized = global.settings.optimise.value private def currentIsTopLevel = !(currentClass.decodedName containsChar '$') + // u1, u2, and u4 are what these data types are called in the JVM spec. + // They are an unsigned byte, unsigned char, and unsigned int respectively. + // We bitmask u1 into an Int to make sure it's 0-255 (and u1 isn't used + // for much beyond tags) but leave u2 alone as it's already unsigned. + protected final def u1(): Int = in.nextByte & 0xFF + protected final def u2(): Char = in.nextChar + protected final def u4(): Int = in.nextInt + + private def readInnerClassFlags() = readClassFlags() + private def readClassFlags() = JavaAccFlags classFlags u2 + private def readMethodFlags() = JavaAccFlags methodFlags u2 + private def readFieldFlags() = JavaAccFlags fieldFlags u2 + private def readTypeName() = readName().toTypeName + private def readName() = pool getName u2 + private def readType() = pool getType u2 + private object unpickler extends scala.reflect.internal.pickling.UnPickler { val global: ClassfileParser.this.global.type = ClassfileParser.this.global } private def handleMissing(e: MissingRequirementError) = { - if (settings.debug.value) e.printStackTrace + if (settings.debug) e.printStackTrace throw new IOException("Missing dependency '" + e.req + "', required by " + in.file) } private def handleError(e: Exception) = { - if (settings.debug.value) e.printStackTrace() + if (settings.debug) e.printStackTrace() throw new IOException("class file '%s' is broken\n(%s/%s)".format( in.file, e.getClass, @@ -106,65 +129,60 @@ abstract class ClassfileParser { } private def parseHeader() { - val magic = in.nextInt + val magic = u4 if (magic != JAVA_MAGIC) - throw new IOException("class file '" + in.file + "' " - + "has wrong magic number 0x" + toHexString(magic) - + ", should be 0x" + toHexString(JAVA_MAGIC)) - val minorVersion = in.nextChar.toInt - val majorVersion = in.nextChar.toInt - if ((majorVersion < JAVA_MAJOR_VERSION) || - ((majorVersion == JAVA_MAJOR_VERSION) && - (minorVersion < JAVA_MINOR_VERSION))) - throw new IOException("class file '" + in.file + "' " - + "has unknown version " - + majorVersion + "." + minorVersion - + ", should be at least " - + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION) + abort(s"class file ${in.file} has wrong magic number 0x${toHexString(magic)}") + + val minor, major = u2 + if (major < JAVA_MAJOR_VERSION || major == JAVA_MAJOR_VERSION && minor < JAVA_MINOR_VERSION) + abort(s"class file ${in.file} has unknown version $major.$minor, should be at least $JAVA_MAJOR_VERSION.$JAVA_MINOR_VERSION") } class ConstantPool { - private val len = in.nextChar - private val starts = new Array[Int](len) - private val values = new Array[AnyRef](len) + private val len = u2 + private val starts = new Array[Int](len) + private val values = new Array[AnyRef](len) private val internalized = new Array[Name](len) { var i = 1 while (i < starts.length) { starts(i) = in.bp i += 1 - (in.nextByte.toInt: @switch) match { - case CONSTANT_UTF8 | CONSTANT_UNICODE => - in.skip(in.nextChar) - case CONSTANT_CLASS | CONSTANT_STRING => - in.skip(2) - case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF - | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT => - in.skip(4) - case CONSTANT_LONG | CONSTANT_DOUBLE => - in.skip(8) - i += 1 - case _ => - errorBadTag(in.bp - 1) + (u1.toInt: @switch) match { + case CONSTANT_UTF8 | CONSTANT_UNICODE => in skip u2 + case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE => in skip 2 + case CONSTANT_METHODHANDLE => in skip 3 + case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF => in skip 4 + case CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT => in skip 4 + case CONSTANT_INVOKEDYNAMIC => in skip 4 + case CONSTANT_LONG | CONSTANT_DOUBLE => in skip 8 ; i += 1 + case _ => errorBadTag(in.bp - 1) } } } - /** Return the name found at given index. */ - def getName(index: Int): Name = { - if (index <= 0 || len <= index) - errorBadIndex(index) + def recordAtIndex[T <: AnyRef](value: T, idx: Int): T = { + values(idx) = value + value + } - values(index) match { + def firstExpecting(index: Int, expected: Int): Int = { + val start = starts(index) + val first = in.buf(start).toInt + if (first == expected) start + 1 + else this errorBadTag start + } + + /** Return the name found at given index. */ + def getName(index: Int): Name = ( + if (index <= 0 || len <= index) errorBadIndex(index) + else values(index) match { case name: Name => name - case null => - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val name = newTermName(in.buf, start + 3, in.getChar(start + 1)) - values(index) = name - name + case _ => + val start = firstExpecting(index, CONSTANT_UTF8) + recordAtIndex(newTermName(in.buf, start + 2, in.getChar(start)), index) } - } + ) /** Return the name found at given index in the constant pool, with '/' replaced by '.'. */ def getExternalName(index: Int): Name = { @@ -179,28 +197,23 @@ abstract class ClassfileParser { def getClassSymbol(index: Int): Symbol = { if (index <= 0 || len <= index) errorBadIndex(index) - var c = values(index).asInstanceOf[Symbol] - if (c eq null) { - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) - val name = getExternalName(in.getChar(start + 1)) - if (nme.isModuleName(name)) - c = rootMirror.getModuleByName(name.dropModule) - else - c = classNameToSymbol(name) - - values(index) = c + values(index) match { + case sym: Symbol => sym + case _ => + val result = getClassName(index) match { + case name if nme.isModuleName(name) => rootMirror getModuleByName name.dropModule + case name => classNameToSymbol(name) + } + recordAtIndex(result, index) } - c } /** Return the external name of the class info structure found at 'index'. * Use 'getClassSymbol' if the class is sure to be a top-level class. */ def getClassName(index: Int): Name = { - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) - getExternalName(in.getChar(start + 1)) + val start = firstExpecting(index, CONSTANT_CLASS) + getExternalName(in getChar start) } /** Return the symbol of the class member at `index`. @@ -276,94 +289,66 @@ abstract class ClassfileParser { */ private def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = { if (index <= 0 || len <= index) errorBadIndex(index) - var p = values(index).asInstanceOf[(Name, Type)] - if (p eq null) { - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_NAMEANDTYPE) errorBadTag(start) - val name = getName(in.getChar(start + 1).toInt) - // create a dummy symbol for method types - val dummySym = ownerTpe.typeSymbol.newMethod(name.toTermName, ownerTpe.typeSymbol.pos) - var tpe = getType(dummySym, in.getChar(start + 3).toInt) - - // fix the return type, which is blindly set to the class currently parsed - if (name == nme.CONSTRUCTOR) - tpe match { - case MethodType(formals, restpe) => - tpe = MethodType(formals, ownerTpe) + (values(index): @unchecked) match { + case p: ((Name, Type)) => p + case _ => + val start = firstExpecting(index, CONSTANT_NAMEANDTYPE) + val name = getName(in.getChar(start).toInt) + // create a dummy symbol for method types + val dummy = ownerTpe.typeSymbol.newMethod(name.toTermName, ownerTpe.typeSymbol.pos) + val tpe = getType(dummy, in.getChar(start + 2).toInt) + // fix the return type, which is blindly set to the class currently parsed + val restpe = tpe match { + case MethodType(formals, _) if name == nme.CONSTRUCTOR => MethodType(formals, ownerTpe) + case _ => tpe } - - p = (name, tpe) + ((name, restpe)) } - p } /** Return the type of a class constant entry. Since * arrays are considered to be class types, they might * appear as entries in 'newarray' or 'cast' opcodes. */ - def getClassOrArrayType(index: Int): Type = { + def getClassOrArrayType(index: Int): Type = ( if (index <= 0 || len <= index) errorBadIndex(index) - val value = values(index) - var c: Type = null - if (value eq null) { - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start) - val name = getExternalName(in.getChar(start + 1)) - if (name.charAt(0) == ARRAY_TAG) { - c = sigToType(null, name) - values(index) = c - } else { - val sym = classNameToSymbol(name) - /*if (name.endsWith("$")) definitions.getModule(name.subName(0, name.length - 1)) - else if (name.endsWith("$class")) definitions.getModule(name) - else definitions.getClass(name)*/ - values(index) = sym - c = sym.tpe - } - } else c = value match { - case tp: Type => tp - case cls: Symbol => cls.tpe + else values(index) match { + case tp: Type => tp + case cls: Symbol => cls.tpe_* + case _ => + val name = getClassName(index) + name charAt 0 match { + case ARRAY_TAG => recordAtIndex(sigToType(null, name), index) + case _ => recordAtIndex(classNameToSymbol(name), index).tpe_* + } } - c - } - - def getType(index: Int): Type = getType(null, index) - - def getType(sym: Symbol, index: Int): Type = - sigToType(sym, getExternalName(index)) + ) - def getSuperClass(index: Int): Symbol = - if (index == 0) definitions.AnyClass else getClassSymbol(index) + def getType(index: Int): Type = getType(null, index) + def getType(sym: Symbol, index: Int): Type = sigToType(sym, getExternalName(index)) + def getSuperClass(index: Int): Symbol = if (index == 0) AnyClass else getClassSymbol(index) - def getConstant(index: Int): Constant = { + private def createConstant(index: Int): Constant = { + val start = starts(index) + Constant((in.buf(start).toInt: @switch) match { + case CONSTANT_STRING => getName(in.getChar(start + 1).toInt).toString + case CONSTANT_INTEGER => in.getInt(start + 1) + case CONSTANT_FLOAT => in.getFloat(start + 1) + case CONSTANT_LONG => in.getLong(start + 1) + case CONSTANT_DOUBLE => in.getDouble(start + 1) + case CONSTANT_CLASS => getClassOrArrayType(index).typeSymbol.tpe_* // !!! Is this necessary or desirable? + case _ => errorBadTag(start) + }) + } + def getConstant(index: Int): Constant = ( if (index <= 0 || len <= index) errorBadIndex(index) - var value = values(index) - if (value eq null) { - val start = starts(index) - value = (in.buf(start).toInt: @switch) match { - case CONSTANT_STRING => - Constant(getName(in.getChar(start + 1).toInt).toString) - case CONSTANT_INTEGER => - Constant(in.getInt(start + 1)) - case CONSTANT_FLOAT => - Constant(in.getFloat(start + 1)) - case CONSTANT_LONG => - Constant(in.getLong(start + 1)) - case CONSTANT_DOUBLE => - Constant(in.getDouble(start + 1)) - case CONSTANT_CLASS => - getClassOrArrayType(index).typeSymbol - case _ => - errorBadTag(start) - } - values(index) = value - } - value match { - case ct: Constant => ct - case cls: Symbol => Constant(cls.tpe_*) - case arr: Type => Constant(arr) + else values(index) match { + case const: Constant => const + case sym: Symbol => Constant(sym.tpe_*) + case tpe: Type => Constant(tpe) + case _ => recordAtIndex(createConstant(index), index) } - } + ) private def getSubArray(bytes: Array[Byte]): Array[Byte] = { val decodedLength = ByteCodecs.decode(bytes) @@ -372,46 +357,41 @@ abstract class ClassfileParser { arr } - def getBytes(index: Int): Array[Byte] = { + def getBytes(index: Int): Array[Byte] = ( if (index <= 0 || len <= index) errorBadIndex(index) - var value = values(index).asInstanceOf[Array[Byte]] - if (value eq null) { - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val len = in.getChar(start + 1) - val bytes = new Array[Byte](len) - System.arraycopy(in.buf, start + 3, bytes, 0, len) - value = getSubArray(bytes) - values(index) = value + else values(index) match { + case xs: Array[Byte] => xs + case _ => + val start = firstExpecting(index, CONSTANT_UTF8) + val len = in getChar start + val bytes = new Array[Byte](len) + System.arraycopy(in.buf, start + 2, bytes, 0, len) + recordAtIndex(getSubArray(bytes), index) } - value - } + ) def getBytes(indices: List[Int]): Array[Byte] = { - assert(!indices.isEmpty, indices) - var value = values(indices.head).asInstanceOf[Array[Byte]] - if (value eq null) { - val bytesBuffer = ArrayBuffer.empty[Byte] - for (index <- indices) { - if (index <= 0 || ConstantPool.this.len <= index) errorBadIndex(index) - val start = starts(index) - if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start) - val len = in.getChar(start + 1) - bytesBuffer ++= in.buf.view(start + 3, start + 3 + len) - } - value = getSubArray(bytesBuffer.toArray) - values(indices.head) = value + val head = indices.head + values(head) match { + case xs: Array[Byte] => xs + case _ => + val arr: Array[Byte] = indices.toArray flatMap { index => + if (index <= 0 || ConstantPool.this.len <= index) errorBadIndex(index) + val start = firstExpecting(index, CONSTANT_UTF8) + val len = in getChar start + in.buf drop start + 2 take len + } + recordAtIndex(getSubArray(arr), head) } - value } /** Throws an exception signaling a bad constant index. */ private def errorBadIndex(index: Int) = - throw new RuntimeException("bad constant pool index: " + index + " at pos: " + in.bp) + abort(s"bad constant pool index: $index at pos: ${in.bp}") /** Throws an exception signaling a bad tag at given address. */ private def errorBadTag(start: Int) = - throw new RuntimeException("bad constant pool tag " + in.buf(start) + " at byte " + start) + abort("bad constant pool tag ${in.buf(start)} at byte $start") } /** Try to force the chain of enclosing classes for the given name. Otherwise @@ -490,30 +470,27 @@ abstract class ClassfileParser { catch { case _: FatalError => loadClassSymbol(name) } } - var sawPrivateConstructor = false - def parseClass() { - val jflags = in.nextChar - val isAnnotation = hasAnnotation(jflags) - val sflags = toScalaClassFlags(jflags) - val nameIdx = in.nextChar - currentClass = pool.getClassName(nameIdx) + val jflags = readClassFlags() + val sflags = jflags.toScalaFlags + val nameIdx = u2 + currentClass = pool.getClassName(nameIdx) /* Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled. * Updates the read pointer of 'in'. */ def parseParents: List[Type] = { if (isScala) { - in.nextChar // skip superclass - val ifaces = in.nextChar - in.bp += ifaces * 2 // .. and iface count interfaces - List(definitions.AnyRefClass.tpe) // dummy superclass, will be replaced by pickled information + u2 // skip superclass + val ifaces = u2 + in.bp += ifaces * 2 // .. and iface count interfaces + List(AnyRefClass.tpe) // dummy superclass, will be replaced by pickled information } else raiseLoaderLevel { - val superType = if (isAnnotation) { in.nextChar; definitions.AnnotationClass.tpe } - else pool.getSuperClass(in.nextChar).tpe_* - val ifaceCount = in.nextChar - var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).tpe_* - if (isAnnotation) ifaces = definitions.ClassfileAnnotationClass.tpe :: ifaces + val superType = if (jflags.isAnnotation) { u2; AnnotationClass.tpe } + else pool.getSuperClass(u2).tpe_* + val ifaceCount = u2 + var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(u2).tpe_* + if (jflags.isAnnotation) ifaces ::= ClassfileAnnotationClass.tpe superType :: ifaces } } @@ -543,21 +520,20 @@ abstract class ClassfileParser { skipMembers() // methods if (!isScala) { clazz setFlag sflags - importPrivateWithinFromJavaFlags(clazz, jflags) - importPrivateWithinFromJavaFlags(staticModule, jflags) - clazz.setInfo(classInfo) + propagatePackageBoundary(jflags, clazz, staticModule) + clazz setInfo classInfo moduleClass setInfo staticInfo - staticModule.setInfo(moduleClass.tpe) - staticModule.setFlag(JAVA) - staticModule.moduleClass.setFlag(JAVA) + staticModule setInfo moduleClass.tpe + staticModule setFlag JAVA + staticModule.moduleClass setFlag JAVA // attributes now depend on having infos set already parseAttributes(clazz, classInfo) def queueLoad() { in.bp = curbp - 0 until in.nextChar foreach (_ => parseField()) + 0 until u2 foreach (_ => parseField()) sawPrivateConstructor = false - 0 until in.nextChar foreach (_ => parseMethod()) + 0 until u2 foreach (_ => parseMethod()) val needsConstructor = ( !sawPrivateConstructor && !(instanceScope containsName nme.CONSTRUCTOR) @@ -593,26 +569,28 @@ abstract class ClassfileParser { } def parseField() { - val jflags = in.nextChar - val sflags = toScalaFieldFlags(jflags) - if ((sflags & PRIVATE) != 0L && !global.settings.optimise.value) { + val jflags = readFieldFlags() + val sflags = jflags.toScalaFlags + + if ((sflags & PRIVATE) != 0L && !optimized) { in.skip(4); skipAttributes() } else { - val name = pool.getName(in.nextChar) - val info = pool.getType(in.nextChar) - val sym = getOwner(jflags).newValue(name.toTermName, NoPosition, sflags) - val isEnum = (jflags & JAVA_ACC_ENUM) != 0 + val name = readName() + val info = readType() + val sym = ownerForFlags(jflags).newValue(name.toTermName, NoPosition, sflags) + // Note: the info may be overrwritten later with a generic signature + // parsed from SignatureATTR sym setInfo { - if (isEnum) ConstantType(Constant(sym)) + if (jflags.isEnum) ConstantType(Constant(sym)) else info } - importPrivateWithinFromJavaFlags(sym, jflags) + propagatePackageBoundary(jflags, sym) parseAttributes(sym, info) - getScope(jflags).enter(sym) + getScope(jflags) enter sym // sealed java enums - if (isEnum) { + if (jflags.isEnum) { val enumClass = sym.owner.linkedClassOfClass if (!enumClass.isSealed) enumClass setFlag (SEALED | ABSTRACT) @@ -623,26 +601,27 @@ abstract class ClassfileParser { } def parseMethod() { - val jflags = in.nextChar.toInt - val sflags = toScalaMethodFlags(jflags) - if (isPrivate(jflags) && !global.settings.optimise.value) { - val name = pool.getName(in.nextChar) + val jflags = readMethodFlags() + val sflags = jflags.toScalaFlags + if (jflags.isPrivate && !optimized) { + val name = readName() if (name == nme.CONSTRUCTOR) sawPrivateConstructor = true in.skip(2); skipAttributes() - } else { - if ((sflags & PRIVATE) != 0L && global.settings.optimise.value) { + } + else { + if ((sflags & PRIVATE) != 0L && optimized) { in.skip(4); skipAttributes() } else { - val name = pool.getName(in.nextChar) - val sym = getOwner(jflags).newMethod(name.toTermName, NoPosition, sflags) - var info = pool.getType(sym, (in.nextChar)) + val name = readName() + val sym = ownerForFlags(jflags).newMethod(name.toTermName, NoPosition, sflags) + var info = pool.getType(sym, u2) if (name == nme.CONSTRUCTOR) info match { case MethodType(params, restpe) => // if this is a non-static inner class, remove the explicit outer parameter val newParams = innerClasses getEntry currentClass match { - case Some(entry) if !isScalaRaw && !isStatic(entry.jflags) => + case Some(entry) if !isScalaRaw && !entry.jflags.isStatic => /* About `clazz.owner.isPackage` below: SI-5957 * For every nested java class A$B, there are two symbols in the scala compiler. * 1. created by SymbolLoader, because of the existence of the A$B.class file, owner: package @@ -657,13 +636,15 @@ abstract class ClassfileParser { } info = MethodType(newParams, clazz.tpe) } - sym.setInfo(info) - importPrivateWithinFromJavaFlags(sym, jflags) + // Note: the info may be overrwritten later with a generic signature + // parsed from SignatureATTR + sym setInfo info + propagatePackageBoundary(jflags, sym) parseAttributes(sym, info) - if ((jflags & JAVA_ACC_VARARGS) != 0) { - sym.setInfo(arrayToRepeated(sym.info)) - } - getScope(jflags).enter(sym) + if (jflags.isVarargs) + sym modifyInfo arrayToRepeated + + getScope(jflags) enter sym } } } @@ -683,15 +664,15 @@ abstract class ClassfileParser { def sig2type(tparams: immutable.Map[Name,Symbol], skiptvs: Boolean): Type = { val tag = sig.charAt(index); index += 1 tag match { - case BYTE_TAG => definitions.ByteClass.tpe - case CHAR_TAG => definitions.CharClass.tpe - case DOUBLE_TAG => definitions.DoubleClass.tpe - case FLOAT_TAG => definitions.FloatClass.tpe - case INT_TAG => definitions.IntClass.tpe - case LONG_TAG => definitions.LongClass.tpe - case SHORT_TAG => definitions.ShortClass.tpe - case VOID_TAG => definitions.UnitClass.tpe - case BOOL_TAG => definitions.BooleanClass.tpe + case BYTE_TAG => ByteClass.tpe + case CHAR_TAG => CharClass.tpe + case DOUBLE_TAG => DoubleClass.tpe + case FLOAT_TAG => FloatClass.tpe + case INT_TAG => IntClass.tpe + case LONG_TAG => LongClass.tpe + case SHORT_TAG => ShortClass.tpe + case VOID_TAG => UnitClass.tpe + case BOOL_TAG => BooleanClass.tpe case 'L' => def processInner(tp: Type): Type = tp match { case TypeRef(pre, sym, args) if (!sym.isStatic) => @@ -716,7 +697,7 @@ abstract class ClassfileParser { val tp = sig2type(tparams, skiptvs) // sig2type seems to return AnyClass regardless of the situation: // we don't want Any as a LOWER bound. - if (tp.typeSymbol == definitions.AnyClass) TypeBounds.empty + if (tp.typeSymbol == AnyClass) TypeBounds.empty else TypeBounds.lower(tp) case '*' => TypeBounds.empty } @@ -737,7 +718,7 @@ abstract class ClassfileParser { // or we'll create a boatload of needless existentials. else if (classSym.isMonomorphicType || classSym.unsafeTypeParams.isEmpty) tp // raw type - existentially quantify all type parameters - else logResult(s"raw type from $classSym")(definitions.unsafeClassExistentialType(classSym)) + else logResult(s"raw type from $classSym")(unsafeClassExistentialType(classSym)) case tp => assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp") tp @@ -750,7 +731,9 @@ abstract class ClassfileParser { accept('.') val name = subName(c => c == ';' || c == '<' || c == '.').toTypeName val clazz = tpe.member(name) - tpe = processClassType(processInner(clazz.tpe)) + val dummyArgs = Nil // the actual arguments are added in processClassType + val inner = typeRef(pre = tpe, sym = clazz, args = dummyArgs) + tpe = processClassType(inner) } accept(';') tpe @@ -763,11 +746,11 @@ abstract class ClassfileParser { // NOTE that the comparison to Object only works for abstract types bounded by classes that are strict subclasses of Object // if the bound is exactly Object, it will have been converted to Any, and the comparison will fail // see also RestrictJavaArraysMap (when compiling java sources directly) - if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) { - elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) + if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< ObjectClass.tpe)) { + elemtp = intersectionType(List(elemtp, ObjectClass.tpe)) } - definitions.arrayType(elemtp) + arrayType(elemtp) case '(' => // we need a method symbol. given in line 486 by calling getType(methodSym, ..) assert(sym ne null, sig) @@ -785,7 +768,7 @@ abstract class ClassfileParser { case 'T' => val n = subName(';'.==).toTypeName index += 1 - if (skiptvs) definitions.AnyClass.tpe + if (skiptvs) AnyClass.tpe else tparams(n).typeConstructor } } // sig2type(tparams, skiptvs) @@ -838,27 +821,23 @@ abstract class ClassfileParser { GenPolyType(ownTypeParams, tpe) } // sigToType - class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType with FlagAgnosticCompleter { - override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } - } - def parseAttributes(sym: Symbol, symtype: Type) { def convertTo(c: Constant, pt: Type): Constant = { - if (pt.typeSymbol == definitions.BooleanClass && c.tag == IntTag) + if (pt.typeSymbol == BooleanClass && c.tag == IntTag) Constant(c.value != 0) else c convertTo pt } def parseAttribute() { - val attrName = pool.getName(in.nextChar).toTypeName - val attrLen = in.nextInt + val attrName = readTypeName() + val attrLen = u4 attrName match { case tpnme.SignatureATTR => if (!isScala && !isScalaRaw) { - val sig = pool.getExternalName(in.nextChar) + val sig = pool.getExternalName(u2) val newType = sigToType(sym, sig) sym.setInfo(newType) - if (settings.debug.value && settings.verbose.value) + if (settings.debug && settings.verbose) println("" + sym + "; signature = " + sig + " type = " + newType) } else in.skip(attrLen) @@ -870,10 +849,10 @@ abstract class ClassfileParser { in.skip(attrLen) case tpnme.DeprecatedATTR => val arg = Literal(Constant("see corresponding Javadoc for more information.")) - sym.addAnnotation(definitions.DeprecatedAttr, arg, Literal(Constant(""))) + sym.addAnnotation(DeprecatedAttr, arg, Literal(Constant(""))) in.skip(attrLen) case tpnme.ConstantValueATTR => - val c = pool.getConstant(in.nextChar) + val c = pool.getConstant(u2) val c1 = convertTo(c, symtype) if (c1 ne null) sym.setInfo(ConstantType(c1)) else println("failure to convert " + c + " to " + symtype); //debug @@ -887,7 +866,7 @@ abstract class ClassfileParser { isScalaRaw = true // Attribute on methods of java annotation classes when that method has a default case tpnme.AnnotationDefaultATTR => - sym.addAnnotation(definitions.AnnotationDefaultAttr) + sym.addAnnotation(AnnotationDefaultAttr) in.skip(attrLen) // Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME case tpnme.RuntimeAnnotationATTR => @@ -917,7 +896,7 @@ abstract class ClassfileParser { parseExceptions(attrLen) case tpnme.SourceFileATTR => - val srcfileLeaf = pool.getName(in.nextChar).toString.trim + val srcfileLeaf = readName().toString.trim val srcpath = sym.enclosingPackage match { case NoSymbol => srcfileLeaf case rootMirror.EmptyPackage => srcfileLeaf @@ -930,8 +909,8 @@ abstract class ClassfileParser { } def parseAnnotArg: Option[ClassfileAnnotArg] = { - val tag = in.nextByte.toChar - val index = in.nextChar + val tag = u1 + val index = u2 tag match { case STRING_TAG => Some(LiteralAnnotArg(Constant(pool.getName(index).toString))) @@ -942,7 +921,7 @@ abstract class ClassfileParser { Some(LiteralAnnotArg(Constant(pool.getType(index)))) case ENUM_TAG => val t = pool.getType(index) - val n = pool.getName(in.nextChar) + val n = readName() val s = t.typeSymbol.companionModule.info.decls.lookup(n) assert(s != NoSymbol, t) Some(LiteralAnnotArg(Constant(s))) @@ -962,20 +941,20 @@ abstract class ClassfileParser { } def parseScalaSigBytes: Option[ScalaSigBytes] = { - val tag = in.nextByte.toChar + val tag = u1 assert(tag == STRING_TAG, tag) - Some(ScalaSigBytes(pool getBytes in.nextChar)) + Some(ScalaSigBytes(pool getBytes u2)) } def parseScalaLongSigBytes: Option[ScalaSigBytes] = { - val tag = in.nextByte.toChar + val tag = u1 assert(tag == ARRAY_TAG, tag) - val stringCount = in.nextChar + val stringCount = u2 val entries = for (i <- 0 until stringCount) yield { - val stag = in.nextByte.toChar + val stag = u1 assert(stag == STRING_TAG, stag) - in.nextChar.toInt + u2.toInt } Some(ScalaSigBytes(pool.getBytes(entries.toList))) } @@ -985,20 +964,20 @@ abstract class ClassfileParser { */ def parseAnnotation(attrNameIndex: Char): Option[AnnotationInfo] = try { val attrType = pool.getType(attrNameIndex) - val nargs = in.nextChar + val nargs = u2 val nvpairs = new ListBuffer[(Name, ClassfileAnnotArg)] var hasError = false for (i <- 0 until nargs) { - val name = pool.getName(in.nextChar) + val name = readName() // The "bytes: String" argument of the ScalaSignature attribute is parsed specially so that it is // available as an array of bytes (the pickled Scala signature) instead of as a string. The pickled signature // is encoded as a string because of limitations in the Java class file format. - if ((attrType == definitions.ScalaSignatureAnnotation.tpe) && (name == nme.bytes)) + if ((attrType == ScalaSignatureAnnotation.tpe) && (name == nme.bytes)) parseScalaSigBytes match { case Some(c) => nvpairs += ((name, c)) case None => hasError = true } - else if ((attrType == definitions.ScalaLongSignatureAnnotation.tpe) && (name == nme.bytes)) + else if ((attrType == ScalaLongSignatureAnnotation.tpe) && (name == nme.bytes)) parseScalaLongSigBytes match { case Some(c) => nvpairs += ((name, c)) case None => hasError = true @@ -1021,7 +1000,7 @@ abstract class ClassfileParser { // with a `FatalError` exception, handled above. Here you'd end up after a NPE (for example), // and that should never be swallowed silently. warning("Caught: " + ex + " while parsing annotations in " + in.file) - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() None // ignore malformed annotations } @@ -1031,10 +1010,10 @@ abstract class ClassfileParser { * thrown by a method. */ def parseExceptions(len: Int) { - val nClasses = in.nextChar + val nClasses = u2 for (n <- 0 until nClasses) { // FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (SI-7065) - val cls = pool.getClassSymbol(in.nextChar.toInt) + val cls = pool.getClassSymbol(u2) // we call initialize due to the fact that we call Symbol.isMonomorphicType in addThrowsAnnotation // and that method requires Symbol to be forced to give the right answers, see SI-7107 for details cls.initialize @@ -1045,13 +1024,13 @@ abstract class ClassfileParser { /* Parse a sequence of annotations and attaches them to the * current symbol sym, except for the ScalaSignature annotation that it returns, if it is available. */ def parseAnnotations(len: Int): Option[AnnotationInfo] = { - val nAttr = in.nextChar + val nAttr = u2 var scalaSigAnnot: Option[AnnotationInfo] = None for (n <- 0 until nAttr) - parseAnnotation(in.nextChar) match { - case Some(scalaSig) if (scalaSig.atp == definitions.ScalaSignatureAnnotation.tpe) => + parseAnnotation(u2) match { + case Some(scalaSig) if (scalaSig.atp == ScalaSignatureAnnotation.tpe) => scalaSigAnnot = Some(scalaSig) - case Some(scalaSig) if (scalaSig.atp == definitions.ScalaLongSignatureAnnotation.tpe) => + case Some(scalaSig) if (scalaSig.atp == ScalaLongSignatureAnnotation.tpe) => scalaSigAnnot = Some(scalaSig) case Some(annot) => sym.addAnnotation(annot) @@ -1061,7 +1040,7 @@ abstract class ClassfileParser { } // begin parseAttributes - for (i <- 0 until in.nextChar) parseAttribute() + for (i <- 0 until u2) parseAttribute() } /** Enter own inner classes in the right scope. It needs the scopes to be set up, @@ -1071,11 +1050,12 @@ abstract class ClassfileParser { def className(name: Name): Name = name.subName(name.lastPos('.') + 1, name.length) - def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile, jflags: Int) { + def enterClassAndModule(entry: InnerClassEntry, file: AbstractFile) { + def jflags = entry.jflags val completer = new global.loaders.ClassfileLoader(file) val name = entry.originalName - val sflags = toScalaClassFlags(jflags) - val owner = getOwner(jflags) + 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 @@ -1104,7 +1084,7 @@ abstract class ClassfileParser { val file = global.classPath.findSourceFile(entry.externalName.toString) getOrElse { throw new AssertionError(entry.externalName) } - enterClassAndModule(entry, file, entry.jflags) + enterClassAndModule(entry, file) } } } @@ -1117,10 +1097,10 @@ abstract class ClassfileParser { skipSuperclasses() skipMembers() // fields skipMembers() // methods - val attrs = in.nextChar + val attrs = u2 for (i <- 0 until attrs) { - val attrName = pool.getName(in.nextChar).toTypeName - val attrLen = in.nextInt + val attrName = readTypeName() + val attrLen = u4 attrName match { case tpnme.SignatureATTR => in.skip(attrLen) @@ -1134,9 +1114,10 @@ abstract class ClassfileParser { case tpnme.ScalaATTR => isScalaRaw = true case tpnme.InnerClassesATTR if !isScala => - val entries = in.nextChar.toInt + val entries = u2 for (i <- 0 until entries) { - val innerIndex, outerIndex, nameIndex, jflags = in.nextChar.toInt + val innerIndex, outerIndex, nameIndex = u2 + val jflags = readInnerClassFlags() if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0) innerClasses add InnerClassEntry(innerIndex, outerIndex, nameIndex, jflags) } @@ -1148,14 +1129,13 @@ abstract class ClassfileParser { } /** An entry in the InnerClasses attribute of this class file. */ - case class InnerClassEntry(external: Int, outer: Int, name: Int, jflags: Int) { + case class InnerClassEntry(external: Int, outer: Int, name: Int, jflags: JavaAccFlags) { def externalName = pool getClassName external def outerName = pool getClassName outer def originalName = pool getName name - def isStatic = ClassfileParser.this.isStatic(jflags) def isModule = originalName.isTermName - def scope = if (isStatic) staticScope else instanceScope - def enclosing = if (isStatic) enclModule else enclClass + def scope = if (jflags.isStatic) staticScope else instanceScope + 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 @@ -1207,6 +1187,9 @@ abstract class ClassfileParser { } } + class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType with FlagAgnosticCompleter { + override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } + } class LazyAliasType(alias: Symbol) extends LazyType with FlagAgnosticCompleter { override def complete(sym: Symbol) { sym setInfo createFromClonedSymbols(alias.initialize.typeParams, alias.tpe)(typeFun) @@ -1214,16 +1197,16 @@ abstract class ClassfileParser { } def skipAttributes() { - var attrCount: Int = in.nextChar + var attrCount: Int = u2 while (attrCount > 0) { in skip 2 - in skip in.nextInt + in skip u4 attrCount -= 1 } } def skipMembers() { - var memberCount: Int = in.nextChar + var memberCount: Int = u2 while (memberCount > 0) { in skip 6 skipAttributes() @@ -1233,17 +1216,10 @@ abstract class ClassfileParser { def skipSuperclasses() { in.skip(2) // superclass - val ifaces = in.nextChar + val ifaces = u2 in.skip(2 * ifaces) } - protected def getOwner(flags: Int): Symbol = - if (isStatic(flags)) moduleClass else clazz - - protected def getScope(flags: Int): Scope = - if (isStatic(flags)) staticScope else instanceScope - - private def isPrivate(flags: Int) = (flags & JAVA_ACC_PRIVATE) != 0 - private def isStatic(flags: Int) = (flags & JAVA_ACC_STATIC) != 0 - private def hasAnnotation(flags: Int) = (flags & JAVA_ACC_ANNOTATION) != 0 + protected def getScope(flags: JavaAccFlags): Scope = + if (flags.isStatic) staticScope else instanceScope } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 599823b408..50487ad123 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -10,6 +10,7 @@ package classfile import scala.collection.{ mutable, immutable } import mutable.ListBuffer import ClassfileConstants._ +import scala.reflect.internal.JavaAccFlags /** ICode reader from Java bytecode. * @@ -45,26 +46,19 @@ abstract class ICodeReader extends ClassfileParser { (staticCode, instanceCode) } - /** If we're parsing a scala module, the owner of members is always - * the module symbol. - */ - override def getOwner(jflags: Int): Symbol = - if (isScalaModule) this.staticModule - else super.getOwner(jflags) - override def parseClass() { this.instanceCode = new IClass(clazz) this.staticCode = new IClass(staticModule) - in.nextChar - pool getClassSymbol in.nextChar + u2 + pool getClassSymbol u2 parseInnerClasses() in.skip(2) // super class - in.skip(2 * in.nextChar) // interfaces - val fieldCount = in.nextChar + in.skip(2 * u2) // interfaces + val fieldCount = u2 for (i <- 0 until fieldCount) parseField() - val methodCount = in.nextChar + val methodCount = u2 for (i <- 0 until methodCount) parseMethod() instanceCode.methods = instanceCode.methods.reverse staticCode.methods = staticCode.methods.reverse @@ -76,25 +70,31 @@ abstract class ICodeReader extends ClassfileParser { skipAttributes() } - private def parseMember(field: Boolean): (Int, Symbol) = { - val jflags = in.nextChar - val name = pool getName in.nextChar - val owner = getOwner(jflags) - val dummySym = owner.newMethod(name.toTermName, owner.pos, toScalaMethodFlags(jflags)) + private def parseMember(field: Boolean): (JavaAccFlags, Symbol) = { + val jflags = JavaAccFlags(u2) + val name = pool getName u2 + /** If we're parsing a scala module, the owner of members is always + * the module symbol. + */ + val owner = ( + if (isScalaModule) staticModule + else if (jflags.isStatic) moduleClass + else clazz + ) + val dummySym = owner.newMethod(name.toTermName, owner.pos, jflags.toScalaFlags) try { - val ch = in.nextChar + val ch = u2 val tpe = pool.getType(dummySym, ch) if ("<clinit>" == name.toString) (jflags, NoSymbol) else { - val owner = getOwner(jflags) var sym = owner.info.findMember(name, 0, 0, stableOnly = false).suchThat(old => sameType(old.tpe, tpe)) if (sym == NoSymbol) sym = owner.info.findMember(newTermName(name + nme.LOCAL_SUFFIX_STRING), 0, 0, stableOnly = false).suchThat(_.tpe =:= tpe) if (sym == NoSymbol) { - sym = if (field) owner.newValue(name.toTermName, owner.pos, toScalaFieldFlags(jflags)) else dummySym + sym = if (field) owner.newValue(name.toTermName, owner.pos, jflags.toScalaFlags) else dummySym sym setInfoAndEnter tpe log(s"ICodeReader could not locate ${name.decode} in $owner. Created ${sym.defString}.") } @@ -126,9 +126,9 @@ abstract class ICodeReader extends ClassfileParser { this.method = new IMethod(sym) this.method.returnType = toTypeKind(sym.tpe.resultType) getCode(jflags).addMethod(this.method) - if ((jflags & JAVA_ACC_NATIVE) != 0) + if (jflags.isNative) this.method.native = true - val attributeCount = in.nextChar + val attributeCount = u2 for (i <- 0 until attributeCount) parseAttribute() } else { debuglog("Skipping non-existent method.") @@ -142,8 +142,8 @@ abstract class ICodeReader extends ClassfileParser { } def parseAttribute() { - val attrName = pool.getName(in.nextChar).toTypeName - val attrLen = in.nextInt + val attrName = pool.getName(u2).toTypeName + val attrLen = u4 attrName match { case tpnme.CodeATTR => parseByteCode() @@ -187,9 +187,9 @@ abstract class ICodeReader extends ClassfileParser { /** Parse java bytecode into ICode */ def parseByteCode() { - maxStack = in.nextChar - maxLocals = in.nextChar - val codeLength = in.nextInt + maxStack = u2 + maxLocals = u2 + val codeLength = u4 val code = new LinearCode def parseInstruction() { @@ -200,7 +200,7 @@ abstract class ICodeReader extends ClassfileParser { /* Parse 16 bit jump target. */ def parseJumpTarget = { size += 2 - val offset = in.nextChar.toShort + val offset = u2.toShort val target = pc + offset assert(target >= 0 && target < codeLength, "Illegal jump target: " + target) target @@ -209,14 +209,13 @@ abstract class ICodeReader extends ClassfileParser { /* Parse 32 bit jump target. */ def parseJumpTargetW: Int = { size += 4 - val offset = in.nextInt + val offset = u4 val target = pc + offset assert(target >= 0 && target < codeLength, "Illegal jump target: " + target + "pc: " + pc + " offset: " + offset) target } - val instr = toUnsignedByte(in.nextByte) - instr match { + u1 match { case JVM.nop => parseInstruction() case JVM.aconst_null => code emit CONSTANT(Constant(null)) case JVM.iconst_m1 => code emit CONSTANT(Constant(-1)) @@ -235,17 +234,17 @@ abstract class ICodeReader extends ClassfileParser { case JVM.dconst_0 => code emit CONSTANT(Constant(0.0)) case JVM.dconst_1 => code emit CONSTANT(Constant(1.0)) - case JVM.bipush => code.emit(CONSTANT(Constant(in.nextByte))); size += 1 - case JVM.sipush => code.emit(CONSTANT(Constant(in.nextChar))); size += 2 - case JVM.ldc => code.emit(CONSTANT(pool.getConstant(toUnsignedByte(in.nextByte)))); size += 1 - case JVM.ldc_w => code.emit(CONSTANT(pool.getConstant(in.nextChar))); size += 2 - case JVM.ldc2_w => code.emit(CONSTANT(pool.getConstant(in.nextChar))); size += 2 - case JVM.iload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, INT))); size += 1 - case JVM.lload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, LONG))); size += 1 - case JVM.fload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, FLOAT))); size += 1 - case JVM.dload => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size += 1 + case JVM.bipush => code.emit(CONSTANT(Constant(u1))); size += 1 + case JVM.sipush => code.emit(CONSTANT(Constant(u2))); size += 2 + case JVM.ldc => code.emit(CONSTANT(pool.getConstant(u1))); size += 1 + case JVM.ldc_w => code.emit(CONSTANT(pool.getConstant(u2))); size += 2 + case JVM.ldc2_w => code.emit(CONSTANT(pool.getConstant(u2))); size += 2 + case JVM.iload => code.emit(LOAD_LOCAL(code.getLocal(u1, INT))); size += 1 + case JVM.lload => code.emit(LOAD_LOCAL(code.getLocal(u1, LONG))); size += 1 + case JVM.fload => code.emit(LOAD_LOCAL(code.getLocal(u1, FLOAT))); size += 1 + case JVM.dload => code.emit(LOAD_LOCAL(code.getLocal(u1, DOUBLE))); size += 1 case JVM.aload => - val local = in.nextByte.toInt; size += 1 + val local = u1.toInt; size += 1 if (local == 0 && !method.isStatic) code.emit(THIS(method.symbol.owner)) else @@ -285,11 +284,11 @@ abstract class ICodeReader extends ClassfileParser { case JVM.caload => code.emit(LOAD_ARRAY_ITEM(CHAR)) case JVM.saload => code.emit(LOAD_ARRAY_ITEM(SHORT)) - case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, INT))); size += 1 - case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, LONG))); size += 1 - case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, FLOAT))); size += 1 - case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size += 1 - case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, ObjectReference))); size += 1 + case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(u1, INT))); size += 1 + case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(u1, LONG))); size += 1 + case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(u1, FLOAT))); size += 1 + case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(u1, DOUBLE))); size += 1 + case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(u1, ObjectReference))); size += 1 case JVM.istore_0 => code.emit(STORE_LOCAL(code.getLocal(0, INT))) case JVM.istore_1 => code.emit(STORE_LOCAL(code.getLocal(1, INT))) case JVM.istore_2 => code.emit(STORE_LOCAL(code.getLocal(2, INT))) @@ -373,9 +372,9 @@ abstract class ICodeReader extends ClassfileParser { case JVM.lxor => code.emit(CALL_PRIMITIVE(Logical(XOR, LONG))) case JVM.iinc => size += 2 - val local = code.getLocal(in.nextByte, INT) + val local = code.getLocal(u1, INT) code.emit(LOAD_LOCAL(local)) - code.emit(CONSTANT(Constant(in.nextByte))) + code.emit(CONSTANT(Constant(u1))) code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT))) code.emit(STORE_LOCAL(local)) @@ -425,14 +424,14 @@ abstract class ICodeReader extends ClassfileParser { size += padding in.bp += padding assert((pc + size % 4) != 0, pc) -/* var byte1 = in.nextByte; size += 1; - while (byte1 == 0) { byte1 = in.nextByte; size += 1; } - val default = byte1 << 24 | in.nextByte << 16 | in.nextByte << 8 | in.nextByte; +/* var byte1 = u1; size += 1; + while (byte1 == 0) { byte1 = u1; size += 1; } + val default = byte1 << 24 | u1 << 16 | u1 << 8 | u1; size = size + 3 */ - val default = pc + in.nextInt; size += 4 - val low = in.nextInt - val high = in.nextInt + val default = pc + u4; size += 4 + val low = u4 + val high = u4 size += 8 assert(low <= high, "Value low not <= high for tableswitch.") @@ -445,13 +444,13 @@ abstract class ICodeReader extends ClassfileParser { size += padding in.bp += padding assert((pc + size % 4) != 0, pc) - val default = pc + in.nextInt; size += 4 - val npairs = in.nextInt; size += 4 + val default = pc + u4; size += 4 + val npairs = u4; size += 4 var tags: List[List[Int]] = Nil var targets: List[Int] = Nil var i = 0 while (i < npairs) { - tags = List(in.nextInt) :: tags; size += 4 + tags = List(u4) :: tags; size += 4 targets = parseJumpTargetW :: targets; // parseJumpTargetW updates 'size' itself i += 1 } @@ -466,47 +465,54 @@ abstract class ICodeReader extends ClassfileParser { case JVM.return_ => code.emit(RETURN(UNIT)) case JVM.getstatic => - val field = pool.getMemberSymbol(in.nextChar, static = true); size += 2 + val field = pool.getMemberSymbol(u2, static = true); size += 2 if (field.hasModuleFlag) code emit LOAD_MODULE(field) else code emit LOAD_FIELD(field, isStatic = true) case JVM.putstatic => - val field = pool.getMemberSymbol(in.nextChar, static = true); size += 2 + val field = pool.getMemberSymbol(u2, static = true); size += 2 code.emit(STORE_FIELD(field, isStatic = true)) case JVM.getfield => - val field = pool.getMemberSymbol(in.nextChar, static = false); size += 2 + val field = pool.getMemberSymbol(u2, static = false); size += 2 code.emit(LOAD_FIELD(field, isStatic = false)) case JVM.putfield => - val field = pool.getMemberSymbol(in.nextChar, static = false); size += 2 + val field = pool.getMemberSymbol(u2, static = false); size += 2 code.emit(STORE_FIELD(field, isStatic = false)) case JVM.invokevirtual => - val m = pool.getMemberSymbol(in.nextChar, static = false); size += 2 + val m = pool.getMemberSymbol(u2, static = false); size += 2 code.emit(CALL_METHOD(m, Dynamic)) case JVM.invokeinterface => - val m = pool.getMemberSymbol(in.nextChar, static = false); size += 4 + val m = pool.getMemberSymbol(u2, static = false); size += 4 in.skip(2) code.emit(CALL_METHOD(m, Dynamic)) case JVM.invokespecial => - val m = pool.getMemberSymbol(in.nextChar, static = false); size += 2 + val m = pool.getMemberSymbol(u2, static = false); size += 2 val style = if (m.name == nme.CONSTRUCTOR || m.isPrivate) Static(onInstance = true) else SuperCall(m.owner.name) code.emit(CALL_METHOD(m, style)) case JVM.invokestatic => - val m = pool.getMemberSymbol(in.nextChar, static = true); size += 2 + val m = pool.getMemberSymbol(u2, static = true); size += 2 if (isBox(m)) code.emit(BOX(toTypeKind(m.info.paramTypes.head))) else if (isUnbox(m)) code.emit(UNBOX(toTypeKind(m.info.resultType))) else code.emit(CALL_METHOD(m, Static(onInstance = false))) + case JVM.invokedynamic => + // TODO, this is just a place holder. A real implementation must parse the class constant entry + debuglog("Found JVM invokedynamic instructionm, inserting place holder ICode INVOKE_DYNAMIC.") + containsInvokeDynamic = true + val poolEntry = in.nextChar + in.skip(2) + code.emit(INVOKE_DYNAMIC(poolEntry)) case JVM.new_ => - code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar)))) + code.emit(NEW(REFERENCE(pool.getClassSymbol(u2)))) size += 2 case JVM.newarray => - val kind = in.nextByte match { + val kind = u1 match { case T_BOOLEAN => BOOL case T_CHAR => CHAR case T_FLOAT => FLOAT @@ -520,35 +526,35 @@ abstract class ICodeReader extends ClassfileParser { code.emit(CREATE_ARRAY(kind, 1)) case JVM.anewarray => - val tpe = pool.getClassOrArrayType(in.nextChar); size += 2 + val tpe = pool.getClassOrArrayType(u2); size += 2 code.emit(CREATE_ARRAY(toTypeKind(tpe), 1)) case JVM.arraylength => code.emit(CALL_PRIMITIVE(ArrayLength(ObjectReference))); // the kind does not matter case JVM.athrow => code.emit(THROW(definitions.ThrowableClass)) case JVM.checkcast => - code.emit(CHECK_CAST(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size += 2 + code.emit(CHECK_CAST(toTypeKind(pool.getClassOrArrayType(u2)))); size += 2 case JVM.instanceof => - code.emit(IS_INSTANCE(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size += 2 + code.emit(IS_INSTANCE(toTypeKind(pool.getClassOrArrayType(u2)))); size += 2 case JVM.monitorenter => code.emit(MONITOR_ENTER()) case JVM.monitorexit => code.emit(MONITOR_EXIT()) case JVM.wide => size += 1 - toUnsignedByte(in.nextByte) match { - case JVM.iload => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, INT))); size += 2 - case JVM.lload => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, LONG))); size += 2 - case JVM.fload => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, FLOAT))); size += 2 - case JVM.dload => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, DOUBLE))); size += 2 - case JVM.aload => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, ObjectReference))); size += 2 - case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, INT))); size += 2 - case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, LONG))); size += 2 - case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, FLOAT))); size += 2 - case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, DOUBLE))); size += 2 - case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, ObjectReference))); size += 2 + u1 match { + case JVM.iload => code.emit(LOAD_LOCAL(code.getLocal(u2, INT))); size += 2 + case JVM.lload => code.emit(LOAD_LOCAL(code.getLocal(u2, LONG))); size += 2 + case JVM.fload => code.emit(LOAD_LOCAL(code.getLocal(u2, FLOAT))); size += 2 + case JVM.dload => code.emit(LOAD_LOCAL(code.getLocal(u2, DOUBLE))); size += 2 + case JVM.aload => code.emit(LOAD_LOCAL(code.getLocal(u2, ObjectReference))); size += 2 + case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(u2, INT))); size += 2 + case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(u2, LONG))); size += 2 + case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(u2, FLOAT))); size += 2 + case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(u2, DOUBLE))); size += 2 + case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(u2, ObjectReference))); size += 2 case JVM.ret => sys.error("Cannot handle jsr/ret") case JVM.iinc => size += 4 - val local = code.getLocal(in.nextChar, INT) - code.emit(CONSTANT(Constant(in.nextChar))) + val local = code.getLocal(u2, INT) + code.emit(CONSTANT(Constant(u2))) code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT))) code.emit(STORE_LOCAL(local)) case _ => sys.error("Invalid 'wide' operand") @@ -556,8 +562,8 @@ abstract class ICodeReader extends ClassfileParser { case JVM.multianewarray => size += 3 - val tpe = toTypeKind(pool getClassOrArrayType in.nextChar) - val dim = in.nextByte + val tpe = toTypeKind(pool getClassOrArrayType u2) + val dim = u1 // assert(dim == 1, "Cannot handle multidimensional arrays yet.") code emit CREATE_ARRAY(tpe, dim) @@ -583,14 +589,14 @@ abstract class ICodeReader extends ClassfileParser { pc = 0 while (pc < codeLength) parseInstruction() - val exceptionEntries = in.nextChar.toInt + val exceptionEntries = u2.toInt code.containsEHs = (exceptionEntries != 0) var i = 0 while (i < exceptionEntries) { // skip start end PC in.skip(4) // read the handler PC - code.jmpTargets += in.nextChar + code.jmpTargets += u2 // skip the exception type in.skip(2) i += 1 @@ -626,10 +632,8 @@ abstract class ICodeReader extends ClassfileParser { /** Return the icode class that should include members with the given flags. * There are two possible classes, the static part and the instance part. */ - def getCode(flags: Int): IClass = - if (isScalaModule) staticCode - else if ((flags & JAVA_ACC_STATIC) != 0) staticCode - else instanceCode + def getCode(flags: JavaAccFlags): IClass = + if (isScalaModule || flags.isStatic) staticCode else instanceCode class LinearCode { val instrs: ListBuffer[(Int, Instruction)] = new ListBuffer @@ -639,6 +643,7 @@ abstract class ICodeReader extends ClassfileParser { var containsDUPX = false var containsNEW = false var containsEHs = false + var containsInvokeDynamic = false def emit(i: Instruction) { instrs += ((pc, i)) @@ -657,6 +662,7 @@ abstract class ICodeReader extends ClassfileParser { val code = new Code(method) method.setCode(code) method.bytecodeHasEHs = containsEHs + method.bytecodeHasInvokeDynamic = containsInvokeDynamic var bb = code.startBlock def makeBasicBlocks: mutable.Map[Int, BasicBlock] = diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 9217bbeeb8..94880c4b2e 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -239,7 +239,7 @@ abstract class Pickler extends SubComponent { putSymbols(tparams) case AnnotatedType(annotations, underlying, selfsym) => putType(underlying) - if (settings.selfInAnnots.value) putSymbol(selfsym) + if (settings.selfInAnnots) putSymbol(selfsym) putAnnotations(annotations filter (_.isStatic)) case _ => throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")") @@ -643,7 +643,7 @@ abstract class Pickler extends SubComponent { annotations filter (_.isStatic) match { case Nil => writeBody(tp) // write the underlying type if there are no annotations case staticAnnots => - if (settings.selfInAnnots.value && selfsym != NoSymbol) + if (settings.selfInAnnots && selfsym != NoSymbol) writeRef(selfsym) writeRef(tp) writeRefs(staticAnnots) diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 3b9cee2d88..ac18e5ba4f 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -85,7 +85,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { def transformApplyDynamic(ad: ApplyDynamic) = { val qual0 = ad.qual val params = ad.args - if (settings.logReflectiveCalls.value) + if (settings.logReflectiveCalls) unit.echo(ad.pos, "method invocation uses reflection") val typedPos = typedWithPos(ad.pos) _ @@ -473,7 +473,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /* For testing purposes, the dynamic application's condition * can be printed-out in great detail. Remove? */ - if (settings.debug.value) { + if (settings.debug) { def paramsToString(xs: Any*) = xs map (_.toString) mkString ", " val mstr = ad.symbol.tpe match { case MethodType(mparams, resType) => diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index e6cf5e6346..ac79c60254 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -66,8 +66,8 @@ abstract class Erasure extends AddInterfaces } } - override protected def verifyJavaErasure = settings.Xverify.value || settings.debug.value - def needsJavaSig(tp: Type) = !settings.Ynogenericsig.value && NeedsSigCollector.collect(tp) + override protected def verifyJavaErasure = settings.Xverify || settings.debug + def needsJavaSig(tp: Type) = !settings.Ynogenericsig && NeedsSigCollector.collect(tp) // only refer to type params that will actually make it into the sig, this excludes: // * higher-order type parameters @@ -418,7 +418,7 @@ abstract class Erasure extends AddInterfaces |both have erased type ${exitingPostErasure(bridge.tpe)}""") } for (bc <- root.baseClasses) { - if (settings.debug.value) + if (settings.debug) exitingPostErasure(println( sm"""check bridge overrides in $bc |${bc.info.nonPrivateDecl(bridge.name)} @@ -648,7 +648,7 @@ abstract class Erasure extends AddInterfaces * @return the adapted tree */ private def adaptToType(tree: Tree, pt: Type): Tree = { - if (settings.debug.value && pt != WildcardType) + if (settings.debug && pt != WildcardType) log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug if (tree.tpe <:< pt) tree diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 124dd6c995..367825c251 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -41,26 +41,24 @@ abstract class ExplicitOuter extends InfoTransform private def isInner(clazz: Symbol) = !clazz.isPackageClass && !clazz.outerClass.isStaticOwner - private def haveSameOuter(parent: Type, clazz: Symbol) = parent match { - case TypeRef(pre, sym, _) => - val owner = clazz.owner + private def haveSameOuter(parent: Type, clazz: Symbol) = { + val owner = clazz.owner + val parentSym = parent.typeSymbol - //println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre") - - sym.isClass && owner.isClass && - (owner isSubClass sym.owner) && - owner.thisType =:= pre - - case _ => false + parentSym.isClass && owner.isClass && + (owner isSubClass parentSym.owner) && + owner.thisType =:= parent.prefix } /** Does given clazz define an outer field? */ def hasOuterField(clazz: Symbol) = { - val parents = clazz.info.parents + val parent = clazz.info.firstParent - isInner(clazz) && !clazz.isTrait && { - parents.isEmpty || !haveSameOuter(parents.head, clazz) - } + // space optimization: inherit the $outer pointer from the parent class if + // we know that it will point to the correct instance. + def canReuseParentOuterField = !parent.typeSymbol.isJavaDefined && haveSameOuter(parent, clazz) + + isInner(clazz) && !clazz.isTrait && !canReuseParentOuterField } private def outerField(clazz: Symbol): Symbol = { @@ -100,6 +98,29 @@ abstract class ExplicitOuter extends InfoTransform sym setInfo clazz.outerClass.thisType } + /** + * Will the outer accessor of the `clazz` subsume the outer accessor of + * `mixin`? + * + * This arises when an inner object mixes in its companion trait. + * + * {{{ + * class C { + * trait T { C.this } // C$T$$$outer$ : C + * object T extends T { C.this } // C$T$$$outer$ : C.this.type + * } + * }}} + * + * See SI-7242. + }} + */ + private def skipMixinOuterAccessor(clazz: Symbol, mixin: Symbol) = { + // Reliant on the current scheme for name expansion, the expanded name + // of the outer accessors in a trait and its companion object are the same. + // If the assumption is one day falsified, run/t7424.scala will let us know. + clazz.fullName == mixin.fullName + } + /** <p> * The type transformation method: * </p> @@ -162,10 +183,14 @@ abstract class ExplicitOuter extends InfoTransform for (mc <- clazz.mixinClasses) { val mixinOuterAcc: Symbol = exitingExplicitOuter(outerAccessor(mc)) if (mixinOuterAcc != NoSymbol) { - if (decls1 eq decls) decls1 = decls.cloneScope - val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) - newAcc setInfo (clazz.thisType memberType mixinOuterAcc) - decls1 enter newAcc + if (skipMixinOuterAccessor(clazz, mc)) + debuglog(s"Reusing outer accessor symbol of $clazz for the mixin outer accessor of $mc") + else { + if (decls1 eq decls) decls1 = decls.cloneScope + val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED) + newAcc setInfo (clazz.thisType memberType mixinOuterAcc) + decls1 enter newAcc + } } } } @@ -370,6 +395,7 @@ abstract class ExplicitOuter extends InfoTransform val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass def mixinPrefix = (currentClass.thisType baseType mixinClass).prefix assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass) + assert(outerAcc.alternatives.size == 1, s"Multiple outer accessors match inner mixin $mixinClass in $currentClass : ${outerAcc.alternatives.map(_.defString)}") // I added the mixinPrefix.typeArgs.nonEmpty condition to address the // crash in SI-4970. I feel quite sure this can be improved. val path = ( @@ -404,7 +430,7 @@ abstract class ExplicitOuter extends InfoTransform } if (!currentClass.isTrait) for (mc <- currentClass.mixinClasses) - if (outerAccessor(mc) != NoSymbol) + if (outerAccessor(mc) != NoSymbol && !skipMixinOuterAccessor(currentClass, mc)) newDefs += mixinOuterAccessorDef(mc) } } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 8971e27bda..35df63b246 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -86,7 +86,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { * Note: The `checkinit` option does not check if transient fields are initialized. */ private def needsInitFlag(sym: Symbol) = ( - settings.checkInit.value + settings.checkInit && sym.isGetter && !sym.isInitializedToDefault && !sym.hasFlag(PARAMACCESSOR | SPECIALIZED | LAZY) @@ -125,7 +125,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { debuglog("starting rebindsuper " + base + " " + member + ":" + member.tpe + " " + mixinClass + " " + base.info.baseClasses + "/" + bcs) while (!bcs.isEmpty && sym == NoSymbol) { - if (settings.debug.value) { + if (settings.debug) { val other = bcs.head.info.nonPrivateDecl(member.name) debuglog("rebindsuper " + bcs.head + " " + other + " " + other.tpe + " " + other.isDeferred) @@ -919,7 +919,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { else if (sym.isConstructor) { deriveDefDef(stat)(addInitBits(clazz, _)) } - else if (settings.checkInit.value && !clazz.isTrait && sym.isSetter) { + else if (settings.checkInit && !clazz.isTrait && sym.isSetter) { val getter = sym.getter(clazz) if (needsInitFlag(getter) && fieldOffset.isDefinedAt(getter)) deriveDefDef(stat)(rhs => Block(List(rhs, localTyper.typed(mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))), UNIT)) diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 91a03009bc..ba19eb1035 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -1156,7 +1156,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * If it is a 'no-specialization' run, it is applied only to loaded symbols. */ override def transformInfo(sym: Symbol, tpe: Type): Type = { - if (settings.nospecialization.value && currentRun.compiles(sym)) tpe + if (settings.nospecialization && currentRun.compiles(sym)) tpe else tpe.resultType match { case cinfo @ ClassInfoType(parents, decls, clazz) if !unspecializableClass(cinfo) => val tparams = tpe.typeParams @@ -1836,7 +1836,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { class SpecializationTransformer(unit: CompilationUnit) extends Transformer { informProgress("specializing " + unit) override def transform(tree: Tree) = { - val resultTree = if (settings.nospecialization.value) tree + val resultTree = if (settings.nospecialization) tree else exitingSpecialize(specializeCalls(unit).transform(tree)) // Remove the final modifier and @inline annotation from anything in the diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 8fd1df7cea..8c1d0a76d0 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -347,10 +347,14 @@ abstract class UnCurry extends InfoTransform } else { log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}") + def canUseDirectly(recv: Tree) = ( + recv.tpe.typeSymbol.isSubClass(FunctionClass(0)) + && treeInfo.isExprSafeToInline(recv) + ) arg match { // don't add a thunk for by-name argument if argument already is an application of // a Function0. We can then remove the application and use the existing Function0. - case Apply(Select(recv, nme.apply), Nil) if recv.tpe.typeSymbol isSubClass FunctionClass(0) => + case Apply(Select(recv, nme.apply), Nil) if canUseDirectly(recv) => recv case _ => newFunction0(arg) @@ -424,7 +428,7 @@ abstract class UnCurry extends InfoTransform val result = ( // TODO - settings.noassertions.value temporarily retained to avoid // breakage until a reasonable interface is settled upon. - if ((sym ne null) && (sym.elisionLevel.exists (_ < settings.elidebelow.value || settings.noassertions.value))) + if ((sym ne null) && (sym.elisionLevel.exists (_ < settings.elidebelow.value || settings.noassertions))) replaceElidableTree(tree) else translateSynchronized(tree) match { case dd @ DefDef(mods, name, tparams, _, tpt, rhs) => diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index 0371df3b10..92b7700c04 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -573,6 +573,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { assert(tp.isInstanceOf[SingletonType]) val toString = tp match { case ConstantType(c) => c.escapedStringValue + case _ if tp.typeSymbol.isModuleClass => tp.typeSymbol.name.toString case _ => tp.toString } Const.unique(tp, new ValueConst(tp, tp.widen, toString)) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index 125e9a3b65..31b04d0bd6 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -15,9 +15,9 @@ import scala.reflect.internal.util.Position /** Optimize and analyze matches based on their TreeMaker-representation. * * The patmat translation doesn't rely on this, so it could be disabled in principle. - * - * TODO: split out match analysis + * - well, not quite: the backend crashes if we emit duplicates in switches (e.g. SI-7290) */ +// TODO: split out match analysis trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { import global._ import global.definitions._ @@ -435,7 +435,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { case SwitchableTreeMaker(pattern) :: GuardAndBodyTreeMakers(guard, body) => Some(CaseDef(pattern, guard, body)) // alternatives - case AlternativesTreeMaker(_, altss, _) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported => + case AlternativesTreeMaker(_, altss, pos) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported => val switchableAlts = altss map { case SwitchableTreeMaker(pattern) :: Nil => Some(pattern) @@ -445,7 +445,17 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { // succeed if they were all switchable sequence(switchableAlts) map { switchableAlts => - CaseDef(Alternative(switchableAlts), guard, body) + def extractConst(t: Tree) = t match { + case Literal(const) => const + case _ => t + } + // SI-7290 Discard duplicate alternatives that would crash the backend + val distinctAlts = distinctBy(switchableAlts)(extractConst) + if (distinctAlts.size < switchableAlts.size) { + val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated + global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}") + } + CaseDef(Alternative(distinctAlts), guard, body) } case _ => // debug.patmat("can't emit switch for "+ makers) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 76268f3ecd..4dff445fe8 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -522,7 +522,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { debug.patmat("combining cases: "+ (casesNoSubstOnly.map(_.mkString(" >> ")).mkString("{", "\n", "}"))) val (suppression, requireSwitch): (Suppression, Boolean) = - if (settings.XnoPatmatAnalysis.value) (Suppression.NoSuppression, false) + if (settings.XnoPatmatAnalysis) (Suppression.NoSuppression, false) else scrut match { case Typed(tree, tpt) => val suppressExhaustive = tpt.tpe hasAnnotation UncheckedClass diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index 62c584e97b..567d5d0ecd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -66,9 +66,9 @@ trait Adaptations { ) } - if (settings.noAdaptedArgs.value) + if (settings.noAdaptedArgs) adaptWarning("No automatic adaptation here: use explicit parentheses.") - else if (settings.warnAdaptedArgs.value) + else if (settings.warnAdaptedArgs) adaptWarning( if (args.isEmpty) "Adapting argument list by inserting (): " + ( if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous." @@ -77,7 +77,7 @@ trait Adaptations { else "Adapting argument list by creating a " + args.size + "-tuple: this may not be what you want." ) - !settings.noAdaptedArgs.value + !settings.noAdaptedArgs } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 36121f2653..02e1eb6f00 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -97,9 +97,9 @@ trait Analyzer extends AnyRef try { val typer = newTyper(rootContext(unit)) unit.body = typer.typed(unit.body) - if (global.settings.Yrangepos.value && !global.reporter.hasErrors) global.validatePositions(unit.body) + if (global.settings.Yrangepos && !global.reporter.hasErrors) global.validatePositions(unit.body) for (workItem <- unit.toCheck) workItem() - if (settings.lint.value) + if (settings.lint) typer checkUnused unit } finally { diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 026f5f7bc8..0686b28079 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -203,7 +203,7 @@ trait Checkable { private def isEffectivelyFinal(sym: Symbol): Boolean = ( // initialization important sym.initialize.isEffectivelyFinal || ( - settings.future.value && isTupleSymbol(sym) // SI-7294 step into the future and treat TupleN as final. + settings.future && isTupleSymbol(sym) // SI-7294 step into the future and treat TupleN as final. ) ) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 8723046728..89fc55bc2c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -919,7 +919,7 @@ trait ContextErrors { def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type], tparams: List[Symbol], kindErrors: List[String]) = issueNormalTypeError(tree, - NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes.value)) + NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes)) //substExpr def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) = @@ -1058,9 +1058,6 @@ trait ContextErrors { issueSymbolTypeError(currentSym, prevSym.name + " is already defined as " + s2 + s3 + where) } - def MaxParametersCaseClassError(tree: Tree) = - issueNormalTypeError(tree, "Implementation restriction: case classes cannot have more than " + definitions.MaxFunctionArity + " parameters.") - def MissingParameterOrValTypeError(vparam: Tree) = issueNormalTypeError(vparam, "missing parameter type") @@ -1364,7 +1361,7 @@ trait ContextErrors { } def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = - compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value)) + compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes)) def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = compatibilityError( diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 9d5a9c819c..e89a860e0f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -79,9 +79,9 @@ trait Contexts { self: Analyzer => protected def rootImports(unit: CompilationUnit): List[Symbol] = { assert(definitions.isDefinitionsInitialized, "definitions uninitialized") - if (settings.noimports.value) Nil + if (settings.noimports) Nil else if (unit.isJava) RootImports.javaList - else if (settings.nopredef.value || treeInfo.noPredefImportForUnit(unit.body)) RootImports.javaAndScalaList + else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) RootImports.javaAndScalaList else RootImports.completeList } @@ -322,7 +322,7 @@ trait Contexts { self: Analyzer => def makeNewImport(imp: Import): Context = { val impInfo = new ImportInfo(imp, depth) - if (settings.lint.value && imp.pos.isDefined) // pos.isDefined excludes java.lang/scala/Predef imports + if (settings.lint && imp.pos.isDefined) // pos.isDefined excludes java.lang/scala/Predef imports allImportInfos(unit) ::= impInfo make(unit, imp, owner, scope, impInfo :: imports) @@ -406,7 +406,7 @@ trait Contexts { self: Analyzer => unit.error(pos, if (checking) "\n**** ERROR DURING INTERNAL CHECKING ****\n" + msg else msg) @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) { - if (settings.Yissuedebug.value) { + if (settings.Yissuedebug) { log("issue error: " + err.errMsg) (new Exception).printStackTrace() } @@ -912,7 +912,25 @@ trait Contexts { self: Analyzer => def lookupImport(imp: ImportInfo, requireExplicit: Boolean) = importedAccessibleSymbol(imp, name, requireExplicit) filter qualifies - while (!impSym.exists && imports.nonEmpty && imp1.depth > symbolDepth) { + // Java: A single-type-import declaration d in a compilation unit c of package p + // that imports a type named n shadows, throughout c, the declarations of: + // + // 1) any top level type named n declared in another compilation unit of p + // + // A type-import-on-demand declaration never causes any other declaration to be shadowed. + // + // Scala: Bindings of different kinds have a precedence defined on them: + // + // 1) Definitions and declarations that are local, inherited, or made available by a + // package clause in the same compilation unit where the definition occurs have + // highest precedence. + // 2) Explicit imports have next highest precedence. + def depthOk(imp: ImportInfo) = ( + imp.depth > symbolDepth + || (unit.isJava && imp.isExplicitImport(name) && imp.depth == symbolDepth) + ) + + while (!impSym.exists && imports.nonEmpty && depthOk(imports.head)) { impSym = lookupImport(imp1, requireExplicit = false) if (!impSym.exists) imports = imports.tail @@ -1047,7 +1065,7 @@ trait Contexts { self: Analyzer => if (result == NoSymbol) selectors = selectors.tail } - if (settings.lint.value && selectors.nonEmpty && result != NoSymbol && pos != NoPosition) + if (settings.lint && selectors.nonEmpty && result != NoSymbol && pos != NoPosition) recordUsage(current, result) // Harden against the fallout from bugs like SI-6745 diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala index 4075aa26f7..7092f00bff 100644 --- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala +++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala @@ -115,7 +115,7 @@ trait EtaExpansion { self: Analyzer => val origTpe = sym.tpe val isRepeated = definitions.isRepeatedParamType(origTpe) // SI-4176 Don't leak A* in eta-expanded function types. See t4176b.scala - val droppedStarTpe = if (settings.etaExpandKeepsStar.value) origTpe else dropIllegalStarTypes(origTpe) + val droppedStarTpe = if (settings.etaExpandKeepsStar) origTpe else dropIllegalStarTypes(origTpe) val valDef = ValDef(Modifiers(SYNTHETIC | PARAM), sym.name.toTermName, TypeTree(droppedStarTpe), EmptyTree) (valDef, isRepeated) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 8f52088b19..85e31347be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -298,7 +298,7 @@ trait Implicits { def pos = if (pos0 != NoPosition) pos0 else tree.pos def failure(what: Any, reason: String, pos: Position = this.pos): SearchResult = { - if (settings.XlogImplicits.value) + if (settings.XlogImplicits) reporter.echo(pos, what+" is not a valid implicit value for "+pt+" because:\n"+reason) SearchFailure } @@ -1118,7 +1118,7 @@ trait Implicits { ) // todo. migrate hardcoded materialization in Implicits to corresponding implicit macros val materializer = atPos(pos.focus)(gen.mkMethodCall(TagMaterializers(tagClass), List(tp), if (prefix != EmptyTree) List(prefix) else List())) - if (settings.XlogImplicits.value) reporter.echo(pos, "materializing requested %s.%s[%s] using %s".format(pre, tagClass.name, tp, materializer)) + if (settings.XlogImplicits) reporter.echo(pos, "materializing requested %s.%s[%s] using %s".format(pre, tagClass.name, tp, materializer)) if (context.macrosEnabled) success(materializer) // don't call `failure` here. if macros are disabled, we just fail silently // otherwise -Xlog-implicits will spam the long with zillions of "macros are disabled" @@ -1141,7 +1141,7 @@ trait Implicits { if (args contains EmptyTree) EmptyTree else typedPos(tree.pos.focus) { val mani = gen.mkManifestFactoryCall(full, constructor, tparg, args.toList) - if (settings.debug.value) println("generated manifest: "+mani) // DEBUG + if (settings.debug) println("generated manifest: "+mani) // DEBUG mani } @@ -1316,7 +1316,7 @@ trait Implicits { } } - if (result.isFailure && settings.debug.value) + if (result.isFailure && settings.debug) log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType) result diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 495ac1c086..8d7830897d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -131,7 +131,7 @@ trait Infer extends Checkable { else if (optionArgs.nonEmpty) if (nbSubPats == 1) { val productArity = productArgs.size - if (productArity > 1 && settings.lint.value) + if (productArity > 1 && settings.lint) global.currentUnit.warning(pos, s"extractor pattern binds a single value to a Product${productArity} of type ${optionArgs.head}") optionArgs } @@ -338,7 +338,7 @@ trait Infer extends Checkable { sym1 = sym if (sym1 == NoSymbol) { - if (settings.debug.value) { + if (settings.debug) { Console.println(context) Console.println(tree) Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType)) @@ -378,7 +378,7 @@ trait Infer extends Checkable { try pre.memberType(sym1) catch { case ex: MalformedType => - if (settings.debug.value) ex.printStackTrace + if (settings.debug) ex.printStackTrace val sym2 = underlyingSymbol(sym1) val itype = pre.memberType(sym2) ErrorUtils.issueTypeError( diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index fe9608368d..de3010c371 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -530,7 +530,13 @@ trait Namers extends MethodSynthesis { // Setting the position at the import means that if there is // more than one hidden name, the second will not be warned. // So it is the position of the actual hidden name. - checkNotRedundant(tree.pos withPoint fromPos, from, to) + // + // Note: java imports have precence over definitions in the same package + // so don't warn for them. There is a corresponding special treatment + // in the shadowing rules in typedIdent to (SI-7232). In any case, + // we shouldn't be emitting warnings for .java source files. + if (!context.unit.isJava) + checkNotRedundant(tree.pos withPoint fromPos, from, to) } } @@ -654,9 +660,6 @@ trait Namers extends MethodSynthesis { tree.symbol setInfo completerOf(tree) if (mods.isCase) { - if (primaryConstructorArity > MaxFunctionArity) - MaxParametersCaseClassError(tree) - val m = ensureCompanionObject(tree, caseModuleDef) m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree)) } @@ -669,7 +672,7 @@ trait Namers extends MethodSynthesis { m.updateAttachment(new ConstructorDefaultsAttachment(tree, null)) } val owner = tree.symbol.owner - if (settings.lint.value && owner.isPackageObjectClass && !mods.isImplicit) { + if (settings.lint && owner.isPackageObjectClass && !mods.isImplicit) { context.unit.warning(tree.pos, "it is not recommended to define classes/objects inside of package objects.\n" + "If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead." @@ -705,7 +708,7 @@ trait Namers extends MethodSynthesis { // check that lower bound is not an F-bound // but carefully: class Foo[T <: Bar[_ >: T]] should be allowed for (tp1 @ TypeRef(_, sym, _) <- lo) { - if (settings.breakCycles.value) { + if (settings.breakCycles) { if (!sym.maybeInitialize) { log(s"Cycle inspecting $lo for possible f-bounds: ${sym.fullLocationString}") return sym @@ -1373,7 +1376,9 @@ trait Namers extends MethodSynthesis { if (!cdef.symbol.hasAbstractFlag) namer.enterSyntheticSym(caseModuleApplyMeth(cdef)) - namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef)) + val primaryConstructorArity = treeInfo.firstConstructorArgs(cdef.impl.body).size + if (primaryConstructorArity <= MaxTupleArity) + namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef)) } def addCopyMethod(cdef: ClassDef, namer: Namer) { diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index d5ecb687b0..6921f8ce27 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -499,7 +499,7 @@ trait NamesDefaults { self: Analyzer => // disable conforms as a view... val errsBefore = reporter.ERROR.count try typer.silent { tpr => - val res = tpr.typed(arg, subst(paramtpe)) + val res = tpr.typed(arg.duplicate, subst(paramtpe)) // better warning for SI-5044: if `silent` was not actually silent give a hint to the user // [H]: the reason why `silent` is not silent is because the cyclic reference exception is // thrown in a context completely different from `context` here. The exception happens while diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 40428272cf..efd4fd804f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -142,7 +142,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } // This has become noisy with implicit classes. - if (settings.lint.value && settings.developer.value) { + if (settings.lint && settings.developer) { clazz.info.decls filter (x => x.isImplicit && x.typeParams.nonEmpty) foreach { sym => val alts = clazz.info.decl(sym.name).alternatives if (alts.size > 1) @@ -307,7 +307,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans infoStringWithLocation(other), infoStringWithLocation(member) ) - else if (settings.debug.value) + else if (settings.debug) analyzer.foundReqMsg(member.tpe, other.tpe) else "" @@ -407,7 +407,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) { // !?! this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here. // !!! is there a !?! convention? I'm !!!ing this to make sure it turns up on my searches. - if (!settings.overrideVars.value) + if (!settings.overrideVars) overrideError("cannot override a mutable variable") } else if (member.isAnyOverride && @@ -431,7 +431,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } else { checkOverrideTypes() checkOverrideDeprecated() - if (settings.warnNullaryOverride.value) { + if (settings.warnNullaryOverride) { if (other.paramss.isEmpty && !member.paramss.isEmpty) { unit.warning(member.pos, "non-nullary method overrides nullary method") } @@ -920,7 +920,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def apply(tp: Type) = mapOver(tp).normalize } - def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint.value) (fn, args) match { + def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint) (fn, args) match { case (tap@TypeApply(fun, targs), List(view: ApplyImplicitView)) if fun.symbol == Option_apply => unit.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567 case _ => @@ -1199,7 +1199,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans catch { case ex: TypeError => unit.error(tree0.pos, ex.getMessage()) - if (settings.explaintypes.value) { + if (settings.explaintypes) { val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds) (argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ)) (argtps, bounds).zipped map ((targ, bound) => explainTypes(targ, bound.hi)) @@ -1537,9 +1537,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case ValDef(_, _, _, _) | DefDef(_, _, _, _, _, _) => checkDeprecatedOvers(tree) checkInfiniteLoop(tree.asInstanceOf[ValOrDefDef]) - if (settings.warnNullaryUnit.value) + if (settings.warnNullaryUnit) checkNullaryMethodReturnType(sym) - if (settings.warnInaccessible.value) { + if (settings.warnInaccessible) { if (!sym.isConstructor && !sym.isEffectivelyFinal && !sym.isSynthetic) checkAccessibilityOfReferencedTypes(tree) } @@ -1642,7 +1642,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans result } catch { case ex: TypeError => - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() unit.error(tree.pos, ex.getMessage()) tree } finally { diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index fb692a1954..b4270ea322 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -91,7 +91,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT if (!found.isErroneous && !req.isErroneous) { val msg = analyzer.ErrorUtils.typeErrorMsg(found, req, typer.infer.isPossiblyMissingArgs(found, req)) typer.context.error(pos, analyzer.withAddendum(pos)(msg)) - if (settings.explaintypes.value) + if (settings.explaintypes) explainTypes(found, req) } } @@ -241,7 +241,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT // also exists in a superclass, because they may be surprised // to find out that a constructor parameter will shadow a // field. See SI-4762. - if (settings.lint.value) { + if (settings.lint) { if (sym.isPrivateLocal && sym.paramss.isEmpty) { qual.symbol.ancestors foreach { parent => parent.info.decls filterNot (x => x.isPrivate || x.hasLocalFlag) foreach { m2 => @@ -296,7 +296,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case Super(_, mix) => if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) { - if (!settings.overrideVars.value) + if (!settings.overrideVars) unit.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf) } else if (isDisallowed(sym)) { unit.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 5dc422bc1a..c531caa2e8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -93,7 +93,7 @@ trait SyntheticMethods extends ast.TreeDSL { // like Tags and Arrays which are not robust and infer things // which they shouldn't. val accessorLub = ( - if (settings.Xexperimental.value) { + if (settings.Xexperimental) { global.weakLub(accessors map (_.tpe.finalResultType))._1 match { case RefinedType(parents, decls) if !decls.isEmpty => intersectionType(parents) case tp => tp @@ -336,7 +336,7 @@ trait SyntheticMethods extends ast.TreeDSL { def shouldGenerate(m: Symbol) = { !hasOverridingImplementation(m) || { clazz.isDerivedValueClass && (m == Any_hashCode || m == Any_equals) && { - if (settings.lint.value) { + if (settings.lint) { (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") } diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index dc11c5fe96..1c8d37ef39 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -69,7 +69,7 @@ abstract class TreeCheckers extends Analyzer { // new symbols if (newSyms.nonEmpty) { informFn(newSyms.size + " new symbols.") - val toPrint = if (settings.debug.value) sortedNewSyms mkString " " else "" + val toPrint = if (settings.debug) sortedNewSyms mkString " " else "" newSyms.clear() if (toPrint != "") @@ -120,7 +120,7 @@ abstract class TreeCheckers extends Analyzer { def errorFn(msg: Any): Unit = {hasError = true; println("[check: %s] %s".format(phase.prev, msg))} def errorFn(pos: Position, msg: Any): Unit = errorFn(posstr(pos) + ": " + msg) def informFn(msg: Any) { - if (settings.verbose.value || settings.debug.value) + if (settings.verbose || settings.debug) println("[check: %s] %s".format(phase.prev, msg)) } @@ -137,7 +137,7 @@ abstract class TreeCheckers extends Analyzer { } def checkTrees() { - if (settings.verbose.value) + if (settings.verbose) Console.println("[consistency check at the beginning of phase " + phase + "]") currentRun.units foreach (x => wrap(x)(check(x))) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 46740cd03c..5f45fead91 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -545,7 +545,7 @@ trait TypeDiagnostics { // Error suppression will squash some of these warnings unless we circumvent it. // It is presumed if you are using a -Y option you would really like to hear // the warnings you've requested. - if (settings.warnDeadCode.value && context.unit.exists && treeOK(tree) && exprOK) + if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK) context.warning(tree.pos, "dead code following this construct", force = true) tree } @@ -585,7 +585,7 @@ trait TypeDiagnostics { // but it seems that throwErrors excludes some of the errors that should actually be // buffered, causing TypeErrors to fly around again. This needs some more investigation. if (!context0.reportErrors) throw ex - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() ex match { case CyclicReference(sym, info: TypeCompleter) => diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeStrings.scala b/src/compiler/scala/tools/nsc/typechecker/TypeStrings.scala index 65a3fedbd2..eb05486dca 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeStrings.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeStrings.scala @@ -50,7 +50,7 @@ trait StructuredTypeStrings extends DestructureTypes { else block(level, grouping)(name, nodes) } private def shortClass(x: Any) = { - if (settings.debug.value) { + if (settings.debug) { val name = (x.getClass.getName split '.').last val str = if (TypeStrings.isAnonClass(x.getClass)) name else (name split '$').last diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index fa5603dcb8..0be7192471 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -944,6 +944,57 @@ trait Typers extends Adaptations with Tags { // due to wrapClassTagUnapply, but when we support parameterized extractors, it will become // more common place) val extractor = overloadedExtractorOfObject orElse unapplyMember(tree.tpe) + def convertToCaseConstructor(clazz: Symbol): TypeTree = { + // convert synthetic unapply of case class to case class constructor + val prefix = tree.tpe.prefix + val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) + .setOriginal(tree) + + val skolems = new mutable.ListBuffer[TypeSymbol] + object variantToSkolem extends TypeMap(trackVariance = true) { + def apply(tp: Type) = mapOver(tp) match { + // !!! FIXME - skipping this when variance.isInvariant allows unsoundness, see SI-5189 + case TypeRef(NoPrefix, tpSym, Nil) if !variance.isInvariant && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm => + // must initialize or tpSym.tpe might see random type params!! + // without this, we'll get very weird types inferred in test/scaladoc/run/SI-5933.scala + // TODO: why is that?? + tpSym.initialize + val bounds = if (variance.isPositive) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe) + // origin must be the type param so we can deskolemize + val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds) + // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree ) + skolems += skolem + skolem.tpe + case tp1 => tp1 + } + } + + // have to open up the existential and put the skolems in scope + // can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance) + val ptSafe = variantToSkolem(pt) // TODO: pt.skolemizeExistential(context.owner, tree) ? + val freeVars = skolems.toList + + // use "tree" for the context, not context.tree: don't make another CaseDef context, + // as instantiateTypeVar's bounds would end up there + val ctorContext = context.makeNewScope(tree, context.owner) + freeVars foreach ctorContext.scope.enter + newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe) + + // simplify types without losing safety, + // so that we get rid of unnecessary type slack, and so that error messages don't unnecessarily refer to skolems + val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type) + val extrapolated = tree1.tpe match { + case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node + ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type + copyMethodType(tree1.tpe, ctorArgs, extrapolate(res)) + case tp => tp + } + + // once the containing CaseDef has been type checked (see typedCase), + // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems) + tree1 setType extrapolated + } + if (extractor != NoSymbol) { // if we did some ad-hoc overloading resolution, update the tree's symbol // do not update the symbol if the tree's symbol's type does not define an unapply member @@ -959,59 +1010,16 @@ trait Typers extends Adaptations with Tags { val clazz = unapplyParameterType(unapply) if (unapply.isCase && clazz.isCase) { - // convert synthetic unapply of case class to case class constructor - val prefix = tree.tpe.prefix - val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) - .setOriginal(tree) - - val skolems = new mutable.ListBuffer[TypeSymbol] - object variantToSkolem extends TypeMap(trackVariance = true) { - def apply(tp: Type) = mapOver(tp) match { - // !!! FIXME - skipping this when variance.isInvariant allows unsoundness, see SI-5189 - case TypeRef(NoPrefix, tpSym, Nil) if !variance.isInvariant && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm => - // must initialize or tpSym.tpe might see random type params!! - // without this, we'll get very weird types inferred in test/scaladoc/run/SI-5933.scala - // TODO: why is that?? - tpSym.initialize - val bounds = if (variance.isPositive) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe) - // origin must be the type param so we can deskolemize - val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds) - // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree ) - skolems += skolem - skolem.tpe - case tp1 => tp1 - } - } - - // have to open up the existential and put the skolems in scope - // can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance) - val ptSafe = variantToSkolem(pt) // TODO: pt.skolemizeExistential(context.owner, tree) ? - val freeVars = skolems.toList - - // use "tree" for the context, not context.tree: don't make another CaseDef context, - // as instantiateTypeVar's bounds would end up there - val ctorContext = context.makeNewScope(tree, context.owner) - freeVars foreach ctorContext.scope.enter - newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe) - - // simplify types without losing safety, - // so that we get rid of unnecessary type slack, and so that error messages don't unnecessarily refer to skolems - val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type) - val extrapolated = tree1.tpe match { - case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node - ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type - copyMethodType(tree1.tpe, ctorArgs, extrapolate(res)) - case tp => tp - } - - // once the containing CaseDef has been type checked (see typedCase), - // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems) - tree1 setType extrapolated + convertToCaseConstructor(clazz) } else { tree } } else { - CaseClassConstructorError(tree) + val clazz = tree.tpe.typeSymbol.linkedClassOfClass + if (clazz.isCase) + convertToCaseConstructor(clazz) + else + CaseClassConstructorError(tree) } } @@ -1133,14 +1141,14 @@ trait Typers extends Adaptations with Tags { // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially // infinite expansion if pt is constant type () if (sym == UnitClass) { // (12) - if (settings.warnValueDiscard.value) + if (settings.warnValueDiscard) context.unit.warning(tree.pos, "discarded non-Unit value") return typedPos(tree.pos, mode, pt) { Block(List(tree), Literal(Constant(()))) } } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) { - if (settings.warnNumericWiden.value) + if (settings.warnNumericWiden) context.unit.warning(tree.pos, "implicit numeric widening") return typedPos(tree.pos, mode, pt) { Select(tree, "to" + sym.name) @@ -1159,7 +1167,7 @@ trait Typers extends Adaptations with Tags { val coercion = inferView(tree, tree.tpe, pt, reportAmbiguous = true) if (coercion != EmptyTree) { def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe - if (settings.logImplicitConv.value) + if (settings.logImplicitConv) unit.echo(tree.pos, msg) debuglog(msg) @@ -1170,9 +1178,9 @@ trait Typers extends Adaptations with Tags { } } } - if (settings.debug.value) { + if (settings.debug) { log("error tree = " + tree) - if (settings.explaintypes.value) explainTypes(tree.tpe, pt) + if (settings.explaintypes) explainTypes(tree.tpe, pt) } val found = tree.tpe @@ -1286,7 +1294,7 @@ trait Typers extends Adaptations with Tags { inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match { case EmptyTree => qual case coercion => - if (settings.logImplicitConv.value) + if (settings.logImplicitConv) unit.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) @@ -1324,8 +1332,7 @@ trait Typers extends Adaptations with Tags { def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Mode, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = { def onError(reportError: => Tree): Tree = context.tree match { case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty => - ( silent (_.typedArgs(args, mode)) - map (_.asInstanceOf[List[Tree]]) + ( silent (_.typedArgs(args.map(_.duplicate), mode)) filter (xs => !(xs exists (_.isErrorTyped))) map (xs => adaptToArguments(qual, name, xs, WildcardType, reportAmbiguous, saveErrors)) orElse ( _ => reportError) @@ -1745,12 +1752,12 @@ trait Typers extends Adaptations with Tags { if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes && !context.owner.isSynthetic && // don't check synthetic concrete classes for virtuals (part of DEVIRTUALIZE) - !settings.noSelfCheck.value && // setting to suppress this very check + !settings.noSelfCheck && // setting to suppress this very check !selfType.isErroneous && !parent.tpe.isErroneous) { pending += ParentSelfTypeConformanceError(parent, selfType) - if (settings.explaintypes.value) explainTypes(selfType, parent.tpe.typeOfThis) + if (settings.explaintypes) explainTypes(selfType, parent.tpe.typeOfThis) } if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError)) @@ -2300,7 +2307,7 @@ trait Typers extends Adaptations with Tags { tdef.symbol.annotations.map(_.completeInfo()) // @specialized should not be pickled when compiling with -no-specialize - if (settings.nospecialization.value && currentRun.compiles(tdef.symbol)) { + if (settings.nospecialization && currentRun.compiles(tdef.symbol)) { tdef.symbol.removeAnnotation(definitions.SpecializedClass) tdef.symbol.deSkolemize.removeAnnotation(definitions.SpecializedClass) } @@ -2492,7 +2499,7 @@ trait Typers extends Adaptations with Tags { // TODO: add fallback __match sentinel to predef val matchStrategy: Tree = - if (!(newPatternMatching && settings.Xexperimental.value && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen + if (!(newPatternMatching && settings.Xexperimental && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match), EXPRmode, WildcardType), reportAmbiguousErrors = false) orElse (_ => null) if (matchStrategy ne null) // virtualize @@ -3558,7 +3565,7 @@ trait Typers extends Adaptations with Tags { // If there are dummy type arguments in typeFun part, it suggests we // must type the actual constructor call, not only the select. The value // arguments are how the type arguments will be inferred. - if (targs.isEmpty && typedFun0.exists(t => isDummyAppliedType(t.tpe))) + if (targs.isEmpty && typedFun0.exists(t => t.tpe != null && isDummyAppliedType(t.tpe))) logResult(s"Retyped $typedFun0 to find type args")(typed(argss.foldLeft(fun0)(Apply(_, _)))) else typedFun0 @@ -4085,7 +4092,7 @@ trait Typers extends Adaptations with Tags { if (ann.tpe == null) { // an annotated type val selfsym = - if (!settings.selfInAnnots.value) + if (!settings.selfInAnnots) NoSymbol else arg1.tpe.selfsym orElse { @@ -4372,6 +4379,12 @@ trait Typers extends Adaptations with Tags { treeCopy.New(tree, tpt1).setType(tp) } + def functionTypeWildcard(tree: Tree, arity: Int): Type = { + val tp = functionType(List.fill(arity)(WildcardType), WildcardType) + if (tp == NoType) MaxFunctionArityError(tree) + tp + } + def typedEta(expr1: Tree): Tree = expr1.tpe match { case TypeRef(_, ByNameParamClass, _) => val expr2 = Function(List(), expr1) setPos expr1.pos @@ -4383,10 +4396,10 @@ trait Typers extends Adaptations with Tags { typed1(expr2, mode, pt) case PolyType(_, MethodType(formals, _)) => if (isFunctionType(pt)) expr1 - else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) + else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length)) case MethodType(formals, _) => if (isFunctionType(pt)) expr1 - else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType)) + else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length)) case ErrorType => expr1 case _ => @@ -4658,7 +4671,7 @@ trait Typers extends Adaptations with Tags { if (isPastTyper) t.tpe match { case OverloadedType(pre, alts) => if (alts forall (s => (s.owner == ObjectClass) || (s.owner == AnyClass) || isPrimitiveValueClass(s.owner))) () - else if (settings.debug.value) printCaller( + else if (settings.debug) printCaller( s"""|Select received overloaded type during $phase, but typer is over. |If this type reaches the backend, we are likely doomed to crash. |$t has these overloads: @@ -4692,11 +4705,13 @@ trait Typers extends Adaptations with Tags { def handleMissing: Tree = { def errorTree = missingSelectErrorTree(tree, qual, name) def asTypeSelection = ( - if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { + if (context.unit.isJava && name.isTypeName) { + // SI-3120 Java uses the same syntax, A.B, to express selection from the + // value A and from the type A. We have to try both. atPos(tree.pos)(gen.convertToSelectFromType(qual, name)) match { case EmptyTree => None case tree1 => Some(typed1(tree1, mode, pt)) - } + } } else None ) @@ -4826,7 +4841,7 @@ trait Typers extends Adaptations with Tags { */ def typedIdent(tree: Tree, name: Name): Tree = { // setting to enable unqualified idents in empty package (used by the repl) - def inEmptyPackage = if (settings.exposeEmptyPackage.value) lookupInEmpty(name) else NoSymbol + def inEmptyPackage = if (settings.exposeEmptyPackage) lookupInEmpty(name) else NoSymbol def issue(err: AbsTypeError) = { // Avoiding some spurious error messages: see SI-2388. @@ -4947,7 +4962,7 @@ trait Typers extends Adaptations with Tags { AppliedTypeNoParametersError(tree, tpt1.tpe) } else { //Console.println("\{tpt1}:\{tpt1.symbol}:\{tpt1.symbol.info}") - if (settings.debug.value) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug + if (settings.debug) Console.println(tpt1+":"+tpt1.symbol+":"+tpt1.symbol.info)//debug AppliedTypeWrongNumberOfArgsError(tree, tpt1, tparams) } } @@ -5150,7 +5165,7 @@ trait Typers extends Adaptations with Tags { def typedLiteral(tree: Literal) = { val value = tree.value // Warn about likely interpolated strings which are missing their interpolators - if (settings.lint.value) value match { + if (settings.lint) value match { case Constant(s: String) => def names = InterpolatorIdentRegex findAllIn s map (n => newTermName(n stripPrefix "$")) val shouldWarn = ( @@ -5332,7 +5347,7 @@ trait Typers extends Adaptations with Tags { reportTypeError(context, tree.pos, ex) setError(tree) case ex: Exception => - if (settings.debug.value) // @M causes cyclic reference error + if (settings.debug) // @M causes cyclic reference error Console.println("exception when typing "+tree+", pt = "+ptPlugins) if (context != null && context.unit.exists && tree != null) logError("AT: " + (tree.pos).dbgString, ex) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 589e5ce6fd..d55dce70c7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -115,11 +115,16 @@ trait Unapplies extends ast.TreeDSL /** The module corresponding to a case class; overrides toString to show the module's name */ def caseModuleDef(cdef: ClassDef): ModuleDef = { - // > MaxFunctionArity is caught in Namers, but for nice error reporting instead of - // an abrupt crash we trim the list here. - def primaries = constrParamss(cdef).head take MaxFunctionArity map (_.tpt) - def inheritFromFun = !cdef.mods.hasAbstractFlag && cdef.tparams.isEmpty && constrParamss(cdef).length == 1 - def createFun = gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true) + val params = constrParamss(cdef) + def inheritFromFun = !cdef.mods.hasAbstractFlag && cdef.tparams.isEmpty && (params match { + case List(ps) if ps.length <= MaxFunctionArity => true + case _ => false + }) + def createFun = { + def primaries = params.head map (_.tpt) + gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true) + } + def parents = if (inheritFromFun) List(createFun) else Nil def toString = DefDef( Modifiers(OVERRIDE | FINAL | SYNTHETIC), diff --git a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala index 6997dbd402..4e1cf02a6e 100644 --- a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala +++ b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala @@ -10,7 +10,7 @@ import java.io.PrintStream * @param enabled: A condition that must be true for trace info to be produced. */ class SimpleTracer(out: PrintStream, enabled: Boolean = true) { - def apply[T](msg: String)(value: T): T = { + def apply[T](msg: => String)(value: T): T = { if (enabled) out.println(msg+value) value } diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 3e227ce8aa..f6ed5f8f1c 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -250,7 +250,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => throwIfErrors() val className = mdef.symbol.fullName - if (settings.debug.value) println("generated: "+className) + if (settings.debug) println("generated: "+className) def moduleFileName(className: String) = className + "$" val jclazz = jClass.forName(moduleFileName(className), true, classLoader) val jmeth = jclazz.getDeclaredMethods.find(_.getName == wrapperMethodName).get @@ -349,11 +349,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => lazy val exporter = importer.reverse def typeCheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = compiler.withCleanupCaches { - if (compiler.settings.verbose.value) println("importing "+tree+", expectedType = "+expectedType) + if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType) val ctree: compiler.Tree = importer.importTree(tree) val cexpectedType: compiler.Type = importer.importType(expectedType) - if (compiler.settings.verbose.value) println("typing "+ctree+", expectedType = "+expectedType) + if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType) val ttree: compiler.Tree = compiler.typeCheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled) val uttree = exporter.importTree(ttree) uttree @@ -369,12 +369,12 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } private def inferImplicit(tree: u.Tree, pt: u.Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: u.Position): u.Tree = compiler.withCleanupCaches { - if (compiler.settings.verbose.value) println(s"importing pt=$pt, tree=$tree, pos=$pos") + if (compiler.settings.verbose) println(s"importing pt=$pt, tree=$tree, pos=$pos") val ctree: compiler.Tree = importer.importTree(tree) val cpt: compiler.Type = importer.importType(pt) val cpos: compiler.Position = importer.importPosition(pos) - if (compiler.settings.verbose.value) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled)) + if (compiler.settings.verbose) println("inferring implicit %s of type %s, macros = %s".format(if (isView) "view" else "value", pt, !withMacrosDisabled)) val itree: compiler.Tree = compiler.inferImplicit(ctree, cpt, isView = isView, silent = silent, withMacrosDisabled = withMacrosDisabled, pos = cpos) val uitree = exporter.importTree(itree) uitree @@ -395,17 +395,17 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } def parse(code: String): u.Tree = { - if (compiler.settings.verbose.value) println("parsing "+code) + if (compiler.settings.verbose) println("parsing "+code) val ctree: compiler.Tree = compiler.parse(code) val utree = exporter.importTree(ctree) utree } def compile(tree: u.Tree): () => Any = { - if (compiler.settings.verbose.value) println("importing "+tree) + if (compiler.settings.verbose) println("importing "+tree) val ctree: compiler.Tree = importer.importTree(tree) - if (compiler.settings.verbose.value) println("compiling "+ctree) + if (compiler.settings.verbose) println("compiling "+ctree) compiler.compile(ctree) } diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index d8e545e6b1..8d65c40a01 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -146,7 +146,7 @@ object PathResolver { import PathResolver.{ Defaults, Environment, ppcp } class PathResolver(settings: Settings, context: JavaContext) { - def this(settings: Settings) = this(settings, if (settings.inline.value) new JavaContext else DefaultJavaContext) + def this(settings: Settings) = this(settings, if (settings.inline) new JavaContext else DefaultJavaContext) private def cmdLineOrElse(name: String, alt: String) = { (commandLineFor(name) match { @@ -240,7 +240,7 @@ class PathResolver(settings: Settings, context: JavaContext) { lazy val result = { val cp = new JavaClassPath(containers.toIndexedSeq, context) - if (settings.Ylogcp.value) { + if (settings.Ylogcp) { Console.println("Classpath built from " + settings.toConciseString) Console.println("Defaults: " + PathResolver.Defaults) Console.println("Calculated: " + Calculated) diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 099a882f10..dbdb2d02b6 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -547,7 +547,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") for (s <- allSources; if !ignoredFiles(s.file); unit <- getUnit(s)) { try { if (!unit.isUpToDate) - if (unit.problems.isEmpty || !settings.YpresentationStrict.value) + if (unit.problems.isEmpty || !settings.YpresentationStrict) typeCheck(unit) else debugLog("%s has syntax errors. Skipped typechecking".format(unit)) else debugLog("already up to date: "+unit) diff --git a/src/interactive/scala/tools/nsc/interactive/Main.scala b/src/interactive/scala/tools/nsc/interactive/Main.scala index 3b4a36f62d..c838606f02 100644 --- a/src/interactive/scala/tools/nsc/interactive/Main.scala +++ b/src/interactive/scala/tools/nsc/interactive/Main.scala @@ -12,7 +12,7 @@ package interactive */ object Main extends nsc.MainClass { override def processSettingsHook(): Boolean = { - if (this.settings.Yidedebug.value) { + if (this.settings.Yidedebug) { this.settings.Xprintpos.value = true this.settings.Yrangepos.value = true val compiler = new interactive.Global(this.settings, this.reporter) diff --git a/src/interactive/scala/tools/nsc/interactive/REPL.scala b/src/interactive/scala/tools/nsc/interactive/REPL.scala index 04c06b9357..432400ecd2 100644 --- a/src/interactive/scala/tools/nsc/interactive/REPL.scala +++ b/src/interactive/scala/tools/nsc/interactive/REPL.scala @@ -32,7 +32,7 @@ object REPL { val settings = new Settings(replError) reporter = new ConsoleReporter(settings) val command = new CompilerCommand(args.toList, settings) - if (command.settings.version.value) + if (command.settings.version) reporter.echo(versionMsg) else { try { @@ -50,7 +50,7 @@ object REPL { } } catch { case ex @ FatalError(msg) => - if (true || command.settings.debug.value) // !!! + if (true || command.settings.debug) // !!! ex.printStackTrace() reporter.error(null, "fatal error: " + msg) } diff --git a/src/interactive/scala/tools/nsc/interactive/tests/Tester.scala b/src/interactive/scala/tools/nsc/interactive/tests/Tester.scala index 9382d5890f..8a47c1df37 100644 --- a/src/interactive/scala/tools/nsc/interactive/tests/Tester.scala +++ b/src/interactive/scala/tools/nsc/interactive/tests/Tester.scala @@ -17,7 +17,7 @@ class Tester(ntests: Int, inputs: Array[SourceFile], settings: Settings) { val compiler = new Global(settings, reporter) def askAndListen[T, U](msg: String, arg: T, op: (T, Response[U]) => Unit) { - if (settings.verbose.value) print(msg+" "+arg+": ") + if (settings.verbose) print(msg+" "+arg+": ") val TIMEOUT = 10 // ms val limit = System.currentTimeMillis() + randomDelayMillis val res = new Response[U] @@ -28,7 +28,7 @@ class Tester(ntests: Int, inputs: Array[SourceFile], settings: Settings) { } else res.get(TIMEOUT) match { case Some(Left(t)) => /**/ - if (settings.verbose.value) println(t) + if (settings.verbose) println(t) case Some(Right(ex)) => ex.printStackTrace() println(ex) diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index d91f70da75..66fbad7643 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -41,12 +41,7 @@ package object parallel { private[parallel] def outofbounds(idx: Int) = throw new IndexOutOfBoundsException(idx.toString) - private[parallel] def getTaskSupport: TaskSupport = - if (scala.util.Properties.isJavaAtLeast("1.6")) { - val vendor = scala.util.Properties.javaVmVendor - if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinTaskSupport - else new ThreadPoolTaskSupport - } else new ThreadPoolTaskSupport + private[parallel] def getTaskSupport: TaskSupport = new ForkJoinTaskSupport val defaultTaskSupport: TaskSupport = getTaskSupport diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 10e6d7d9a4..97d7da3f2d 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -1,5 +1,7 @@ package scala +import java.lang.reflect.{ AccessibleObject => jAccessibleObject } + package object reflect { // in the new scheme of things ClassManifests are aliased to ClassTags @@ -42,6 +44,18 @@ package object reflect { def classTag[T](implicit ctag: ClassTag[T]) = ctag + /** Make a java reflection object accessible, if it is not already + * and it is possible to do so. If a SecurityException is thrown in the + * attempt, it is caught and discarded. + */ + def ensureAccessible[T <: jAccessibleObject](m: T): T = { + if (!m.isAccessible) { + try m setAccessible true + catch { case _: SecurityException => } // does nothing + } + m + } + // anchor for the class tag materialization macro emitted during tag materialization in Implicits.scala // implementation is hardwired into `scala.reflect.reify.Taggers` // using the mechanism implemented in `scala.tools.reflect.FastTrack` diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 753dd0205e..ea1f392e2b 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -158,13 +158,7 @@ object ScalaRunTime { // Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957 // More background at ticket #2318. - def ensureAccessible(m: JMethod): JMethod = { - if (!m.isAccessible) { - try m setAccessible true - catch { case _: SecurityException => () } - } - m - } + def ensureAccessible(m: JMethod): JMethod = scala.reflect.ensureAccessible(m) def checkInitialized[T <: AnyRef](x: T): T = if (x == null) throw new UninitializedError else x diff --git a/src/partest/scala/tools/partest/nest/Diff.java b/src/partest/scala/tools/partest/nest/Diff.java deleted file mode 100644 index f69fc6858b..0000000000 --- a/src/partest/scala/tools/partest/nest/Diff.java +++ /dev/null @@ -1,873 +0,0 @@ - -package scala.tools.partest.nest; - -import java.util.Hashtable; - -/** A class to compare IndexedSeqs of objects. The result of comparison - is a list of <code>change</code> objects which form an - edit script. The objects compared are traditionally lines - of text from two files. Comparison options such as "ignore - whitespace" are implemented by modifying the <code>equals</code> - and <code>hashcode</code> methods for the objects compared. -<p> - The basic algorithm is described in: </br> - "An O(ND) Difference Algorithm and its Variations", Eugene Myers, - Algorithmica Vol. 1 No. 2, 1986, p 251. -<p> - This class outputs different results from GNU diff 1.15 on some - inputs. Our results are actually better (smaller change list, smaller - total size of changes), but it would be nice to know why. Perhaps - there is a memory overwrite bug in GNU diff 1.15. - - @author Stuart D. Gathman, translated from GNU diff 1.15 - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the <a href=COPYING.txt> - GNU General Public License</a> - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -public class Diff { - - /** Prepare to find differences between two arrays. Each element of - the arrays is translated to an "equivalence number" based on - the result of <code>equals</code>. The original Object arrays - are no longer needed for computing the differences. They will - be needed again later to print the results of the comparison as - an edit script, if desired. - */ - public Diff(Object[] a,Object[] b) { - Hashtable<Object, Integer> h = new Hashtable<Object, Integer>(a.length + b.length); - filevec[0] = new file_data(a,h); - filevec[1] = new file_data(b,h); - } - - /** 1 more than the maximum equivalence value used for this or its - sibling file. */ - private int equiv_max = 1; - - /** When set to true, the comparison uses a heuristic to speed it up. - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - public boolean heuristic = false; - - /** When set to true, the algorithm returns a guarranteed minimal - set of changes. This makes things slower, sometimes much slower. */ - public boolean no_discards = false; - - private int[] xvec, yvec; /* IndexedSeqs being compared. */ - private int[] fdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the forward - search of the edit matrix. */ - private int[] bdiag; /* IndexedSeq, indexed by diagonal, containing - the X coordinate of the point furthest - along the given diagonal in the backward - search of the edit matrix. */ - private int fdiagoff, bdiagoff; - private final file_data[] filevec = new file_data[2]; - private int cost; - - /** Find the midpoint of the shortest edit script for a specified - portion of the two files. - - We scan from the beginnings of the files, and simultaneously from the ends, - doing a breadth-first search through the space of edit-sequence. - When the two searches meet, we have found the midpoint of the shortest - edit sequence. - - The value returned is the number of the diagonal on which the midpoint lies. - The diagonal number equals the number of inserted lines minus the number - of deleted lines (counting only lines before the midpoint). - The edit cost is stored into COST; this is the total number of - lines inserted or deleted (counting only lines before the midpoint). - - This function assumes that the first lines of the specified portions - of the two files do not match, and likewise that the last lines do not - match. The caller must trim matching lines from the beginning and end - of the portions it is going to specify. - - Note that if we return the "wrong" diagonal value, or if - the value of bdiag at that diagonal is "wrong", - the worst this can do is cause suboptimal diff output. - It cannot cause incorrect diff output. */ - - private int diag (int xoff, int xlim, int yoff, int ylim) { - final int[] fd = fdiag; // Give the compiler a chance. - final int[] bd = bdiag; // Additional help for the compiler. - final int[] xv = xvec; // Still more help for the compiler. - final int[] yv = yvec; // And more and more . . . - final int dmin = xoff - ylim; // Minimum valid diagonal. - final int dmax = xlim - yoff; // Maximum valid diagonal. - final int fmid = xoff - yoff; // Center diagonal of top-down search. - final int bmid = xlim - ylim; // Center diagonal of bottom-up search. - int fmin = fmid, fmax = fmid; // Limits of top-down search. - int bmin = bmid, bmax = bmid; // Limits of bottom-up search. - /* True if southeast corner is on an odd - diagonal with respect to the northwest. */ - final boolean odd = (fmid - bmid & 1) != 0; - - fd[fdiagoff + fmid] = xoff; - bd[bdiagoff + bmid] = xlim; - - for (int c = 1;; ++c) - { - int d; /* Active diagonal. */ - boolean big_snake = false; - - /* Extend the top-down search by an edit step in each diagonal. */ - if (fmin > dmin) - fd[fdiagoff + --fmin - 1] = -1; - else - ++fmin; - if (fmax < dmax) - fd[fdiagoff + ++fmax + 1] = -1; - else - --fmax; - for (d = fmax; d >= fmin; d -= 2) - { - int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1]; - - if (tlo >= thi) - x = tlo + 1; - else - x = thi; - oldx = x; - y = x - d; - while (x < xlim && y < ylim && xv[x] == yv[y]) { - ++x; ++y; - } - if (x - oldx > 20) - big_snake = true; - fd[fdiagoff + d] = x; - if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c - 1; - return d; - } - } - - /* Similar extend the bottom-up search. */ - if (bmin > dmin) - bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE; - else - ++bmin; - if (bmax < dmax) - bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE; - else - --bmax; - for (d = bmax; d >= bmin; d -= 2) - { - int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1]; - - if (tlo < thi) - x = tlo; - else - x = thi - 1; - oldx = x; - y = x - d; - while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) { - --x; --y; - } - if (oldx - x > 20) - big_snake = true; - bd[bdiagoff + d] = x; - if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) - { - cost = 2 * c; - return d; - } - } - - /* Heuristic: check occasionally for a diagonal that has made - lots of progress compared with the edit distance. - If we have any such, find the one that has made the most - progress and return it as if it had succeeded. - - With this heuristic, for files with a constant small density - of changes, the algorithm is linear in the file size. */ - - if (c > 200 && big_snake && heuristic) - { - int best = 0; - int bestpos = -1; - - for (d = fmax; d >= fmin; d -= 2) - { - int dd = d - fmid; - if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if (fd[fdiagoff + d] * 2 - dd > best - && fd[fdiagoff + d] - xoff > 20 - && fd[fdiagoff + d] - d - yoff > 20) - { - int k; - int x = fd[fdiagoff + d]; - - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - for (k = 1; k <= 20; k++) - if (xvec[x - k] != yvec[x - d - k]) - break; - - if (k == 21) - { - best = fd[fdiagoff + d] * 2 - dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - - best = 0; - for (d = bmax; d >= bmin; d -= 2) - { - int dd = d - bmid; - if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) - { - if ((xlim - bd[bdiagoff + d]) * 2 + dd > best - && xlim - bd[bdiagoff + d] > 20 - && ylim - (bd[bdiagoff + d] - d) > 20) - { - /* We have a good enough best diagonal; - now insist that it end with a significant snake. */ - int k; - int x = bd[bdiagoff + d]; - - for (k = 0; k < 20; k++) - if (xvec[x + k] != yvec[x - d + k]) - break; - if (k == 20) - { - best = (xlim - bd[bdiagoff + d]) * 2 + dd; - bestpos = d; - } - } - } - } - if (best > 0) - { - cost = 2 * c - 1; - return bestpos; - } - } - } - } - - /** Compare in detail contiguous subsequences of the two files - which are known, as a whole, to match each other. - - The results are recorded in the IndexedSeqs filevec[N].changed_flag, by - storing a 1 in the element for each line that is an insertion or deletion. - - The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. - - Note that XLIM, YLIM are exclusive bounds. - All line numbers are origin-0 and discarded lines are not counted. */ - - private void compareseq (int xoff, int xlim, int yoff, int ylim) { - /* Slide down the bottom initial diagonal. */ - while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) { - ++xoff; ++yoff; - } - /* Slide up the top initial diagonal. */ - while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) { - --xlim; --ylim; - } - - /* Handle simple cases. */ - if (xoff == xlim) - while (yoff < ylim) - filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true; - else if (yoff == ylim) - while (xoff < xlim) - filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true; - else - { - /* Find a point of correspondence in the middle of the files. */ - - int d = diag (xoff, xlim, yoff, ylim); - int c = cost; - int f = fdiag[fdiagoff + d]; - int b = bdiag[bdiagoff + d]; - - if (c == 1) - { - /* This should be impossible, because it implies that - one of the two subsequences is empty, - and that case was handled above without calling `diag'. - Let's verify that this is true. */ - throw new IllegalArgumentException("Empty subsequence"); - } - else - { - /* Use that point to split this problem into two subproblems. */ - compareseq (xoff, b, yoff, b - d); - /* This used to use f instead of b, - but that is incorrect! - It is not necessarily the case that diagonal d - has a snake from b to f. */ - compareseq (b, xlim, b - d, ylim); - } - } - } - - /** Discard lines from one file that have no matches in the other file. - */ - - private void discard_confusing_lines() { - filevec[0].discard_confusing_lines(filevec[1]); - filevec[1].discard_confusing_lines(filevec[0]); - } - - private boolean inhibit = false; - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - */ - - private void shift_boundaries() { - if (inhibit) - return; - filevec[0].shift_boundaries(filevec[1]); - filevec[1].shift_boundaries(filevec[0]); - } - - public interface ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script. - @param changed0 true for lines in first file which do not match 2nd - @param len0 number of lines in first file - @param changed1 true for lines in 2nd file which do not match 1st - @param len1 number of lines in 2nd file - @return a linked list of changes - or null - */ - public change build_script( - boolean[] changed0,int len0, - boolean[] changed1,int len1 - ); - } - - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in reverse order. */ - - static class ReverseScript implements ScriptBuilder { - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = 0, i1 = 0; - while (i0 < len0 || i1 < len1) { - if (changed0[1+i0] || changed1[1+i1]) { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[1+i0]) ++i0; - while (changed1[1+i1]) ++i1; - - /* Record this change. */ - script = new change(line0, line1, i0 - line0, i1 - line1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0++; i1++; - } - - return script; - } - } - - static class ForwardScript implements ScriptBuilder { - /** Scan the tables of which lines are inserted and deleted, - producing an edit script in forward order. */ - public change build_script( - final boolean[] changed0,int len0, - final boolean[] changed1,int len1) - { - change script = null; - int i0 = len0, i1 = len1; - - while (i0 >= 0 || i1 >= 0) - { - if (changed0[i0] || changed1[i1]) - { - int line0 = i0, line1 = i1; - - /* Find # lines changed here in each file. */ - while (changed0[i0]) --i0; - while (changed1[i1]) --i1; - - /* Record this change. */ - script = new change(i0, i1, line0 - i0, line1 - i1, script); - } - - /* We have reached lines in the two files that match each other. */ - i0--; i1--; - } - - return script; - } - } - - /** Standard ScriptBuilders. */ - public final static ScriptBuilder - forwardScript = new ForwardScript(), - reverseScript = new ReverseScript(); - - /* Report the differences of two files. DEPTH is the current directory - depth. */ - public final change diff_2(final boolean reverse) { - return diff(reverse ? reverseScript : forwardScript); - } - - /** Get the results of comparison as an edit script. The script - is described by a list of changes. The standard ScriptBuilder - implementations provide for forward and reverse edit scripts. - Alternate implementations could, for instance, list common elements - instead of differences. - @param bld an object to build the script from change flags - @return the head of a list of changes - */ - public change diff(final ScriptBuilder bld) { - - /* Some lines are obviously insertions or deletions - because they don't match anything. Detect them now, - and avoid even thinking about them in the main comparison algorithm. */ - - discard_confusing_lines (); - - /* Now do the main comparison algorithm, considering just the - undiscarded lines. */ - - xvec = filevec[0].undiscarded; - yvec = filevec[1].undiscarded; - - int diags = - filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3; - fdiag = new int[diags]; - fdiagoff = filevec[1].nondiscarded_lines + 1; - bdiag = new int[diags]; - bdiagoff = filevec[1].nondiscarded_lines + 1; - - compareseq (0, filevec[0].nondiscarded_lines, - 0, filevec[1].nondiscarded_lines); - fdiag = null; - bdiag = null; - - /* Modify the results slightly to make them prettier - in cases where that can validly be done. */ - - shift_boundaries (); - - /* Get the results of comparison in the form of a chain - of `struct change's -- an edit script. */ - return bld.build_script( - filevec[0].changed_flag, - filevec[0].buffered_lines, - filevec[1].changed_flag, - filevec[1].buffered_lines - ); - - } - - /** The result of comparison is an "edit script": a chain of change objects. - Each change represents one place where some lines are deleted - and some are inserted. - - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - - public static class change { - /** Previous or next edit command. */ - public change link; - /** # lines of file 1 changed here. */ - public final int inserted; - /** # lines of file 0 changed here. */ - public final int deleted; - /** Line number of 1st deleted line. */ - public final int line0; - /** Line number of 1st inserted line. */ - public final int line1; - - /** Cons an additional entry onto the front of an edit script OLD. - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - public change(int line0, int line1, int deleted, int inserted, change old) { - this.line0 = line0; - this.line1 = line1; - this.inserted = inserted; - this.deleted = deleted; - this.link = old; - //System.err.println(line0+","+line1+","+inserted+","+deleted); - } - } - - /** Data on one input file being compared. - */ - - class file_data { - - /** Allocate changed array for the results of comparison. */ - void clear() { - /* Allocate a flag for each line of each file, saying whether that line - is an insertion or deletion. - Allocate an extra element, always zero, at each end of each IndexedSeq. - */ - changed_flag = new boolean[buffered_lines + 2]; - } - - /** Return equiv_count[I] as the number of lines in this file - that fall in equivalence class I. - @return the array of equivalence class counts. - */ - int[] equivCount() { - int[] equiv_count = new int[equiv_max]; - for (int i = 0; i < buffered_lines; ++i) - ++equiv_count[equivs[i]]; - return equiv_count; - } - - /** Discard lines that have no matches in another file. - - A line which is discarded will not be considered by the actual - comparison algorithm; it will be as if that line were not in the file. - The file's `realindexes' table maps virtual line numbers - (which don't count the discarded lines) into real line numbers; - this is how the actual comparison algorithm produces results - that are comprehensible when the discarded lines are counted. -<p> - When we discard a line, we also mark it as a deletion or insertion - so that it will be printed in the output. - @param f the other file - */ - void discard_confusing_lines(file_data f) { - clear(); - /* Set up table of which lines are going to be discarded. */ - final byte[] discarded = discardable(f.equivCount()); - - /* Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - filterDiscards(discarded); - - /* Actually discard the lines. */ - discard(discarded); - } - - /** Mark to be discarded each line that matches no line of another file. - If a line matches many lines, mark it as provisionally discardable. - @see equivCount() - @param counts The count of each equivalence number for the other file. - @return 0=nondiscardable, 1=discardable or 2=provisionally discardable - for each line - */ - - private byte[] discardable(final int[] counts) { - final int end = buffered_lines; - final byte[] discards = new byte[end]; - final int[] equivs = this.equivs; - int many = 5; - int tem = end / 64; - - /* Multiply MANY by approximate square root of number of lines. - That is the threshold for provisionally discardable lines. */ - while ((tem = tem >> 2) > 0) - many *= 2; - - for (int i = 0; i < end; i++) - { - int nmatch; - if (equivs[i] == 0) - continue; - nmatch = counts[equivs[i]]; - if (nmatch == 0) - discards[i] = 1; - else if (nmatch > many) - discards[i] = 2; - } - return discards; - } - - /** Don't really discard the provisional lines except when they occur - in a run of discardables, with nonprovisionals at the beginning - and end. */ - - private void filterDiscards(final byte[] discards) { - final int end = buffered_lines; - - for (int i = 0; i < end; i++) - { - /* Cancel provisional discards not in middle of run of discards. */ - if (discards[i] == 2) - discards[i] = 0; - else if (discards[i] != 0) - { - /* We have found a nonprovisional discard. */ - int j; - int length; - int provisional = 0; - - /* Find end of this run of discardable lines. - Count how many are provisionally discardable. */ - for (j = i; j < end; j++) - { - if (discards[j] == 0) - break; - if (discards[j] == 2) - ++provisional; - } - - /* Cancel provisional discards at end, and shrink the run. */ - while (j > i && discards[j - 1] == 2) { - discards[--j] = 0; --provisional; - } - - /* Now we have the length of a run of discardable lines - whose first and last are not provisional. */ - length = j - i; - - /* If 1/4 of the lines in the run are provisional, - cancel discarding of all provisional lines in the run. */ - if (provisional * 4 > length) - { - while (j > i) - if (discards[--j] == 2) - discards[j] = 0; - } - else - { - int consec; - int minimum = 1; - int tem = length / 4; - - /* MINIMUM is approximate square root of LENGTH/4. - A subrun of two or more provisionals can stand - when LENGTH is at least 16. - A subrun of 4 or more can stand when LENGTH >= 64. */ - while ((tem = tem >> 2) > 0) - minimum *= 2; - minimum++; - - /* Cancel any subrun of MINIMUM or more provisionals - within the larger run. */ - for (j = 0, consec = 0; j < length; j++) - if (discards[i + j] != 2) - consec = 0; - else if (minimum == ++consec) - /* Back up to start of subrun, to cancel it all. */ - j -= consec; - else if (minimum < consec) - discards[i + j] = 0; - - /* Scan from beginning of run - until we find 3 or more nonprovisionals in a row - or until the first nonprovisional at least 8 lines in. - Until that point, cancel any provisionals. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i + j] == 1) - break; - if (discards[i + j] == 2) { - consec = 0; discards[i + j] = 0; - } - else if (discards[i + j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - - /* I advances to the last line of the run. */ - i += length - 1; - - /* Same thing, from end. */ - for (j = 0, consec = 0; j < length; j++) - { - if (j >= 8 && discards[i - j] == 1) - break; - if (discards[i - j] == 2) { - consec = 0; discards[i - j] = 0; - } - else if (discards[i - j] == 0) - consec = 0; - else - consec++; - if (consec == 3) - break; - } - } - } - } - } - - /** Actually discard the lines. - @param discards flags lines to be discarded - */ - private void discard(final byte[] discards) { - final int end = buffered_lines; - int j = 0; - for (int i = 0; i < end; ++i) - if (no_discards || discards[i] == 0) - { - undiscarded[j] = equivs[i]; - realindexes[j++] = i; - } - else - changed_flag[1+i] = true; - nondiscarded_lines = j; - } - - file_data(Object[] data, Hashtable<Object, Integer> h) { - buffered_lines = data.length; - - equivs = new int[buffered_lines]; - undiscarded = new int[buffered_lines]; - realindexes = new int[buffered_lines]; - - for (int i = 0; i < data.length; ++i) { - Integer ir = h.get(data[i]); - if (ir == null) - h.put(data[i], new Integer(equivs[i] = equiv_max++)); - else - equivs[i] = ir.intValue(); - } - } - - /** Adjust inserts/deletes of blank lines to join changes - as much as possible. - - We do something when a run of changed lines include a blank - line at one end and have an excluded blank line at the other. - We are free to choose which blank line is included. - `compareseq' always chooses the one at the beginning, - but usually it is cleaner to consider the following blank line - to be the "change". The only exception is if the preceding blank line - would join this change to other changes. - @param f the file being compared against - */ - - void shift_boundaries(file_data f) { - final boolean[] changed = changed_flag; - final boolean[] other_changed = f.changed_flag; - int i = 0; - int j = 0; - int i_end = buffered_lines; - int preceding = -1; - int other_preceding = -1; - - for (;;) - { - int start, end, other_start; - - /* Scan forwards to find beginning of another run of changes. - Also keep track of the corresponding point in the other file. */ - - while (i < i_end && !changed[1+i]) - { - while (other_changed[1+j++]) - /* Non-corresponding lines in the other file - will count as the preceding batch of changes. */ - other_preceding = j; - i++; - } - - if (i == i_end) - break; - - start = i; - other_start = j; - - for (;;) - { - /* Now find the end of this run of changes. */ - - while (i < i_end && changed[1+i]) i++; - end = i; - - /* If the first changed line matches the following unchanged one, - and this run does not follow right after a previous run, - and there are no lines deleted from the other file here, - then classify the first changed line as unchanged - and the following line as changed in its place. */ - - /* You might ask, how could this run follow right after another? - Only because the previous run was shifted here. */ - - if (end != i_end - && equivs[start] == equivs[end] - && !other_changed[1+j] - && end != i_end - && !((preceding >= 0 && start == preceding) - || (other_preceding >= 0 - && other_start == other_preceding))) - { - changed[1+end++] = true; - changed[1+start++] = false; - ++i; - /* Since one line-that-matches is now before this run - instead of after, we must advance in the other file - to keep in synch. */ - ++j; - } - else - break; - } - - preceding = i; - other_preceding = j; - } - } - - /** Number of elements (lines) in this file. */ - final int buffered_lines; - - /** IndexedSeq, indexed by line number, containing an equivalence code for - each line. It is this IndexedSeq that is actually compared with that - of another file to generate differences. */ - private final int[] equivs; - - /** IndexedSeq, like the previous one except that - the elements for discarded lines have been squeezed out. */ - final int[] undiscarded; - - /** IndexedSeq mapping virtual line numbers (not counting discarded lines) - to real ones (counting those lines). Both are origin-0. */ - final int[] realindexes; - - /** Total number of nondiscarded lines. */ - int nondiscarded_lines; - - /** Array, indexed by real origin-1 line number, - containing true for a line that is an insertion or a deletion. - The results of comparison are stored here. */ - boolean[] changed_flag; - - } -} diff --git a/src/partest/scala/tools/partest/nest/DiffPrint.java b/src/partest/scala/tools/partest/nest/DiffPrint.java deleted file mode 100644 index 31f9a1bc79..0000000000 --- a/src/partest/scala/tools/partest/nest/DiffPrint.java +++ /dev/null @@ -1,606 +0,0 @@ - -package scala.tools.partest.nest; - -import java.io.*; -import java.util.Vector; -import java.util.Date; -//import com.objectspace.jgl.predicates.UnaryPredicate; - -interface UnaryPredicate { - boolean execute(Object obj); -} - -/** A simple framework for printing change lists produced by <code>Diff</code>. - @see bmsi.util.Diff - @author Stuart D. Gathman - Copyright (C) 2000 Business Management Systems, Inc. -<p> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. -<p> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -<p> - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -public class DiffPrint { - /** A Base class for printing edit scripts produced by Diff. - This class divides the change list into "hunks", and calls - <code>print_hunk</code> for each hunk. Various utility methods - are provided as well. - */ - public static abstract class Base { - protected Base(Object[] a,Object[] b, Writer w) { - outfile = new PrintWriter(w); - file0 = a; - file1 = b; - } - /** Set to ignore certain kinds of lines when printing - an edit script. For example, ignoring blank lines or comments. - */ - protected UnaryPredicate ignore = null; - - /** Set to the lines of the files being compared. - */ - protected Object[] file0, file1; - - /** Divide SCRIPT into pieces by calling HUNKFUN and - print each piece with PRINTFUN. - Both functions take one arg, an edit script. - - PRINTFUN takes a subscript which belongs together (with a null - link at the end) and prints it. */ - public void print_script(Diff.change script) { - Diff.change next = script; - - while (next != null) - { - Diff.change t, end; - - /* Find a set of changes that belong together. */ - t = next; - end = hunkfun(next); - - /* Disconnect them from the rest of the changes, - making them a hunk, and remember the rest for next iteration. */ - next = end.link; - end.link = null; - //if (DEBUG) - // debug_script(t); - - /* Print this hunk. */ - print_hunk(t); - - /* Reconnect the script so it will all be freed properly. */ - end.link = next; - } - outfile.flush(); - } - - /** Called with the tail of the script - and returns the last link that belongs together with the start - of the tail. */ - - protected Diff.change hunkfun(Diff.change hunk) { - return hunk; - } - - protected int first0, last0, first1, last1, deletes, inserts; - protected PrintWriter outfile; - - /** Look at a hunk of edit script and report the range of lines in each file - that it applies to. HUNK is the start of the hunk, which is a chain - of `struct change'. The first and last line numbers of file 0 are stored - in *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. - Note that these are internal line numbers that count from 0. - - If no lines from file 0 are deleted, then FIRST0 is LAST0+1. - - Also set *DELETES nonzero if any lines of file 0 are deleted - and set *INSERTS nonzero if any lines of file 1 are inserted. - If only ignorable lines are inserted or deleted, both are - set to 0. */ - - protected void analyze_hunk(Diff.change hunk) { - int f0, l0 = 0, f1, l1 = 0, show_from = 0, show_to = 0; - int i; - Diff.change next; - boolean nontrivial = (ignore == null); - - show_from = show_to = 0; - - f0 = hunk.line0; - f1 = hunk.line1; - - for (next = hunk; next != null; next = next.link) - { - l0 = next.line0 + next.deleted - 1; - l1 = next.line1 + next.inserted - 1; - show_from += next.deleted; - show_to += next.inserted; - for (i = next.line0; i <= l0 && ! nontrivial; i++) - if (!ignore.execute(file0[i])) - nontrivial = true; - for (i = next.line1; i <= l1 && ! nontrivial; i++) - if (!ignore.execute(file1[i])) - nontrivial = true; - } - - first0 = f0; - last0 = l0; - first1 = f1; - last1 = l1; - - /* If all inserted or deleted lines are ignorable, - tell the caller to ignore this hunk. */ - - if (!nontrivial) - show_from = show_to = 0; - - deletes = show_from; - inserts = show_to; - } - - /** Print the script header which identifies the files compared. */ - protected void print_header(String filea, String fileb) { } - - protected abstract void print_hunk(Diff.change hunk); - - protected void print_1_line(String pre,Object linbuf) { - outfile.println(pre + linbuf.toString()); - } - - /** Print a pair of line numbers with SEPCHAR, translated for file FILE. - If the two numbers are identical, print just one number. - - Args A and B are internal line numbers. - We print the translated (real) line numbers. */ - - protected void print_number_range (char sepchar, int a, int b) { - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (++b > ++a) - outfile.print("" + a + sepchar + b); - else - outfile.print(b); - } - - public static char change_letter(int inserts, int deletes) { - if (inserts == 0) - return 'd'; - else if (deletes == 0) - return 'a'; - else - return 'c'; - } - } - - /** Print a change list in the standard diff format. - */ - public static class NormalPrint extends Base { - - public NormalPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of a normal diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - - protected void print_hunk (Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk(hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.print(change_letter(inserts, deletes)); - print_number_range (',', first1, last1); - outfile.println(); - - /* Print the lines that the first file has. */ - if (deletes != 0) - for (int i = first0; i <= last0; i++) - print_1_line ("< ", file0[i]); - - if (inserts != 0 && deletes != 0) - outfile.println("---"); - - /* Print the lines that the second file has. */ - if (inserts != 0) - for (int i = first1; i <= last1; i++) - print_1_line ("> ", file1[i]); - } - } - - /** Prints an edit script in a format suitable for input to <code>ed</code>. - The edit script must be generated with the reverse option to - be useful as actual <code>ed</code> input. - */ - public static class EdPrint extends Base { - - public EdPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - /** Print a hunk of an ed diff */ - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - if (deletes == 0 && inserts == 0) - return; - - /* Print out the line number header for this hunk */ - print_number_range (',', first0, last0); - outfile.println(change_letter(inserts, deletes)); - - /* Print new/changed lines from second file, if needed */ - if (inserts != 0) - { - boolean inserting = true; - for (int i = first1; i <= last1; i++) - { - /* Resume the insert, if we stopped. */ - if (! inserting) - outfile.println(i - first1 + first0 + "a"); - inserting = true; - - /* If the file's line is just a dot, it would confuse `ed'. - So output it with a double dot, and set the flag LEADING_DOT - so that we will output another ed-command later - to change the double dot into a single dot. */ - - if (".".equals(file1[i])) - { - outfile.println(".."); - outfile.println("."); - /* Now change that double dot to the desired single dot. */ - outfile.println(i - first1 + first0 + 1 + "s/^\\.\\././"); - inserting = false; - } - else - /* Line is not `.', so output it unmodified. */ - print_1_line ("", file1[i]); - } - - /* End insert mode, if we are still in it. */ - if (inserting) - outfile.println("."); - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class ContextPrint extends Base { - - protected int context = 3; - - public ContextPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - protected void print_context_label (String mark, File inf, String label) { - if (label != null) - outfile.println(mark + ' ' + label); - else if (inf.lastModified() > 0) - // FIXME: use DateFormat to get precise format needed. - outfile.println( - mark + ' ' + inf.getPath() + '\t' + new Date(inf.lastModified()) - ); - else - /* Don't pretend that standard input is ancient. */ - outfile.println(mark + ' ' + inf.getPath()); - } - - public void print_header(String filea,String fileb) { - print_context_label ("***", new File(filea), filea); - print_context_label ("---", new File(fileb), fileb); - } - - /** If function_regexp defined, search for start of function. */ - private String find_function(Object[] lines, int start) { - return null; - } - - protected void print_function(Object[] file,int start) { - String function = find_function (file0, first0); - if (function != null) { - outfile.print(" "); - outfile.print( - (function.length() < 40) ? function : function.substring(0,40) - ); - } - } - - protected void print_hunk(Diff.change hunk) { - - /* Determine range of line numbers involved in each file. */ - - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - outfile.print("***************"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function (file0, first0); - - outfile.println(); - outfile.print("*** "); - print_number_range (',', first0, last0); - outfile.println(" ****"); - - if (deletes != 0) { - Diff.change next = hunk; - - for (int i = first0; i <= last0; i++) { - /* Skip past changes that apply (in file 0) - only to lines before line I. */ - - while (next != null && next.line0 + next.deleted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line0 <= i) - /* The change NEXT covers this line. - If lines were inserted here in file 1, this is "changed". - Otherwise it is "deleted". */ - prefix = (next.inserted > 0) ? "!" : "-"; - - print_1_line (prefix, file0[i]); - } - } - - outfile.print("--- "); - print_number_range (',', first1, last1); - outfile.println(" ----"); - - if (inserts != 0) { - Diff.change next = hunk; - - for (int i = first1; i <= last1; i++) { - /* Skip past changes that apply (in file 1) - only to lines before line I. */ - - while (next != null && next.line1 + next.inserted <= i) - next = next.link; - - /* Compute the marking for line I. */ - - String prefix = " "; - if (next != null && next.line1 <= i) - /* The change NEXT covers this line. - If lines were deleted here in file 0, this is "changed". - Otherwise it is "inserted". */ - prefix = (next.deleted > 0) ? "!" : "+"; - - print_1_line (prefix, file1[i]); - } - } - } - } - - /** Prints an edit script in context diff format. This and its - 'unified' variation is used for source code patches. - */ - public static class UnifiedPrint extends ContextPrint { - - public UnifiedPrint(Object[] a,Object[] b, Writer w) { - super(a,b,w); - } - - public void print_header(String filea,String fileb) { - print_context_label ("---", new File(filea), filea); - print_context_label ("+++", new File(fileb), fileb); - } - - private void print_number_range (int a, int b) { - //translate_range (file, a, b, &trans_a, &trans_b); - - /* Note: we can have B < A in the case of a range of no lines. - In this case, we should print the line number before the range, - which is B. */ - if (b < a) - outfile.print(b + ",0"); - else - super.print_number_range(',',a,b); - } - - protected void print_hunk(Diff.change hunk) { - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk); - - if (deletes == 0 && inserts == 0) - return; - - /* Include a context's width before and after. */ - - first0 = Math.max(first0 - context, 0); - first1 = Math.max(first1 - context, 0); - last0 = Math.min(last0 + context, file0.length - 1); - last1 = Math.min(last1 + context, file1.length - 1); - - - - outfile.print("@@ -"); - print_number_range (first0, last0); - outfile.print(" +"); - print_number_range (first1, last1); - outfile.print(" @@"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - print_function(file0,first0); - - outfile.println(); - - Diff.change next = hunk; - int i = first0; - int j = first1; - - while (i <= last0 || j <= last1) { - - /* If the line isn't a difference, output the context from file 0. */ - - if (next == null || i < next.line0) { - outfile.print(' '); - print_1_line ("", file0[i++]); - j++; - } - else { - /* For each difference, first output the deleted part. */ - - int k = next.deleted; - while (k-- > 0) { - outfile.print('-'); - print_1_line ("", file0[i++]); - } - - /* Then output the inserted part. */ - - k = next.inserted; - while (k-- > 0) { - outfile.print('+'); - print_1_line ("", file1[j++]); - } - - /* We're done with this hunk, so on to the next! */ - - next = next.link; - } - } - } - } - - - /** Read a text file into an array of String. This provides basic diff - functionality. A more advanced diff utility will use specialized - objects to represent the text lines, with options to, for example, - convert sequences of whitespace to a single space for comparison - purposes. - */ - static String[] slurp(String file) throws IOException { - BufferedReader rdr = new BufferedReader(new FileReader(file)); - Vector<String> s = new Vector<String>(); - for (;;) { - String line = rdr.readLine(); - if (line == null) break; - s.addElement(line); - } - String[] a = new String[s.size()]; - s.copyInto(a); - return a; - } - - public static void main(String[] argv) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - System.err.println("No differences"); - else { - Base p; - Writer w = new OutputStreamWriter(System.out); - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - - public static void doDiff(String[] argv, Writer w) throws IOException { - String filea = argv[argv.length - 2]; - String fileb = argv[argv.length - 1]; - String[] a = slurp(filea); - String[] b = slurp(fileb); - Diff d = new Diff(a,b); - char style = 'n'; - for (int i = 0; i < argv.length - 2; ++i) { - String f = argv[i]; - if (f.startsWith("-")) { - for (int j = 1; j < f.length(); ++j) { - switch (f.charAt(j)) { - case 'e': // Ed style - style = 'e'; break; - case 'c': // Context diff - style = 'c'; break; - case 'u': - style = 'u'; break; - } - } - } - } - boolean reverse = style == 'e'; - Diff.change script = d.diff_2(reverse); - if (script == null) - w.write("No differences\n"); - else { - Base p; - switch (style) { - case 'e': - p = new EdPrint(a,b,w); break; - case 'c': - p = new ContextPrint(a,b,w); break; - case 'u': - p = new UnifiedPrint(a,b,w); break; - default: - p = new NormalPrint(a,b,w); - } - p.print_header(filea,fileb); - p.print_script(script); - } - } - -} diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala index a32c56e973..23546c6511 100644 --- a/src/partest/scala/tools/partest/nest/FileManager.scala +++ b/src/partest/scala/tools/partest/nest/FileManager.scala @@ -17,34 +17,31 @@ import scala.collection.mutable trait FileUtil { /** - * Compares two files using a Java implementation of the GNU diff - * available at http://www.bmsi.com/java/#diff. + * Compares two files using difflib to produce a unified diff. * * @param f1 the first file to be compared * @param f2 the second file to be compared - * @return the text difference between the compared files + * @return the unified diff of the compared files or the empty string if they're equal */ def compareFiles(f1: File, f2: File): String = { - val diffWriter = new StringWriter - val args = Array(f1.getAbsolutePath(), f2.getAbsolutePath()) - - DiffPrint.doDiff(args, diffWriter) - val res = diffWriter.toString - if (res startsWith "No") "" else res + compareContents(io.Source.fromFile(f1).getLines.toSeq, io.Source.fromFile(f2).getLines.toSeq, f1.getName, f2.getName) } - def compareContents(lines1: Seq[String], lines2: Seq[String]): String = { - val xs1 = lines1.toArray[AnyRef] - val xs2 = lines2.toArray[AnyRef] - - val diff = new Diff(xs1, xs2) - val change = diff.diff_2(false) - val writer = new StringWriter - val p = new DiffPrint.NormalPrint(xs1, xs2, writer) - - p.print_script(change) - val res = writer.toString - if (res startsWith "No ") "" - else res + + /** + * Compares two lists of lines using difflib to produce a unified diff. + * + * @param origLines the first seq of lines to be compared + * @param newLines the second seq of lines to be compared + * @param origName file name to be used in unified diff for `origLines` + * @param newName file name to be used in unified diff for `newLines` + * @return the unified diff of the `origLines` and `newLines` or the empty string if they're equal + */ + def compareContents(origLines: Seq[String], newLines: Seq[String], origName: String = "a", newName: String = "b"): String = { + import collection.JavaConverters._ + + val diff = difflib.DiffUtils.diff(origLines.asJava, newLines.asJava) + if (diff.getDeltas.isEmpty) "" + else difflib.DiffUtils.generateUnifiedDiff(origName, newName, origLines.asJava, diff, 1).asScala.mkString("\n") } } object FileUtil extends FileUtil { } diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala index 02651c527b..7c005b4f61 100644 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ b/src/partest/scala/tools/partest/nest/PathSettings.scala @@ -71,6 +71,9 @@ object PathSettings { findJar(buildPackLibDir.files ++ srcLibDir.files, "scalacheck") getOrElse { sys.error("No scalacheck jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir)) } + + lazy val diffUtils: File = + findJar(buildPackLibDir.files, "diffutils") getOrElse sys.error(s"No diffutils.jar found in '$buildPackLibDir'.") } class PathSettings() { diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala index 05cae7b238..9780e82cd9 100644 --- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala +++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala @@ -51,10 +51,13 @@ class ReflectiveRunner { new ConsoleFileManager // this is a workaround for https://issues.scala-lang.org/browse/SI-5433 - // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed + // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed // we hack into the classloader that will become parent classloader for scalac // this way we ensure that reflective macro lookup will pick correct Code.lift - val sepUrls = PathSettings.srcCodeLib.toURI.toURL :: fileManager.latestUrls + // it's also used to inject diffutils into the classpath when running partest from the test/partest script + val srcCodeLibAndDiff = List(PathSettings.srcCodeLib, PathSettings.diffUtils) + val sepUrls = srcCodeLibAndDiff.map(_.toURI.toURL) ::: fileManager.latestUrls + // this seems to be the core classloader that determines which classes can be found when running partest from the test/partest script val sepLoader = new URLClassLoader(sepUrls.toArray, null) if (isPartestDebug) diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index 8f28277a6c..a63a81c47b 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -78,6 +78,7 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val compileMgr = new CompileManager(fileManager) fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck + fileManager.CLASSPATH += File.pathSeparator + PathSettings.diffUtils // needed to put diffutils on test/partest's classpath private def compareFiles(f1: File, f2: File): String = try fileManager.compareFiles(f1, f2) diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala index d9e05e77c1..162fe1296b 100644 --- a/src/reflect/scala/reflect/api/Printers.scala +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -163,6 +163,8 @@ trait Printers { self: Universe => import scala.language.implicitConversions implicit def booleanToBooleanFlag(value: Boolean): BooleanFlag = BooleanFlag(Some(value)) implicit def optionToBooleanFlag(value: Option[Boolean]): BooleanFlag = BooleanFlag(value) + import scala.reflect.internal.settings.MutableSettings + implicit def settingToBooleanFlag(setting: MutableSettings#BooleanSetting): BooleanFlag = BooleanFlag(Some(setting.value)) } /** @group Printers */ diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala index 78f7438429..faf61e5205 100644 --- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala +++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala @@ -72,6 +72,9 @@ object ClassfileConstants { final val CONSTANT_METHODREF = 10 final val CONSTANT_INTFMETHODREF = 11 final val CONSTANT_NAMEANDTYPE = 12 + final val CONSTANT_METHODHANDLE = 15 + final val CONSTANT_METHODTYPE = 16 + final val CONSTANT_INVOKEDYNAMIC = 18 // tags describing the type of a literal in attribute values final val BYTE_TAG = 'B' @@ -306,7 +309,7 @@ object ClassfileConstants { final val invokespecial = 0xb7 final val invokestatic = 0xb8 final val invokeinterface = 0xb9 - final val xxxunusedxxxx = 0xba + final val invokedynamic = 0xba final val new_ = 0xbb final val newarray = 0xbc diff --git a/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala b/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala new file mode 100644 index 0000000000..3d1d1bf451 --- /dev/null +++ b/src/reflect/scala/reflect/internal/JMethodOrConstructor.scala @@ -0,0 +1,45 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ +package scala.reflect +package internal + +import java.lang.{ Class => jClass } +import java.lang.annotation.{ Annotation => jAnnotation } +import java.lang.reflect.{ + Member => jMember, Constructor => jConstructor, Method => jMethod, + AnnotatedElement => jAnnotatedElement, Type => jType, + TypeVariable => jTypeVariable +} + +/** This class tries to abstract over some of the duplication + * in java.lang.reflect.{ Method, Constructor }. + */ +class JMethodOrConstructor(val member: jMember with jAnnotatedElement) { + def isVarArgs: Boolean = member match { + case m: jMethod => m.isVarArgs + case m: jConstructor[_] => m.isVarArgs + } + def typeParams: Array[_ <: jTypeVariable[_]] = member match { + case m: jMethod => m.getTypeParameters + case m: jConstructor[_] => m.getTypeParameters + } + def paramTypes: Array[jType] = member match { + case m: jMethod => m.getGenericParameterTypes + case m: jConstructor[_] => m.getGenericParameterTypes + } + def paramAnnotations: Array[Array[jAnnotation]] = member match { + case m: jMethod => m.getParameterAnnotations + case m: jConstructor[_] => m.getParameterAnnotations + } + def resultType: jType = member match { + case m: jMethod => m.getGenericReturnType + case m: jConstructor[_] => classOf[Unit] + } +} + +object JMethodOrConstructor { + implicit def liftMethodToJmoc(m: jMethod): JMethodOrConstructor = new JMethodOrConstructor(m) + implicit def liftConstructorToJmoc(m: jConstructor[_]): JMethodOrConstructor = new JMethodOrConstructor(m) +} diff --git a/src/reflect/scala/reflect/internal/JavaAccFlags.scala b/src/reflect/scala/reflect/internal/JavaAccFlags.scala new file mode 100644 index 0000000000..4be1f828d3 --- /dev/null +++ b/src/reflect/scala/reflect/internal/JavaAccFlags.scala @@ -0,0 +1,83 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Paul Phillips + */ +package scala.reflect +package internal + +import java.lang.{ Class => jClass } +import java.lang.reflect.{ Member => jMember, Constructor => jConstructor, Field => jField, Method => jMethod } +import JavaAccFlags._ +import ClassfileConstants._ + +/** A value class which encodes the access_flags (JVMS 4.1) + * for a field, method, or class. The low 16 bits are the same + * as those returned by java.lang.reflect.Member#getModifiers + * and found in the bytecode. + * + * The high bits encode whether the access flags are directly + * associated with a class, constructor, field, or method. + */ +final class JavaAccFlags private (val coded: Int) extends AnyVal { + private def has(mask: Int) = (flags & mask) != 0 + private def flagCarrierId = coded >>> 16 + private def flags = coded & 0xFFFF + + def isAbstract = has(JAVA_ACC_ABSTRACT) + def isAnnotation = has(JAVA_ACC_ANNOTATION) + def isBridge = has(JAVA_ACC_BRIDGE) + def isEnum = has(JAVA_ACC_ENUM) + def isFinal = has(JAVA_ACC_FINAL) + def isInterface = has(JAVA_ACC_INTERFACE) + def isNative = has(JAVA_ACC_NATIVE) + def isPrivate = has(JAVA_ACC_PRIVATE) + def isProtected = has(JAVA_ACC_PROTECTED) + def isPublic = has(JAVA_ACC_PUBLIC) + def isStatic = has(JAVA_ACC_STATIC) + def isStrictFp = has(JAVA_ACC_STRICT) + def isSuper = has(JAVA_ACC_SUPER) + def isSynchronized = has(JAVA_ACC_SYNCHRONIZED) + def isSynthetic = has(JAVA_ACC_SYNTHETIC) + def isTransient = has(JAVA_ACC_TRANSIENT) + def isVarargs = has(JAVA_ACC_VARARGS) + def isVolatile = has(JAVA_ACC_VOLATILE) + + /** Do these flags describe a member which has either protected or package access? + * Such access in java is encoded in scala as protected[foo] or private[foo], where + * `foo` is the defining package. + */ + def hasPackageAccessBoundary = !has(JAVA_ACC_PRIVATE | JAVA_ACC_PUBLIC) // equivalently, allows protected or package level access + def isPackageProtected = !has(JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC) + + def toJavaFlags: Int = flags + def toScalaFlags: Long = flagCarrierId match { + case Method | Constructor => FlagTranslation methodFlags flags + case Class => FlagTranslation classFlags flags + case _ => FlagTranslation fieldFlags flags + } +} + +object JavaAccFlags { + private val Unknown = 0 + private val Class = 1 + private val Field = 2 + private val Method = 3 + private val Constructor = 4 + + private def create(flagCarrier: Int, access_flags: Int): JavaAccFlags = + new JavaAccFlags((flagCarrier << 16) | (access_flags & 0xFFFF)) + + def classFlags(flags: Int): JavaAccFlags = create(Class, flags) + def methodFlags(flags: Int): JavaAccFlags = create(Method, flags) + def fieldFlags(flags: Int): JavaAccFlags = create(Field, flags) + def constructorFlags(flags: Int): JavaAccFlags = create(Constructor, flags) + + def apply(access_flags: Int): JavaAccFlags = create(Unknown, access_flags) + def apply(clazz: jClass[_]): JavaAccFlags = classFlags(clazz.getModifiers) + def apply(member: jMember): JavaAccFlags = member match { + case x: jConstructor[_] => constructorFlags(x.getModifiers) + case x: jMethod => methodFlags(x.getModifiers) + case x: jField => fieldFlags(x.getModifiers) + case _ => apply(member.getModifiers) + } +} diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala index cc8dd16d69..3c49aef05a 100644 --- a/src/reflect/scala/reflect/internal/Kinds.scala +++ b/src/reflect/scala/reflect/internal/Kinds.scala @@ -145,7 +145,7 @@ trait Kinds { kindErrors = f(kindErrors) } - if (settings.debug.value) { + if (settings.debug) { log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) @@ -201,7 +201,7 @@ trait Kinds { else NoKindErrors } - if (settings.debug.value && (tparams.nonEmpty || targs.nonEmpty)) log( + if (settings.debug && (tparams.nonEmpty || targs.nonEmpty)) log( "checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + owner + ", " + explainErrors + ")" ) diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index 63178d0b39..81d7619f22 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -46,7 +46,7 @@ trait Mirrors extends api.Mirrors { val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym if (result != NoSymbol) result else { - if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug + if (settings.debug) { log(sym.info); log(sym.info.members) }//debug thisMirror.missingHook(owner, name) orElse { MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror) } diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index cc32a0363f..3cf4f4a1df 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -107,7 +107,7 @@ trait Positions extends api.Positions { self: SymbolTable => def validate(tree: Tree, encltree: Tree): Unit = { if (!tree.isEmpty && tree.canHaveAttrs) { - if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value)) + if (settings.Yposdebug && (settings.verbose || settings.Yrangepos)) println("[%10s] %s".format("validate", treeStatus(tree, encltree))) if (!tree.pos.isDefined) diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index e1ef6d6365..5b80889225 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -169,7 +169,7 @@ trait Printers extends api.Printers { self: SymbolTable => ) def printFlags(flags: Long, privateWithin: String) { - val mask: Long = if (settings.debug.value) -1L else PrintableFlags + val mask: Long = if (settings.debug) -1L else PrintableFlags val s = flagsToString(flags & mask, privateWithin) if (s != "") print(s + " ") } @@ -376,7 +376,7 @@ trait Printers extends api.Printers { self: SymbolTable => if (!qual.isEmpty) print(symName(tree, qual) + ".") print("this") - case Select(qual @ New(tpe), name) if (!settings.debug.value) => + case Select(qual @ New(tpe), name) if !settings.debug => print(qual) case Select(qualifier, name) => diff --git a/src/reflect/scala/reflect/internal/PrivateWithin.scala b/src/reflect/scala/reflect/internal/PrivateWithin.scala index 9b99b94b41..5646ac82ae 100644 --- a/src/reflect/scala/reflect/internal/PrivateWithin.scala +++ b/src/reflect/scala/reflect/internal/PrivateWithin.scala @@ -1,23 +1,26 @@ package scala.reflect package internal -import ClassfileConstants._ +import java.lang.{ Class => jClass } +import java.lang.reflect.{ Member => jMember } trait PrivateWithin { self: SymbolTable => - def importPrivateWithinFromJavaFlags(sym: Symbol, jflags: Int): Symbol = { - if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0) - // See ticket #1687 for an example of when topLevelClass is NoSymbol: it - // apparently occurs when processing v45.3 bytecode. - if (sym.enclosingTopLevelClass != NoSymbol) - sym.privateWithin = sym.enclosingTopLevelClass.owner - - // protected in java means package protected. #3946 - if ((jflags & JAVA_ACC_PROTECTED) != 0) - if (sym.enclosingTopLevelClass != NoSymbol) - sym.privateWithin = sym.enclosingTopLevelClass.owner - - sym + def propagatePackageBoundary(c: jClass[_], syms: Symbol*): Unit = + propagatePackageBoundary(JavaAccFlags(c), syms: _*) + def propagatePackageBoundary(m: jMember, syms: Symbol*): Unit = + propagatePackageBoundary(JavaAccFlags(m), syms: _*) + def propagatePackageBoundary(jflags: JavaAccFlags, syms: Symbol*) { + if (jflags.hasPackageAccessBoundary) + syms foreach setPackageAccessBoundary } -}
\ No newline at end of file + + // protected in java means package protected. #3946 + // See ticket #1687 for an example of when the enclosing top level class is NoSymbol; + // it apparently occurs when processing v45.3 bytecode. + def setPackageAccessBoundary(sym: Symbol): Symbol = ( + if (sym.enclosingTopLevelClass eq NoSymbol) sym + else sym setPrivateWithin sym.enclosingTopLevelClass.owner + ) +} diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 03ec59f0fe..336c2748c6 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -60,8 +60,8 @@ abstract class SymbolTable extends macros.Universe def debugwarn(msg: => String): Unit = devWarning(msg) /** Override with final implementation for inlining. */ - def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) - def devWarning(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) + def debuglog(msg: => String): Unit = if (settings.debug) log(msg) + def devWarning(msg: => String): Unit = if (settings.debug) Console.err.println(msg) def throwableAsString(t: Throwable): String = "" + t /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */ diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 037d44c540..8ef2805529 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -190,7 +190,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def varianceString: String = variance.symbolicString override def flagMask = - if (settings.debug.value && !isAbstractType) AllFlags + if (settings.debug && !isAbstractType) AllFlags else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE else ExplicitFlags @@ -202,7 +202,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def shortSymbolClass = shortClassOfInstance(this) def symbolCreationString: String = ( "%s%25s | %-40s | %s".format( - if (settings.uniqid.value) "%06d | ".format(id) else "", + if (settings.uniqid) "%06d | ".format(id) else "", shortSymbolClass, name.decode + " in " + owner, rawFlagString @@ -828,7 +828,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Is this symbol effectively final? I.e, it cannot be overridden */ final def isEffectivelyFinal: Boolean = ( (this hasFlag FINAL | PACKAGE) - || isModuleOrModuleClass && (isTopLevel || !settings.overrideObjects.value) + || isModuleOrModuleClass && (isTopLevel || !settings.overrideObjects) || isTerm && ( isPrivate || isLocal @@ -2621,20 +2621,32 @@ trait Symbols extends api.Symbols { self: SymbolTable => } /** change name by appending $$<fully-qualified-name-of-class `base`> - * Do the same for any accessed symbols or setters/getters + * Do the same for any accessed symbols or setters/getters. + * If the accessor to be renamed is overriding a base symbol, enter + * a cloned symbol with the original name but without ACCESSOR flag. */ override def expandName(base: Symbol) { - if (!hasFlag(EXPANDEDNAME)) { - setFlag(EXPANDEDNAME) - if (hasAccessorFlag && !isDeferred) { - accessed.expandName(base) - } - else if (hasGetter) { - getter(owner).expandName(base) - setter(owner).expandName(base) - } - name = nme.expandedName(name.toTermName, base) + def expand(sym: Symbol) { + if ((sym eq NoSymbol) || (sym hasFlag EXPANDEDNAME)) () // skip + else sym setFlag EXPANDEDNAME setName nme.expandedName(sym.name.toTermName, base) + } + def cloneAndExpand(accessor: Symbol) { + val clone = accessor.cloneSymbol(accessor.owner, (accessor.flags | ARTIFACT) & ~ACCESSOR) + expand(accessor) + log(s"Expanded overriding accessor to $accessor, but cloned $clone to preserve override") + accessor.owner.info.decls enter clone + } + def expandAccessor(accessor: Symbol) { + if (accessor.isOverridingSymbol) cloneAndExpand(accessor) else expand(accessor) + } + if (hasAccessorFlag && !isDeferred) { + expand(accessed) + } + else if (hasGetter) { + expandAccessor(getter(owner)) + expandAccessor(setter(owner)) } + expand(this) } } implicit val TermSymbolTag = ClassTag[TermSymbol](classOf[TermSymbol]) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index d6eeb68452..e3b34b83e9 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1306,7 +1306,7 @@ trait Types override def isVolatile = false override def isHigherKinded = sym.isRefinementClass && underlying.isHigherKinded override def prefixString = - if (settings.debug.value) sym.nameString + ".this." + if (settings.debug) sym.nameString + ".this." else if (sym.isAnonOrRefinementClass) "this." else if (sym.isOmittablePrefix) "" else if (sym.isModuleClass) sym.fullNameString + "." @@ -1522,7 +1522,7 @@ trait Types typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement) override def safeToString: String = parentsString(parents) + ( - (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) + (if (settings.debug || parents.isEmpty || (decls.elems ne null)) fullyInitializeScope(decls).mkString("{", "; ", "}") else "") ) } @@ -1622,7 +1622,7 @@ trait Types object baseClassesCycleMonitor { private var open: List[Symbol] = Nil @inline private def cycleLog(msg: => String) { - if (settings.debug.value) + if (settings.debug) Console.err.println(msg) } def size = open.size @@ -1868,7 +1868,7 @@ trait Types tp match { case tr @ TypeRef(_, sym, args) if args.nonEmpty => val tparams = tr.initializedTypeParams - if (settings.debug.value && !sameLength(tparams, args)) + if (settings.debug && !sameLength(tparams, args)) devWarning(s"Mismatched zip in computeRefs(): ${sym.info.typeParams}, $args") foreach2(tparams, args) { (tparam1, arg) => @@ -1934,7 +1934,7 @@ trait Types override def kind = "ClassInfoType" override def safeToString = - if (settings.debug.value || decls.size > 1) + if (settings.debug || decls.size > 1) formattedToString else super.safeToString @@ -1943,7 +1943,7 @@ trait Types */ def formattedToString: String = parents.mkString("\n with ") + ( - if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) + if (settings.debug || parents.isEmpty || (decls.elems ne null)) fullyInitializeScope(decls).mkString(" {\n ", "\n ", "\n}") else "" ) @@ -2352,7 +2352,7 @@ trait Types // ensure that symbol is not a local copy with a name coincidence private def needsPreString = ( - settings.debug.value + settings.debug || !shorthands(sym.fullName) || (sym.ownersIterator exists (s => !s.isClass)) ) @@ -2403,12 +2403,12 @@ trait Types "" } override def safeToString = { - val custom = if (settings.debug.value) "" else customToString + val custom = if (settings.debug) "" else customToString if (custom != "") custom else finishPrefix(preString + sym.nameString + argsString) } override def prefixString = "" + ( - if (settings.debug.value) + if (settings.debug) super.prefixString else if (sym.isOmittablePrefix) "" @@ -2722,10 +2722,10 @@ trait Types override def safeToString: String = { def clauses = { val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }") - if (settings.explaintypes.value) "(" + str + ")" else str + if (settings.explaintypes) "(" + str + ")" else str } underlying match { - case TypeRef(pre, sym, args) if !settings.debug.value && isRepresentableWithWildcards => + case TypeRef(pre, sym, args) if !settings.debug && isRepresentableWithWildcards => "" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]") case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => "(" + underlying + ")" + clauses @@ -3228,7 +3228,7 @@ trait Types if (sym.owner.isTerm && (sym.owner != encl)) Some(sym.owner) else None ).flatten map (s => s.decodedName + tparamsOfSym(s)) mkString "#" } - private def levelString = if (settings.explaintypes.value) level else "" + private def levelString = if (settings.explaintypes) level else "" override def safeToString = ( if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>" else if (constr.inst ne NoType) "=?" + constr.inst @@ -3760,10 +3760,11 @@ trait Types if (tp.isTrivial) tp else if (tp.prefix.typeSymbol isNonBottomSubClass owner) { val widened = tp match { - case _: ConstantType => tp // Java enum constants: don't widen to the enum type! - case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. + case _: ConstantType => tp // Java enum constants: don't widen to the enum type! + case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect. } - widened asSeenFrom (pre, tp.typeSymbol.owner) + val memType = widened asSeenFrom (pre, tp.typeSymbol.owner) + if (tp eq widened) memType else memType.narrow } else loop(tp.prefix) memberType tp.typeSymbol @@ -3791,7 +3792,7 @@ trait Types * the maximum depth `bd` of all types in the base type sequences of these types. */ private def lubDepthAdjust(td: Int, bd: Int): Int = - if (settings.XfullLubs.value) bd + if (settings.XfullLubs) bd else if (bd <= 3) bd else if (bd <= 5) td max (bd - 1) else if (bd <= 7) td max (bd - 2) @@ -4407,7 +4408,7 @@ trait Types /** An exception for cyclic references from which we can recover */ case class RecoverableCyclicReference(sym: Symbol) extends TypeError("illegal cyclic reference involving " + sym) { - if (settings.debug.value) printStackTrace() + if (settings.debug) printStackTrace() } class NoCommonType(tps: List[Type]) extends Throwable( @@ -4433,12 +4434,12 @@ trait Types /** If option `explaintypes` is set, print a subtype trace for `found <:< required`. */ def explainTypes(found: Type, required: Type) { - if (settings.explaintypes.value) withTypesExplained(found <:< required) + if (settings.explaintypes) withTypesExplained(found <:< required) } /** If option `explaintypes` is set, print a subtype trace for `op(found, required)`. */ def explainTypes(op: (Type, Type) => Any, found: Type, required: Type) { - if (settings.explaintypes.value) withTypesExplained(op(found, required)) + if (settings.explaintypes) withTypesExplained(op(found, required)) } /** Execute `op` while printing a trace of the operations on types executed. */ diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index e7a1ea9311..68f9fc8e83 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -49,3 +49,8 @@ abstract class MutableSettings extends AbsSettings { def XfullLubs: BooleanSetting def breakCycles: BooleanSetting } +object MutableSettings { + import scala.language.implicitConversions + /** Support the common use case, `if (settings.debug) println("Hello, martin.")` */ + @inline implicit def reflectSettingToBoolean(s: MutableSettings#BooleanSetting): Boolean = s.value +} diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala index 5bdc5f8a73..921d2e3d66 100644 --- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala +++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala @@ -366,7 +366,7 @@ private[internal] trait GlbLubs { // parameters are not handled correctly. val ok = ts forall { t => isSubType(t, lubRefined, depth) || { - if (settings.debug.value || printLubs) { + if (settings.debug || printLubs) { Console.println( "Malformed lub: " + lubRefined + "\n" + "Argument " + t + " does not conform. Falling back to " + lubBase diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index e9d3ffbf56..d408857cf3 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -52,7 +52,7 @@ trait TypeComparers { private def isSubPre(pre1: Type, pre2: Type, sym: Symbol) = if ((pre1 ne pre2) && (pre1 ne NoPrefix) && (pre2 ne NoPrefix) && pre1 <:< pre2) { - if (settings.debug.value) println(s"new isSubPre $sym: $pre1 <:< $pre2") + if (settings.debug) println(s"new isSubPre $sym: $pre1 <:< $pre2") true } else false diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index a002b01f70..b0feb0a7fb 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -66,7 +66,7 @@ private[internal] trait TypeConstraints { def clear() { lock() try { - if (settings.debug.value) + if (settings.debug) self.log("Clearing " + log.size + " entries from the undoLog.") log = Nil } finally unlock() diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala index 263b0f5a3e..c86383e9e3 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala @@ -14,7 +14,7 @@ private[internal] trait TypeToStrings { protected def typeToString(tpe: Type): String = if (tostringRecursions >= maxTostringRecursions) { devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe)) - if (settings.debug.value) + if (settings.debug) (new Throwable).printStackTrace "..." diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala index 63b7f73386..d6fca9d186 100644 --- a/src/reflect/scala/reflect/internal/util/Collections.scala +++ b/src/reflect/scala/reflect/internal/util/Collections.scala @@ -76,6 +76,19 @@ trait Collections { lb.toList } + final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = { + val buf = new ListBuffer[A] + val seen = mutable.Set[B]() + xs foreach { x => + val y = f(x) + if (!seen(y)) { + buf += x + seen += y + } + } + buf.toList + } + @tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = { xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail) } diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index e58e89a4b1..3211bb7919 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -6,12 +6,14 @@ import scala.collection.mutable.WeakHashMap import java.lang.{Class => jClass, Package => jPackage} import java.lang.reflect.{ - Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField, + Method => jMethod, Constructor => jConstructor, Field => jField, Member => jMember, Type => jType, TypeVariable => jTypeVariable, Array => jArray, + AccessibleObject => jAccessibleObject, GenericDeclaration, GenericArrayType, ParameterizedType, WildcardType, AnnotatedElement } import java.lang.annotation.{Annotation => jAnnotation} import java.io.IOException -import internal.MissingRequirementError +import scala.reflect.internal.{ MissingRequirementError, JavaAccFlags, JMethodOrConstructor } +import JavaAccFlags._ import internal.pickling.ByteCodecs import internal.ClassfileConstants._ import internal.pickling.UnPickler @@ -88,12 +90,12 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni // ----------- Caching ------------------------------------------------------------------ - private val classCache = new TwoWayCache[jClass[_], ClassSymbol] - private val packageCache = new TwoWayCache[Package, ModuleSymbol] - private val methodCache = new TwoWayCache[jMethod, MethodSymbol] + private val classCache = new TwoWayCache[jClass[_], ClassSymbol] + private val packageCache = new TwoWayCache[Package, ModuleSymbol] + private val methodCache = new TwoWayCache[jMethod, MethodSymbol] private val constructorCache = new TwoWayCache[jConstructor[_], MethodSymbol] - private val fieldCache = new TwoWayCache[jField, TermSymbol] - private val tparamCache = new TwoWayCache[jTypeVariable[_ <: GenericDeclaration], TypeSymbol] + private val fieldCache = new TwoWayCache[jField, TermSymbol] + private val tparamCache = new TwoWayCache[jTypeVariable[_ <: GenericDeclaration], TypeSymbol] private[runtime] def toScala[J: HasJavaClass, S](cache: TwoWayCache[J, S], key: J)(body: (JavaMirror, J) => S): S = cache.toScala(key){ @@ -101,38 +103,36 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni body(mirrorDefining(jclazz), key) } - private implicit val classHasJavaClass: HasJavaClass[jClass[_]] = - new HasJavaClass(identity) - private implicit val methHasJavaClass: HasJavaClass[jMethod] - = new HasJavaClass(_.getDeclaringClass) - private implicit val fieldHasJavaClass: HasJavaClass[jField] = - new HasJavaClass(_.getDeclaringClass) - private implicit val constrHasJavaClass: HasJavaClass[jConstructor[_]] = - new HasJavaClass(_.getDeclaringClass) + private implicit val classHasJavaClass: HasJavaClass[jClass[_]] = new HasJavaClass(identity) + private implicit val methHasJavaClass: HasJavaClass[jMethod] = new HasJavaClass(_.getDeclaringClass) + private implicit val fieldHasJavaClass: HasJavaClass[jField] = new HasJavaClass(_.getDeclaringClass) + private implicit val constrHasJavaClass: HasJavaClass[jConstructor[_]] = new HasJavaClass(_.getDeclaringClass) private implicit val tparamHasJavaClass: HasJavaClass[jTypeVariable[_ <: GenericDeclaration]] = new HasJavaClass ( (tparam: jTypeVariable[_ <: GenericDeclaration]) => { tparam.getGenericDeclaration match { - case jclazz: jClass[_] => jclazz - case jmeth: jMethod => jmeth.getDeclaringClass + case jclazz: jClass[_] => jclazz + case jmeth: jMethod => jmeth.getDeclaringClass case jconstr: jConstructor[_] => jconstr.getDeclaringClass } }) // ----------- Implementations of mirror operations and classes ------------------- - private def ErrorInnerClass(sym: Symbol) = throw new ScalaReflectionException(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") - private def ErrorInnerModule(sym: Symbol) = throw new ScalaReflectionException(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") - private def ErrorStaticClass(sym: Symbol) = throw new ScalaReflectionException(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") - private def ErrorStaticModule(sym: Symbol) = throw new ScalaReflectionException(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") - private def ErrorNotMember(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") - private def ErrorNotField(sym: Symbol) = throw new ScalaReflectionException(s"expected a field or an accessor method symbol, you provided $sym") - private def ErrorNonExistentField(sym: Symbol) = throw new ScalaReflectionException( + private def abort(msg: String) = throw new ScalaReflectionException(msg) + + private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror") + private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") + private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") + private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") + private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}") + private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym") + private def ErrorSetImmutableField(sym: Symbol) = abort(s"cannot set an immutable field ${sym.name}") + private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym") + private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") + private def ErrorNonExistentField(sym: Symbol) = abort( sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method |note that private parameters of class constructors don't get mapped onto fields and/or accessors, |unless they are used outside of their declaring constructors.""") - private def ErrorSetImmutableField(sym: Symbol) = throw new ScalaReflectionException(s"cannot set an immutable field ${sym.name}") - private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a constructor of $owner, you provided $sym") - private def ErrorFree(member: Symbol, freeType: Symbol) = throw new ScalaReflectionException(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") /** Helper functions for extracting typed values from a (Class[_], Any) * representing an annotation argument. @@ -210,7 +210,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni case _ => body } } - private def checkMemberOf(sym: Symbol, owner: ClassSymbol) { if (sym.owner == AnyClass || sym.owner == AnyRefClass || sym.owner == ObjectClass) { // do nothing @@ -236,8 +235,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni if (staticClazz.isPrimitive) staticClazz else dynamicClazz } - private class JavaInstanceMirror[T: ClassTag](val instance: T) - extends InstanceMirror { + private class JavaInstanceMirror[T: ClassTag](val instance: T) extends InstanceMirror { def symbol = thisMirror.classSymbol(preciseClass(instance)) def reflectField(field: TermSymbol): FieldMirror = { checkMemberOf(field, symbol) @@ -269,12 +267,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol) extends FieldMirror { - lazy val jfield = { - val jfield = fieldToJava(symbol) - if (!jfield.isAccessible) jfield.setAccessible(true) - jfield - } - def get = jfield.get(receiver) + lazy val jfield = ensureAccessible(fieldToJava(symbol)) + def get = jfield get receiver def set(value: Any) = { if (!symbol.isMutable) ErrorSetImmutableField(symbol) jfield.set(receiver, value) @@ -338,15 +332,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } } } - - private abstract class JavaMethodMirror(val symbol: MethodSymbol) - extends MethodMirror { - lazy val jmeth = { - val jmeth = methodToJava(symbol) - if (!jmeth.isAccessible) jmeth.setAccessible(true) - jmeth - } - + private abstract class JavaMethodMirror(val symbol: MethodSymbol) extends MethodMirror { + lazy val jmeth = ensureAccessible(methodToJava(symbol)) def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) def jinvoke(jmeth: jMethod, receiver: Any, args: Seq[Any]): Any = { @@ -418,13 +405,13 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni if (!perfectMatch && !varargMatch) { val n_arguments = if (isVarArgsList(params)) s"${params.length - 1} or more" else s"${params.length}" val s_arguments = if (params.length == 1 && !isVarArgsList(params)) "argument" else "arguments" - throw new ScalaReflectionException(s"${showMethodSig(symbol)} takes $n_arguments $s_arguments") + abort(s"${showMethodSig(symbol)} takes $n_arguments $s_arguments") } def objReceiver = receiver.asInstanceOf[AnyRef] def objArg0 = args(0).asInstanceOf[AnyRef] def objArgs = args.asInstanceOf[Seq[AnyRef]] - def fail(msg: String) = throw new ScalaReflectionException(msg + ", it cannot be invoked with mirrors") + def fail(msg: String) = abort(msg + ", it cannot be invoked with mirrors") def invokePrimitiveMethod = { val jmeths = classOf[BoxesRunTime].getDeclaredMethods.filter(_.getName == nme.primitiveMethodName(symbol.name).toString) @@ -464,14 +451,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni extends MethodMirror { def bind(newReceiver: Any) = new JavaConstructorMirror(newReceiver.asInstanceOf[AnyRef], symbol) override val receiver = outer - lazy val jconstr = { - val jconstr = constructorToJava(symbol) - if (!jconstr.isAccessible) jconstr.setAccessible(true) - jconstr - } + lazy val jconstr = ensureAccessible(constructorToJava(symbol)) def apply(args: Any*): Any = { if (symbol.owner == ArrayClass) - throw new ScalaReflectionException("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") + abort("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead") val effectiveArgs = if (outer == null) args.asInstanceOf[Seq[AnyRef]] @@ -532,7 +515,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni } def javaClass(path: String): jClass[_] = - Class.forName(path, true, classLoader) + jClass.forName(path, true, classLoader) /** Does `path` correspond to a Java class with that fully qualified name in the current class loader? */ def tryJavaClass(path: String): Option[jClass[_]] = ( @@ -562,7 +545,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni def markAbsent(tpe: Type) = setAllInfos(clazz, module, tpe) def handleError(ex: Exception) = { markAbsent(ErrorType) - if (settings.debug.value) ex.printStackTrace() + if (settings.debug) ex.printStackTrace() val msg = ex.getMessage() MissingRequirementError.signal( (if (msg eq null) "reflection error while loading " + clazz.name @@ -655,13 +638,22 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList // SI-7065: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser val jexTpes = jann match { - case jm: jMethod => jm.getExceptionTypes.toList + case jm: jMethod => jm.getExceptionTypes.toList case jconstr: jConstructor[_] => jconstr.getExceptionTypes.toList - case _ => Nil + case _ => Nil } jexTpes foreach (jexTpe => sym.addThrowsAnnotation(classSymbol(jexTpe))) } + private implicit class jClassOps(val clazz: jClass[_]) { + def javaFlags: JavaAccFlags = JavaAccFlags(clazz) + def scalaFlags: Long = javaFlags.toScalaFlags + } + private implicit class jMemberOps(val member: jMember) { + def javaFlags: JavaAccFlags = JavaAccFlags(member) + def scalaFlags: Long = javaFlags.toScalaFlags + } + /** * A completer that fills in the types of a Scala class and its companion object * by copying corresponding type info from a Java class. This completer is used @@ -681,14 +673,14 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni override def load(sym: Symbol): Unit = { debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym) - val flags = toScalaClassFlags(jclazz.getModifiers) + val flags = jclazz.scalaFlags clazz setFlag (flags | JAVA) if (module != NoSymbol) { module setFlag (flags & PRIVATE | JAVA) module.moduleClass setFlag (flags & PRIVATE | JAVA) } - relatedSymbols foreach (importPrivateWithinFromJavaFlags(_, jclazz.getModifiers)) + propagatePackageBoundary(jclazz, relatedSymbols: _*) copyAnnotations(clazz, jclazz) // to do: annotations to set also for module? @@ -720,28 +712,21 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass) } - def enter(sym: Symbol, mods: Int) = - (if (jModifier.isStatic(mods)) module.moduleClass else clazz).info.decls enter sym + def enter(sym: Symbol, mods: JavaAccFlags) = + ( if (mods.isStatic) module.moduleClass else clazz ).info.decls enter sym for (jinner <- jclazz.getDeclaredClasses) jclassAsScala(jinner) // inner class is entered as a side-effect // no need to call enter explicitly - pendingLoadActions = { () => - - for (jfield <- jclazz.getDeclaredFields) - enter(jfieldAsScala(jfield), jfield.getModifiers) - - for (jmeth <- jclazz.getDeclaredMethods) - enter(jmethodAsScala(jmeth), jmeth.getModifiers) - - for (jconstr <- jclazz.getConstructors) - enter(jconstrAsScala(jconstr), jconstr.getModifiers) - - } :: pendingLoadActions + pendingLoadActions ::= { () => + jclazz.getDeclaredFields foreach (f => enter(jfieldAsScala(f), f.javaFlags)) + jclazz.getDeclaredMethods foreach (m => enter(jmethodAsScala(m), m.javaFlags)) + jclazz.getConstructors foreach (c => enter(jconstrAsScala(c), c.javaFlags)) + } if (parentsLevel == 0) { - while (!pendingLoadActions.isEmpty) { + while (pendingLoadActions.nonEmpty) { val item = pendingLoadActions.head pendingLoadActions = pendingLoadActions.tail item() @@ -760,8 +745,8 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * If Java modifiers `mods` contain STATIC, return the module class * of the companion module of `clazz`, otherwise the class `clazz` itself. */ - private def followStatic(clazz: Symbol, mods: Int) = - if (jModifier.isStatic(mods)) clazz.companionModule.moduleClass else clazz + private def followStatic(clazz: Symbol, mods: JavaAccFlags) = + if (mods.isStatic) clazz.companionModule.moduleClass else clazz /** Methods which need to be treated with care * because they either are getSimpleName or call getSimpleName: @@ -797,7 +782,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni if (jclazz.isMemberClass) { val jEnclosingClass = jclazz.getEnclosingClass val sEnclosingClass = classToScala(jEnclosingClass) - followStatic(sEnclosingClass, jclazz.getModifiers) + followStatic(sEnclosingClass, jclazz.javaFlags) } else if (jclazz.isLocalClass0) { val jEnclosingMethod = jclazz.getEnclosingMethod if (jEnclosingMethod != null) { @@ -825,7 +810,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * The Scala owner of the Scala symbol corresponding to the Java member `jmember` */ private def sOwner(jmember: jMember): Symbol = { - followStatic(classToScala(jmember.getDeclaringClass), jmember.getModifiers) + followStatic(classToScala(jmember.getDeclaringClass), jmember.javaFlags) } /** @@ -866,7 +851,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def methodToScala1(jmeth: jMethod): MethodSymbol = { val jOwner = jmeth.getDeclaringClass val preOwner = classToScala(jOwner) - val owner = followStatic(preOwner, jmeth.getModifiers) + val owner = followStatic(preOwner, jmeth.javaFlags) (lookup(owner, jmeth.getName) suchThat (erasesTo(_, jmeth)) orElse jmethodAsScala(jmeth)) .asMethod } @@ -880,7 +865,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni toScala(constructorCache, jconstr)(_ constructorToScala1 _) private def constructorToScala1(jconstr: jConstructor[_]): MethodSymbol = { - val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.getModifiers) + val owner = followStatic(classToScala(jconstr.getDeclaringClass), jconstr.javaFlags) (lookup(owner, jconstr.getName) suchThat (erasesTo(_, jconstr)) orElse jconstrAsScala(jconstr)) .asMethod } @@ -1018,6 +1003,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni case jmeth: jMethod => methodToScala(jmeth) case jconstr: jConstructor[_] => constructorToScala(jconstr) } + def reflectMemberToScala(m: jMember): Symbol = m match { + case x: GenericDeclaration => genericDeclarationToScala(x) + case x: jField => jfieldAsScala(x) + } /** * Given some Java type arguments, a corresponding list of Scala types, plus potentially @@ -1092,10 +1081,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def jfieldAsScala1(jfield: jField): TermSymbol = { val field = sOwner(jfield) - .newValue(newTermName(jfield.getName), NoPosition, toScalaFieldFlags(jfield.getModifiers)) + .newValue(newTermName(jfield.getName), NoPosition, jfield.scalaFlags) .setInfo(typeToScala(jfield.getGenericType)) - fieldCache enter (jfield, field) - importPrivateWithinFromJavaFlags(field, jfield.getModifiers) + + fieldCache.enter(jfield, field) + propagatePackageBoundary(jfield, field) copyAnnotations(field, jfield) field } @@ -1115,16 +1105,19 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def jmethodAsScala1(jmeth: jMethod): MethodSymbol = { val clazz = sOwner(jmeth) - val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, toScalaMethodFlags(jmeth.getModifiers)) + val meth = clazz.newMethod(newTermName(jmeth.getName), NoPosition, jmeth.scalaFlags) methodCache enter (jmeth, meth) val tparams = jmeth.getTypeParameters.toList map createTypeParameter val paramtpes = jmeth.getGenericParameterTypes.toList map typeToScala val resulttpe = typeToScala(jmeth.getGenericReturnType) setMethType(meth, tparams, paramtpes, resulttpe) - importPrivateWithinFromJavaFlags(meth, jmeth.getModifiers) + propagatePackageBoundary(jmeth.javaFlags, meth) copyAnnotations(meth, jmeth) - if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) meth.setInfo(arrayToRepeated(meth.info)) - meth + + if (jmeth.javaFlags.isVarargs) + meth modifyInfo arrayToRepeated + else + meth } /** @@ -1139,13 +1132,13 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni private def jconstrAsScala1(jconstr: jConstructor[_]): MethodSymbol = { // [Martin] Note: I know there's a lot of duplication wrt jmethodAsScala, but don't think it's worth it to factor this out. val clazz = sOwner(jconstr) - val constr = clazz.newConstructor(NoPosition, toScalaMethodFlags(jconstr.getModifiers)) + val constr = clazz.newConstructor(NoPosition, jconstr.scalaFlags) constructorCache enter (jconstr, constr) val tparams = jconstr.getTypeParameters.toList map createTypeParameter val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala setMethType(constr, tparams, paramtpes, clazz.tpe_*) constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) - importPrivateWithinFromJavaFlags(constr, jconstr.getModifiers) + propagatePackageBoundary(jconstr.javaFlags, constr) copyAnnotations(constr, jconstr) constr } @@ -1170,13 +1163,15 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni else if (clazz.isTopLevel) javaClass(clazz.javaClassName) else if (clazz.owner.isClass) { - val childOfClass = !clazz.owner.isModuleClass - val childOfTopLevel = clazz.owner.isTopLevel + val childOfClass = !clazz.owner.isModuleClass + val childOfTopLevel = clazz.owner.isTopLevel val childOfTopLevelObject = clazz.owner.isModuleClass && childOfTopLevel // suggested in https://issues.scala-lang.org/browse/SI-4023?focusedCommentId=54759#comment-54759 var ownerClazz = classToJava(clazz.owner.asClass) - if (childOfTopLevelObject) ownerClazz = Class.forName(ownerClazz.getName stripSuffix "$", true, ownerClazz.getClassLoader) + if (childOfTopLevelObject) + ownerClazz = jClass.forName(ownerClazz.getName stripSuffix "$", true, ownerClazz.getClassLoader) + val ownerChildren = ownerClazz.getDeclaredClasses var fullNameOfJavaClass = ownerClazz.getName @@ -1241,11 +1236,11 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni * 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(_, sym: ClassSymbol, _) => classToJava(sym.asClass) + case ExistentialType(_, rtpe) => typeToJavaClass(rtpe) + case TypeRef(_, ArrayClass, List(elemtpe)) => jArrayClass(typeToJavaClass(elemtpe)) + case TypeRef(_, sym: ClassSymbol, _) => classToJava(sym.asClass) case tpe @ TypeRef(_, sym: AliasTypeSymbol, _) => typeToJavaClass(tpe.dealias) - case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found") + case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found") } } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index a130013398..4d90afcdc3 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -14,7 +14,7 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S lazy val settings = new Settings private val isLogging = sys.props contains "scala.debug.reflect" - def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) + def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) type TreeCopier = InternalTreeCopierOps def newStrictTreeCopier: TreeCopier = new StrictTreeCopier diff --git a/src/reflect/scala/reflect/runtime/SymbolTable.scala b/src/reflect/scala/reflect/runtime/SymbolTable.scala index 5c08e9a508..ade7a4a21a 100644 --- a/src/reflect/scala/reflect/runtime/SymbolTable.scala +++ b/src/reflect/scala/reflect/runtime/SymbolTable.scala @@ -11,10 +11,10 @@ import scala.reflect.internal.Flags._ private[scala] trait SymbolTable extends internal.SymbolTable with JavaMirrors with SymbolLoaders with SynchronizedOps { def info(msg: => String) = - if (settings.verbose.value) println("[reflect-compiler] "+msg) + if (settings.verbose) println("[reflect-compiler] "+msg) def debugInfo(msg: => String) = - if (settings.debug.value) info(msg) + if (settings.debug) info(msg) /** Declares that this is a runtime reflection universe. * diff --git a/src/repl/scala/tools/nsc/MainGenericRunner.scala b/src/repl/scala/tools/nsc/MainGenericRunner.scala index 7195424cf9..9e87b6ba55 100644 --- a/src/repl/scala/tools/nsc/MainGenericRunner.scala +++ b/src/repl/scala/tools/nsc/MainGenericRunner.scala @@ -17,7 +17,7 @@ object JarRunner extends CommonRunner { val jarURLs = ClassPath expandManifestPath jarPath val urls = if (jarURLs.isEmpty) File(jarPath).toURL +: settings.classpathURLs else jarURLs - if (settings.Ylogcp.value) { + if (settings.Ylogcp) { Console.err.println("Running jar with these URLs as the classpath:") urls foreach println } @@ -46,7 +46,7 @@ class MainGenericRunner { def sampleCompiler = new Global(settings) // def so its not created unless needed if (!command.ok) return errorFn("\n" + command.shortUsageMsg) - else if (settings.version.value) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) + else if (settings.version) return errorFn("Scala code runner %s -- %s".format(versionString, copyrightString)) else if (command.shouldStopWithInfo) return errorFn(command getInfoMessage sampleCompiler) def isE = !settings.execute.isDefault diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 599a061984..df28e428ce 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -628,10 +628,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) * with SimpleReader. */ def chooseReader(settings: Settings): InteractiveReader = { - if (settings.Xnojline.value || Properties.isEmacsShell) + if (settings.Xnojline || Properties.isEmacsShell) SimpleReader() else try new JLineReader( - if (settings.noCompletion.value) NoCompletion + if (settings.noCompletion) NoCompletion else new JLineCompletion(intp) ) catch { diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index d2b6cdd7f0..4ba81b634a 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -397,7 +397,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } private[nsc] def replwarn(msg: => String) { - if (!settings.nowarnings.value) + if (!settings.nowarnings) printMessage(msg) } diff --git a/src/repl/scala/tools/nsc/interpreter/Power.scala b/src/repl/scala/tools/nsc/interpreter/Power.scala index e517a16b32..da6d271a68 100644 --- a/src/repl/scala/tools/nsc/interpreter/Power.scala +++ b/src/repl/scala/tools/nsc/interpreter/Power.scala @@ -70,7 +70,7 @@ class Power[ReplValsImpl <: ReplVals : ru.TypeTag: ClassTag](val intp: IMain, re pass += 1 val (repeats, unseen) = todo partition seen unseenHistory += unseen.size - if (settings.verbose.value) { + if (settings.verbose) { println("%3d %s accumulated, %s discarded. This pass: %s unseen, %s repeats".format( pass, keep.size, discarded, unseen.size, repeats.size)) } diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala index b4d2adaad4..4607684c0d 100644 --- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala @@ -126,7 +126,7 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor } private[doc] def docdbg(msg: String) { - if (settings.Ydocdebug.value) + if (settings.Ydocdebug) println(msg) } } diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index 5ad50445a8..bf6d6ffed7 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -91,7 +91,7 @@ trait ScaladocAnalyzer extends Analyzer { typedStats(trees, NoSymbol) useCase.defined = context.scope.toList filterNot (useCase.aliases contains _) - if (settings.debug.value) + if (settings.debug) useCase.defined foreach (sym => println("defined use cases: %s:%s".format(sym, sym.tpe))) useCase.defined diff --git a/src/scaladoc/scala/tools/nsc/doc/Uncompilable.scala b/src/scaladoc/scala/tools/nsc/doc/Uncompilable.scala index 9447e36610..ea45ca1a56 100644 --- a/src/scaladoc/scala/tools/nsc/doc/Uncompilable.scala +++ b/src/scaladoc/scala/tools/nsc/doc/Uncompilable.scala @@ -28,7 +28,7 @@ trait Uncompilable { lazy val pairs = files flatMap { f => val comments = docPairs(f.slurp()) - if (settings.verbose.value) + if (settings.verbose) inform("Found %d doc comments in parse-only file %s: %s".format(comments.size, f, comments.map(_._1).mkString(", "))) comments @@ -37,7 +37,7 @@ trait Uncompilable { def symbols = pairs map (_._1) def templates = symbols filter (x => x.isClass || x.isTrait || x == AnyRefClass/* which is now a type alias */) toSet def comments = { - if (settings.debug.value || settings.verbose.value) + if (settings.debug || settings.verbose) inform("Found %d uncompilable files: %s".format(files.size, files mkString ", ")) if (pairs.isEmpty) diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala index 2a07547de2..ac5fec80b3 100755 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala @@ -73,16 +73,20 @@ object EntityLink { def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link)) } final case class HtmlTag(data: String) extends Inline { - def canClose(open: HtmlTag) = { - open.data.stripPrefix("<") == data.stripPrefix("</") + private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r + private val (isEnd, tagName) = data match { + case Pattern(s1, s2) => + (! s1.isEmpty, Some(s2.toLowerCase)) + case _ => + (false, None) } - def close = { - if (data.indexOf("</") == -1) - Some(HtmlTag("</" + data.stripPrefix("<"))) - else - None + def canClose(open: HtmlTag) = { + isEnd && tagName == open.tagName } + + private val TagsNotToClose = Set("br", "img") + def close = tagName collect { case name if !TagsNotToClose(name) => HtmlTag(s"</$name>") } } /** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */ diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala index 229e26d699..9edd5afa13 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlPage.scala @@ -60,7 +60,7 @@ abstract class HtmlPage extends Page { thisPage => w.write(xml.Xhtml.toXhtml(html)) } - if (site.universe.settings.docRawOutput.value) + if (site.universe.settings.docRawOutput) writeFile(site, ".raw") { // we're only interested in the body, as this will go into the diff _.write(body.text) diff --git a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala index 5781e680dd..348ea97c5b 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.doc.html import scala.xml.NodeSeq +import scala.annotation.tailrec /** Highlight the syntax of Scala code appearing in a `{{{` wiki block * (see method `HtmlPage.blockToHtml`). @@ -209,9 +210,9 @@ private[html] object SyntaxHigh { out.toString } - def parse(pre: String, i: Int): Int = { + @tailrec def parse(pre: String, i: Int): Unit = { out append pre - if (i == buf.length) return i + if (i == buf.length) return buf(i) match { case '\n' => parse("\n", i+1) @@ -277,7 +278,6 @@ private[html] object SyntaxHigh { } else parse(buf(i).toChar.toString, i+1) } - i } parse("", 0) diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DiagramStats.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DiagramStats.scala index ec00cace75..ab8e9e2756 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DiagramStats.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DiagramStats.scala @@ -42,7 +42,7 @@ object DiagramStats { private[this] var fixedImages = 0 def printStats(settings: Settings) = { - if (settings.docDiagramsDebug.value) { + if (settings.docDiagramsDebug) { settings.printMsg("\nDiagram generation running time breakdown:\n") filterTrack.printStats(settings.printMsg) modelTrack.printStats(settings.printMsg) @@ -63,4 +63,4 @@ object DiagramStats { def addBrokenImage(): Unit = brokenImages += 1 def addFixedImage(): Unit = fixedImages += 1 -}
\ No newline at end of file +} diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala index 837d9e6f21..7d146b4a5f 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/diagram/DotDiagramGenerator.scala @@ -329,7 +329,7 @@ class DotDiagramGenerator(settings: doc.Settings) extends DiagramGenerator { NodeSeq.Empty } catch { case exc: Exception => - if (settings.docDiagramsDebug.value) { + if (settings.docDiagramsDebug) { settings.printMsg("\n\n**********************************************************************") settings.printMsg("Encountered an error while generating page for " + template.qualifiedName) settings.printMsg(dotInput.toString.split("\n").mkString("\nDot input:\n\t","\n\t","")) diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala index 895cc84f39..cc228082c1 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactory.scala @@ -272,7 +272,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { assert(!(docTemplatesCache isDefinedAt sym), sym) docTemplatesCache += (sym -> this) - if (settings.verbose.value) + if (settings.verbose) inform("Creating doc template for " + sym) override def toRoot: List[DocTemplateImpl] = this :: inTpl.toRoot @@ -350,7 +350,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // the implicit conversions are generated eagerly, but the members generated by implicit conversions are added // lazily, on completeModel val conversions: List[ImplicitConversionImpl] = - if (settings.docImplicits.value) makeImplicitConversions(sym, this) else Nil + if (settings.docImplicits) makeImplicitConversions(sym, this) else Nil // members as given by the compiler lazy val memberSyms = sym.info.members.filter(s => membersShouldDocument(s, this)).toList @@ -924,7 +924,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def ownerTpl(sym: Symbol): Symbol = if (sym.isClass || sym.isModule || sym == NoSymbol) sym else ownerTpl(sym.owner) val tpe = - if (thisFactory.settings.useStupidTypes.value) aType else { + if (thisFactory.settings.useStupidTypes) aType else { def ownerTpl(sym: Symbol): Symbol = if (sym.isClass || sym.isModule || sym == NoSymbol) sym else ownerTpl(sym.owner) val fixedSym = if (inTpl.sym.isModule) inTpl.sym.moduleClass else inTpl.sym @@ -1036,7 +1036,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // whether or not to create a page for an {abstract,alias} type def typeShouldDocument(bSym: Symbol, inTpl: DocTemplateImpl) = - (settings.docExpandAllTypes.value && (bSym.sourceFile != null)) || + (settings.docExpandAllTypes && (bSym.sourceFile != null)) || (bSym.isAliasType || bSym.isAbstractType) && { val rawComment = global.expandedDocComment(bSym, inTpl.sym) rawComment.contains("@template") || rawComment.contains("@documentable") } diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 71b0a00e0a..1f87f935f2 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -241,7 +241,7 @@ trait ModelFactoryImplicitSupport { available match { case Some(true) => Nil - case Some(false) if (!settings.docImplicitsShowAll.value) => + case Some(false) if !settings.docImplicitsShowAll => // if -implicits-show-all is not set, we get rid of impossible conversions (such as Numeric[String]) throw new ImplicitNotFound(implType) case _ => diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala index 99e9059d79..d5048dcfa3 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryTypeSupport.scala @@ -140,7 +140,7 @@ trait ModelFactoryTypeSupport { } val prefix = - if (!settings.docNoPrefixes.value && needsPrefix && (bSym != AnyRefClass /* which we normalize */)) { + if (!settings.docNoPrefixes && needsPrefix && (bSym != AnyRefClass /* which we normalize */)) { if (!owner.isRefinementClass) { val qName = makeQualifiedName(owner, Some(inTpl.sym)) if (qName != "") qName + "." else "" @@ -308,7 +308,7 @@ trait ModelFactoryTypeSupport { // SI-4360: Entity caching depends on both the type AND the template it's in, as the prefixes might change for the // same type based on the template the type is shown in. - if (settings.docNoPrefixes.value) + if (settings.docNoPrefixes) typeCache.getOrElseUpdate(aType, createTypeEntity) else createTypeEntity } diff --git a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala index 6395446d3b..44d8886e4e 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramDirectiveParser.scala @@ -248,7 +248,7 @@ trait DiagramDirectiveParser { hideNodesFilter = hideNodesFilter0, hideEdgesFilter = hideEdgesFilter0) - if (settings.docDiagramsDebug.value && result != NoDiagramAtAll && result != FullDiagram) + if (settings.docDiagramsDebug && result != NoDiagramAtAll && result != FullDiagram) settings.printMsg(template.kind + " " + template.qualifiedName + " filter: " + result) tFilter += System.currentTimeMillis |