From 7664e25eed8ae4547f1cfd774b62a7b6a4baf8b5 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 28 Oct 2014 14:54:35 +1000 Subject: SI-8941 Idempotent presentation compilation of implicit classes When we name an implicit class, `enterImplicitWrapper` is called, which enters the symbol for the factory method into the owning scope. The tree defining this factory method is stowed into `unit.synthetics`, from whence it will be retrieved and incorporated into the enclosing tree during typechecking (`addDerivedTrees`). The entry in `unit.synthetics` is removed at that point. However, in the presentation compiler, we can typecheck a unit more than once in a single run. For example, if, as happens in the enclosed test, a call to ask for a type at a given position interrupts type checking of the entire unit, we can get into a situation whereby the first type checking invocation has consumed the entry from `unit.synthetics`, and the second will crash when it can't find an entry. Similar problems have been solved in the past in `enterExistingSym` in the presentation compiler. This method is called when the namer encounters a tree that already has a symbol attached. See 0b78a0196 / 148736c3df. This commit takes a two pronged approach. First, `enterExistingSym` is extended to handle implicit classes. Any previous factory method in the owning scope is removed, and `enterImplicitWrapper` is called to place a new tree for the factory into `unit.synthetics` and to enter its symbol into the owning scope. Second, the assertions that could be tripped in `addDerivedTrees` and in `ImplicitClassWrapper#derivedSym` have been converted to positioned errors. The first change is sufficient to fix this bug, but the second is also enough to make the enclosed test pass, and has been retained as an extra layer of defence. --- src/interactive/scala/tools/nsc/interactive/Global.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/interactive') diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 174254d523..e308bc3bf0 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -64,7 +64,7 @@ trait InteractiveAnalyzer extends Analyzer { // that case the definitions that were already attributed as // well as any default parameters of such methods need to be // re-entered in the current scope. - override def enterExistingSym(sym: Symbol): Context = { + override def enterExistingSym(sym: Symbol, tree: Tree): Context = { if (sym != null && sym.owner.isTerm) { enterIfNotThere(sym) if (sym.isLazy) @@ -72,8 +72,13 @@ trait InteractiveAnalyzer extends Analyzer { for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment]) defAtt.defaultGetters foreach enterIfNotThere + } else if (sym != null && sym.isClass && sym.isImplicit) { + val owningInfo = sym.owner.info + val existingDerivedSym = owningInfo.decl(sym.name.toTermName).filter(sym => sym.isSynthetic && sym.isMethod) + existingDerivedSym.alternatives foreach (owningInfo.decls.unlink) + enterImplicitWrapper(tree.asInstanceOf[ClassDef]) } - super.enterExistingSym(sym) + super.enterExistingSym(sym, tree) } override def enterIfNotThere(sym: Symbol) { val scope = context.scope -- cgit v1.2.3 From 8f9e9c893893084129ea423ef7ff5d3e79074622 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 28 Oct 2014 19:12:29 +1000 Subject: SI-8941 Deterministic tests for pres. compiler idempotency A retrospective test case which covers typechecking idempotency which was introduced in 0b78a0196 / 148736c3df. It also tests the implicit class handling, which was fixed in the previous commit. It is difficult to test this using existing presentation compiler testing infrastructure, as one can't control at which point during the first typechecking the subesquent work item will be noticed. Instead, I've created a test with a custom subclass of `interactive.Global` that allows precise, deterministic control of when this happens. It overrides `signalDone`, which is called after each tree is typechecked, and watches for a defintion with a well known name. At that point, it triggers a targetted typecheck of the tree marked with a special comment. It is likely that this approach can be generalized to a reusable base class down the track. In particular, I expect that some of the nasty interactive ScalaDoc bugs could use this single-threaded approach to testing the presentation compiler. --- .../scala/tools/nsc/interactive/Global.scala | 6 +- .../presentation/t8941b/IdempotencyTest.scala | 73 ++++++++++++++++++++++ test/files/presentation/t8941b/Test.scala | 53 ++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 test/files/presentation/t8941b/IdempotencyTest.scala create mode 100644 test/files/presentation/t8941b/Test.scala (limited to 'src/interactive') diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index e308bc3bf0..7df809b6ff 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -64,6 +64,8 @@ trait InteractiveAnalyzer extends Analyzer { // that case the definitions that were already attributed as // well as any default parameters of such methods need to be // re-entered in the current scope. + // + // Tested in test/files/presentation/t8941b override def enterExistingSym(sym: Symbol, tree: Tree): Context = { if (sym != null && sym.owner.isTerm) { enterIfNotThere(sym) @@ -737,7 +739,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } } - private def reloadSource(source: SourceFile) { + private[interactive] def reloadSource(source: SourceFile) { val unit = new RichCompilationUnit(source) unitOfFile(source.file) = unit toBeRemoved -= source.file @@ -786,7 +788,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } /** A fully attributed tree located at position `pos` */ - private def typedTreeAt(pos: Position): Tree = getUnit(pos.source) match { + private[interactive] def typedTreeAt(pos: Position): Tree = getUnit(pos.source) match { case None => reloadSources(List(pos.source)) try typedTreeAt(pos) diff --git a/test/files/presentation/t8941b/IdempotencyTest.scala b/test/files/presentation/t8941b/IdempotencyTest.scala new file mode 100644 index 0000000000..af01b36898 --- /dev/null +++ b/test/files/presentation/t8941b/IdempotencyTest.scala @@ -0,0 +1,73 @@ +package scala.tools.nsc +package interactive +package tests.core + +import reporters.{Reporter => CompilerReporter} +import scala.tools.nsc.interactive.InteractiveReporter +import scala.reflect.internal.util.SourceFile + +/** Determistically interrupts typechecking of `code` when a defintion named + * `MagicInterruptionMarker` is typechecked, and then performs a targetted + * typecheck of the tree at the specal comment marker marker + */ +abstract class IdempotencyTest { self => + private val settings = new Settings + settings.usejavacp.value = true + + private object Break extends scala.util.control.ControlThrowable + + private val compilerReporter: CompilerReporter = new InteractiveReporter { + override def compiler = self.compiler + } + + object compiler extends Global(settings, compilerReporter) { + override def checkForMoreWork(pos: Position) { + } + override def signalDone(context: Context, old: Tree, result: Tree) { + // println("signalDone: " + old.toString.take(50).replaceAll("\n", "\\n")) + if (!interrupted && analyzer.lockedCount == 0 && interruptsEnabled && shouldInterrupt(result)) { + interrupted = true + val typed = typedTreeAt(markerPosition) + checkTypedTree(typed) + throw Break + } + super.signalDone(context, old, result) + } + + // we're driving manually using our own thread, disable the check here. + override def assertCorrectThread() {} + } + + import compiler._ + + private var interrupted = false + + // Extension points + protected def code: String + protected def shouldInterrupt(tree: Tree): Boolean = { + tree.symbol != null && tree.symbol.name.toString == "MagicInterruptionMarker" + } + protected def checkTypedTree(tree: Tree): Unit = {} + + + private val source: SourceFile = newSourceFile(code) + private def markerPosition: Position = source.position(code.indexOf("/*?*/")) + + def assertNoProblems() { + val problems = getUnit(source).get.problems + assert(problems.isEmpty, problems.mkString("\n")) + } + + def show() { + reloadSource(source) + try { + typedTree(source, true) + assert(false, "Expected to break out of typechecking.") + } catch { + case Break => // expected + } + assertNoProblems() + } + + def main(args: Array[String]) { show() } +} diff --git a/test/files/presentation/t8941b/Test.scala b/test/files/presentation/t8941b/Test.scala new file mode 100644 index 0000000000..7269a14286 --- /dev/null +++ b/test/files/presentation/t8941b/Test.scala @@ -0,0 +1,53 @@ +import scala.tools.nsc.interactive.tests.core.IdempotencyTest + +// At the time of writing this test, removing any part of `enterExistingSym` +// leads to a failure. +object Test { + def main(args: Array[String]) { + test(""" + object Foo { + def term { + def foo(c: String = "") = c + class MagicInterruptionMarker + foo()/*?*/ + } + } + """) + + test(""" + object Foo { + def term { + def foo = 42 + class MagicInterruptionMarker + foo/*?*/ + } + } + """) + + test(""" + object Foo { + def term { + lazy val foo = 42 + class MagicInterruptionMarker + foo/*?*/ + } + } + """) + + test(""" + object Foo { + implicit class C(val a: String) extends AnyVal + class MagicInterruptionMarker + ""/*?*/ + } + """) + } + + def test(code0: String) { + val t = new IdempotencyTest { + def code = code0 + } + t.show() + } +} + -- cgit v1.2.3 From a8c43dc5caf7439dbcb47f6c25b33fb6b3ed8705 Mon Sep 17 00:00:00 2001 From: mpociecha Date: Sun, 30 Nov 2014 23:52:37 +0100 Subject: Cleanup and refactoring - semicolons, unused or commented out code This commit contains some minor changes made by the way when implementing flat classpath. Sample JUnit test that shows that all pieces of JUnit infrastructure work correctly now uses assert method form JUnit as it should do from the beginning. I removed commented out lines which were obvious to me. In the case of less obvious commented out lines I added TODOs as someone should look at such places some day and clean them up. I removed also some unnecessary semicolons and unused imports. Many string concatenations using + have been changed to string interpolation. There's removed unused, private walkIterator method from ZipArchive. It seems that it was unused since this commit: https://github.com/scala/scala/commit/9d4994b96c77d914687433586eb6d1f9e49c520f However, I had to add an exception for the compatibility checker because it was complaining about this change. I made some trivial corrections/optimisations like use 'findClassFile' method instead of 'findClass' in combination with 'binary' to find the class file. --- bincompat-backward.whitelist.conf | 5 +++++ bincompat-forward.whitelist.conf | 13 +++++++++++++ src/compiler/scala/tools/nsc/Global.scala | 4 ++-- src/compiler/scala/tools/nsc/PhaseAssembly.scala | 2 +- src/compiler/scala/tools/nsc/plugins/Plugins.scala | 2 +- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 5 ++--- .../scala/tools/nsc/transform/AddInterfaces.scala | 1 + src/compiler/scala/tools/reflect/ReflectMain.scala | 2 +- src/compiler/scala/tools/util/PathResolver.scala | 15 ++++++--------- .../scala/tools/nsc/interactive/Global.scala | 4 ++-- .../scala/tools/partest/BytecodeTest.scala | 6 ++---- .../scala/reflect/internal/SymbolTable.scala | 1 - src/reflect/scala/reflect/internal/Symbols.scala | 5 ++--- .../internal/settings/MutableSettings.scala | 3 +++ src/reflect/scala/reflect/io/VirtualFile.scala | 4 ++-- src/reflect/scala/reflect/io/ZipArchive.scala | 21 +++++++-------------- src/repl/scala/tools/nsc/interpreter/IMain.scala | 8 +++++--- src/scalap/scala/tools/scalap/Arguments.scala | 22 +++++++++++----------- src/scalap/scala/tools/scalap/Main.scala | 2 +- test/junit/scala/tools/nsc/SampleTest.scala | 2 +- .../nsc/symtab/SymbolTableForUnitTesting.scala | 2 +- test/script-tests/README | 7 ++++++- 22 files changed, 75 insertions(+), 61 deletions(-) (limited to 'src/interactive') diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf index 56d5b0135c..a1706d103d 100644 --- a/bincompat-backward.whitelist.conf +++ b/bincompat-backward.whitelist.conf @@ -203,6 +203,11 @@ filter { { matchName="scala.reflect.runtime.ThreadLocalStorage#MyThreadLocalStorage.values" problemName=MissingMethodProblem + }, + // the below method was the unused private (sic!) method but the compatibility checker was complaining about it + { + matchName="scala.reflect.io.ZipArchive.scala$reflect$io$ZipArchive$$walkIterator" + problemName=MissingMethodProblem } ] } diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 228b746fa1..13e4f4ba85 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -301,6 +301,19 @@ filter { { matchName="scala.reflect.io.FileZipArchive.root" problemName=MissingMethodProblem + }, + // introduced the harmless method (instead of the repeated code in several places) + { + matchName="scala.reflect.runtime.Settings#MultiStringSetting.valueSetByUser" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.Settings#BooleanSetting.valueSetByUser" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.Settings#IntSetting.valueSetByUser" + problemName=MissingMethodProblem } ] } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 01e8829d6e..9cb4159e60 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -332,7 +332,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) None } - val charset = ( if (settings.encoding.isSetByUser) Some(settings.encoding.value) else None ) flatMap loadCharset getOrElse { + val charset = settings.encoding.valueSetByUser flatMap loadCharset getOrElse { settings.encoding.value = defaultEncoding // A mandatory charset Charset.forName(defaultEncoding) } @@ -347,7 +347,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - ( if (settings.sourceReader.isSetByUser) Some(settings.sourceReader.value) else None ) flatMap loadReader getOrElse { + settings.sourceReader.valueSetByUser flatMap loadReader getOrElse { new SourceReader(charset.newDecoder(), reporter) } } diff --git a/src/compiler/scala/tools/nsc/PhaseAssembly.scala b/src/compiler/scala/tools/nsc/PhaseAssembly.scala index cfb4cd23a1..1eb6c9da2c 100644 --- a/src/compiler/scala/tools/nsc/PhaseAssembly.scala +++ b/src/compiler/scala/tools/nsc/PhaseAssembly.scala @@ -199,7 +199,7 @@ trait PhaseAssembly { // Add all phases in the set to the graph val graph = phasesSetToDepGraph(phasesSet) - val dot = if (settings.genPhaseGraph.isSetByUser) Some(settings.genPhaseGraph.value) else None + val dot = settings.genPhaseGraph.valueSetByUser // Output the phase dependency graph at this stage def dump(stage: Int) = dot foreach (n => graphToDotFile(graph, s"$n-$stage.dot")) diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 6e3d013e52..4b1805479d 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package plugins -import scala.reflect.io.{ File, Path } +import scala.reflect.io.Path import scala.tools.nsc.util.ClassPath import scala.tools.util.PathResolver.Defaults diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 6386da5725..9af3efbece 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -88,8 +88,7 @@ abstract class SymbolLoaders { // require yjp.jar at runtime. See SI-2089. if (settings.termConflict.isDefault) throw new TypeError( - root+" contains object and package with same name: "+ - name+"\none of them needs to be removed from classpath" + s"$root contains object and package with same name: $name\none of them needs to be removed from classpath" ) else if (settings.termConflict.value == "package") { warning( @@ -252,7 +251,7 @@ abstract class SymbolLoaders { * Load contents of a package */ class PackageLoader(classpath: ClassPath[AbstractFile]) extends SymbolLoader with FlagAgnosticCompleter { - protected def description = "package loader "+ classpath.name + protected def description = s"package loader ${classpath.name}" protected def doComplete(root: Symbol) { assert(root.isPackageClass, root) diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index c5f46dc140..f786ffb8f3 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -351,6 +351,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => while (owner != sym && owner != impl) owner = owner.owner; if (owner == impl) This(impl) setPos tree.pos else tree + //TODO what about this commented out code? /* !!! case Super(qual, mix) => val mix1 = mix diff --git a/src/compiler/scala/tools/reflect/ReflectMain.scala b/src/compiler/scala/tools/reflect/ReflectMain.scala index a998a44643..8d8418945a 100644 --- a/src/compiler/scala/tools/reflect/ReflectMain.scala +++ b/src/compiler/scala/tools/reflect/ReflectMain.scala @@ -1,10 +1,10 @@ package scala.tools package reflect +import scala.reflect.internal.util.ScalaClassLoader import scala.tools.nsc.Driver import scala.tools.nsc.Global import scala.tools.nsc.Settings -import scala.tools.nsc.util.ScalaClassLoader import scala.tools.util.PathResolverFactory object ReflectMain extends Driver { diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala index 315476953d..8e5b1e0a5c 100644 --- a/src/compiler/scala/tools/util/PathResolver.scala +++ b/src/compiler/scala/tools/util/PathResolver.scala @@ -51,9 +51,8 @@ object PathResolver { /** Values found solely by inspecting environment or property variables. */ object Environment { - private def searchForBootClasspath = ( + private def searchForBootClasspath = systemProperties find (_._1 endsWith ".boot.class.path") map (_._2) getOrElse "" - ) /** Environment variables which java pays attention to so it * seems we do as well. @@ -107,7 +106,7 @@ object PathResolver { else if (scalaLibAsDir.isDirectory) scalaLibAsDir.path else "" - // XXX It must be time for someone to figure out what all these things + // TODO It must be time for someone to figure out what all these things // are intended to do. This is disabled here because it was causing all // the scala jars to end up on the classpath twice: one on the boot // classpath as set up by the runner (or regular classpath under -nobootcp) @@ -177,7 +176,7 @@ object PathResolver { def fromPathString(path: String, context: JavaContext = DefaultJavaContext): JavaClassPath = { val s = new Settings() s.classpath.value = path - new PathResolver(s, context) result + new PathResolver(s, context).result } /** With no arguments, show the interesting values in Environment and Defaults. @@ -263,11 +262,9 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil * - Otherwise, if CLASSPATH is set, it is that * - If neither of those, then "." is used. */ - def userClassPath = ( - if (!settings.classpath.isDefault) - settings.classpath.value + def userClassPath = + if (!settings.classpath.isDefault) settings.classpath.value else sys.env.getOrElse("CLASSPATH", ".") - ) import classPathFactory._ @@ -291,7 +288,7 @@ abstract class PathResolverBase[BaseClassPathType <: ClassFileLookup[AbstractFil | javaBootClassPath = ${ppcp(javaBootClassPath)} | javaExtDirs = ${ppcp(javaExtDirs)} | javaUserClassPath = ${ppcp(javaUserClassPath)} - | useJavaClassPath = $useJavaClassPath + | useJavaClassPath = $useJavaClassPath | scalaBootClassPath = ${ppcp(scalaBootClassPath)} | scalaExtDirs = ${ppcp(scalaExtDirs)} | userClassPath = ${ppcp(userClassPath)} diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 7df809b6ff..5d00141e6a 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -128,8 +128,8 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") else NullLogger import log.logreplay - debugLog("logger: " + log.getClass + " writing to " + (new java.io.File(logName)).getAbsolutePath) - debugLog("classpath: "+classPath) + debugLog(s"logger: ${log.getClass} writing to ${(new java.io.File(logName)).getAbsolutePath}") + debugLog(s"classpath: $classPath") private var curTime = System.nanoTime private def timeStep = { diff --git a/src/partest-extras/scala/tools/partest/BytecodeTest.scala b/src/partest-extras/scala/tools/partest/BytecodeTest.scala index 3261cada37..37ef4684ef 100644 --- a/src/partest-extras/scala/tools/partest/BytecodeTest.scala +++ b/src/partest-extras/scala/tools/partest/BytecodeTest.scala @@ -116,10 +116,8 @@ abstract class BytecodeTest { sys.error(s"Didn't find method '$name' in class '${classNode.name}'") protected def loadClassNode(name: String, skipDebugInfo: Boolean = true): ClassNode = { - val classBytes: InputStream = (for { - classRep <- classpath.findClass(name) - binary <- classRep.binary - } yield binary.input) getOrElse sys.error(s"failed to load class '$name'; classpath = $classpath") + val classBytes: InputStream = classpath.findClassFile(name).map(_.input) + .getOrElse(sys.error(s"failed to load class '$name'; classpath = $classpath")) val cr = new ClassReader(classBytes) val cn = new ClassNode() diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index ed5c68fe82..01e4cdf367 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -338,7 +338,6 @@ abstract class SymbolTable extends macros.Universe case _ => false } if (pkgModule.isModule && !fromSource) { - // println("open "+pkgModule)//DEBUG openPackageModule(pkgModule, pkgClass) } } diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index c665f2b91a..8e86e6fad9 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -181,7 +181,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => type AccessBoundaryType = Symbol type AnnotationType = AnnotationInfo - // TODO - don't allow names to be renamed in this unstructured a fashion. + // TODO - don't allow names to be renamed in this unstructured fashion. // Rename as little as possible. Enforce invariants on all renames. type TypeOfClonedSymbol >: Null <: Symbol { type NameType = Symbol.this.NameType } @@ -1461,11 +1461,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def info: Type = try { var cnt = 0 while (validTo == NoPeriod) { - //if (settings.debug.value) System.out.println("completing " + this);//DEBUG assert(infos ne null, this.name) assert(infos.prev eq null, this.name) val tp = infos.info - //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug if ((_rawflags & LOCKED) != 0L) { // rolled out once for performance lock { @@ -1474,6 +1472,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } } else { _rawflags |= LOCKED + // TODO another commented out lines - this should be solved in one way or another // activeLocks += 1 // lockedSyms += this } diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala index a494c7f0d0..38893d8db3 100644 --- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala @@ -31,6 +31,9 @@ abstract class MutableSettings extends AbsSettings { v = arg postSetHook() } + + /** Returns Some(value) in the case of a value set by user and None otherwise. */ + def valueSetByUser: Option[T] = if (isSetByUser) Some(value) else None } def Xexperimental: BooleanSetting diff --git a/src/reflect/scala/reflect/io/VirtualFile.scala b/src/reflect/scala/reflect/io/VirtualFile.scala index 45f38db745..1cb4f2fe6f 100644 --- a/src/reflect/scala/reflect/io/VirtualFile.scala +++ b/src/reflect/scala/reflect/io/VirtualFile.scala @@ -75,10 +75,10 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF } /** Does this abstract file denote an existing file? */ - def create() { unsupported() } + def create(): Unit = unsupported() /** Delete the underlying file or directory (recursively). */ - def delete() { unsupported() } + def delete(): Unit = unsupported() /** * Returns the abstract file in this abstract directory with the diff --git a/src/reflect/scala/reflect/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala index dc2ec848b1..0c63acb86c 100644 --- a/src/reflect/scala/reflect/io/ZipArchive.scala +++ b/src/reflect/scala/reflect/io/ZipArchive.scala @@ -74,12 +74,6 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq def container = unsupported() def absolute = unsupported() - private def walkIterator(its: Iterator[AbstractFile]): Iterator[AbstractFile] = { - its flatMap { f => - if (f.isDirectory) walkIterator(f.iterator) - else Iterator(f) - } - } /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) { // have to keep this name for compat with sbt's compiler-interface @@ -87,6 +81,7 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq override def underlyingSource = Some(self) override def toString = self.path + "(" + path + ")" } + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class DirEntry(path: String) extends Entry(path) { val entries = mutable.HashMap[String, Entry]() @@ -245,11 +240,9 @@ final class ManifestResources(val url: URL) extends ZipArchive(null) { val manifest = new Manifest(input) val iter = manifest.getEntries().keySet().iterator().filter(_.endsWith(".class")).map(new ZipEntry(_)) - while (iter.hasNext) { - val zipEntry = iter.next() + for (zipEntry <- iter) { val dir = getDir(dirs, zipEntry) - if (zipEntry.isDirectory) dir - else { + if (!zipEntry.isDirectory) { class FileEntry() extends Entry(zipEntry.getName) { override def lastModified = zipEntry.getTime() override def input = resourceInputStream(path) @@ -285,14 +278,14 @@ final class ManifestResources(val url: URL) extends ZipArchive(null) { private def resourceInputStream(path: String): InputStream = { new FilterInputStream(null) { override def read(): Int = { - if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path); + if(in == null) in = Thread.currentThread().getContextClassLoader().getResourceAsStream(path) if(in == null) throw new RuntimeException(path + " not found") - super.read(); + super.read() } override def close(): Unit = { - super.close(); - in = null; + super.close() + in = null } } } diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 63d95b32b7..f9f7388363 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -1282,9 +1282,11 @@ object IMain { def getProgram(statements: String*): String = null - def getScriptEngine: ScriptEngine = new IMain(this, new Settings() { - usemanifestcp.value = true - }) + def getScriptEngine: ScriptEngine = { + val settings = new Settings() + settings.usemanifestcp.value = true + new IMain(this, settings) + } } // The two name forms this is catching are the two sides of this assignment: diff --git a/src/scalap/scala/tools/scalap/Arguments.scala b/src/scalap/scala/tools/scalap/Arguments.scala index c375a5bac4..de9c30b8af 100644 --- a/src/scalap/scala/tools/scalap/Arguments.scala +++ b/src/scalap/scala/tools/scalap/Arguments.scala @@ -9,7 +9,7 @@ package scala.tools.scalap import scala.collection.mutable -import mutable.{ Buffer, ListBuffer } +import mutable.ListBuffer object Arguments { case class Parser(optionPrefix: Char) { @@ -47,7 +47,7 @@ object Arguments { } def parseBinding(str: String, separator: Char): (String, String) = (str indexOf separator) match { - case -1 => argumentError("missing '" + separator + "' in binding '" + str + "'") ; ("", "") + case -1 => argumentError(s"missing '$separator' in binding '$str'") ; ("", "") case idx => ((str take idx).trim, (str drop (idx + 1)).trim) } @@ -71,7 +71,7 @@ object Arguments { i += 1 } else if (optionalArgs contains args(i)) { if ((i + 1) == args.length) { - argumentError("missing argument for '" + args(i) + "'") + argumentError(s"missing argument for '${args(i)}'") i += 1 } else { res.addArgument(args(i), args(i + 1)) @@ -79,11 +79,11 @@ object Arguments { } } else if (optionalBindings contains args(i)) { if ((i + 1) == args.length) { - argumentError("missing argument for '" + args(i) + "'") + argumentError(s"missing argument for '${args(i)}'") i += 1 } else { res.addBinding(args(i), - parseBinding(args(i + 1), optionalBindings(args(i)))); + parseBinding(args(i + 1), optionalBindings(args(i)))) i += 2 } } else { @@ -92,23 +92,23 @@ object Arguments { while ((i == j) && iter.hasNext) { val prefix = iter.next if (args(i) startsWith prefix) { - res.addPrefixed(prefix, args(i).substring(prefix.length()).trim()); + res.addPrefixed(prefix, args(i).substring(prefix.length()).trim()) i += 1 } } if (i == j) { - val iter = prefixedBindings.keysIterator; + val iter = prefixedBindings.keysIterator while ((i == j) && iter.hasNext) { val prefix = iter.next if (args(i) startsWith prefix) { val arg = args(i).substring(prefix.length()).trim() i = i + 1 res.addBinding(prefix, - parseBinding(arg, prefixedBindings(prefix))); + parseBinding(arg, prefixedBindings(prefix))) } } if (i == j) { - argumentError("unknown option '" + args(i) + "'") + argumentError(s"unknown option '${args(i)}'") i = i + 1 } } @@ -119,7 +119,7 @@ object Arguments { def parse(options: String*)(args: Array[String]): Arguments = { val parser = new Parser('-') - options foreach (parser withOption _) + options foreach parser.withOption parser parse args } } @@ -142,7 +142,7 @@ class Arguments { if (key.length > 0) bindings.getOrElseUpdate(tag, new mutable.HashMap)(key) = value - def addBinding(tag: String, binding: Tuple2[String, String]): Unit = + def addBinding(tag: String, binding: (String, String)): Unit = addBinding(tag, binding._1, binding._2) def addOther(arg: String): Unit = others += arg diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 34684fc3e1..7c554d196c 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -178,7 +178,7 @@ object Main extends Main { verbose = arguments contains opts.verbose printPrivates = arguments contains opts.showPrivateDefs // construct a custom class path - val cpArg = List(opts.classpath, opts.cp) map (arguments getArgument) reduceLeft (_ orElse _) + val cpArg = List(opts.classpath, opts.cp) map arguments.getArgument reduceLeft (_ orElse _) val settings = new Settings() diff --git a/test/junit/scala/tools/nsc/SampleTest.scala b/test/junit/scala/tools/nsc/SampleTest.scala index 810c88ef9d..60bb09e98f 100644 --- a/test/junit/scala/tools/nsc/SampleTest.scala +++ b/test/junit/scala/tools/nsc/SampleTest.scala @@ -11,6 +11,6 @@ import org.junit.runners.JUnit4 class SampleTest { @Test def testMath: Unit = { - assert(2+2 == 4, "you didn't get the math right fellow") + assertTrue("you didn't get the math right fellow", 2 + 2 == 4) } } diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index d61c62784c..f0f20acf07 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -83,7 +83,7 @@ class SymbolTableForUnitTesting extends SymbolTable { rm.asInstanceOf[Mirror] } - def settings: Settings = { + lazy val settings: Settings = { val s = new Settings // initialize classpath using java classpath s.usejavacp.value = true diff --git a/test/script-tests/README b/test/script-tests/README index 3f5c2ce19c..7b3291c407 100755 --- a/test/script-tests/README +++ b/test/script-tests/README @@ -5,4 +5,9 @@ putting self-contained script tests in here to run some way that doesn't depend on all the platform stars aligning all the time. Feel free to join me. --- extempore, Nov 21 2011 \ No newline at end of file +-- extempore, Nov 21 2011 + +But there's a problem that probably nobody would run such tests so they would become outdated quite quickly. +And therefore they wouldn't work (and even compile) after some time - like this one existing currently. + +-- mpociecha, Oct 9 2014 \ No newline at end of file -- cgit v1.2.3