diff options
74 files changed, 1043 insertions, 267 deletions
@@ -22,7 +22,7 @@ END-USER TARGETS <target name="clean" depends="quick.clean" description="Removes binaries of compiler and library. Distributions are untouched."/> - <target name="test" depends="test.done, osgi.test" + <target name="test" depends="test.done, osgi.test, bc.run" description="Runs test suite and bootstrapping test on Scala compiler and library."/> <target name="test-opt" @@ -2644,6 +2644,40 @@ BOOTRAPING TEST AND TEST SUITE <target name="test.done" depends="test.suite, test.continuations.suite, test.scaladoc, test.stability, test.sbt"/> + +<!-- =========================================================================== +Binary compatibility testing +============================================================================ --> + + <target name="bc.init" depends="init"> + <property name="bc-build.dir" value="${build.dir}/bc"/> + <!-- Obtain mima --> + <mkdir dir="${bc-build.dir}"/> + <!-- Pull down MIMA --> + <artifact:dependencies pathId="mima.classpath"> + <dependency groupId="com.typesafe" artifactId="mima-reporter_2.9.2" version="0.1.4"/> + </artifact:dependencies> + <artifact:dependencies pathId="old.bc.classpath"> + <dependency groupId="org.scala-lang" artifactId="scala-library" version="2.10.0-RC2"/> + </artifact:dependencies> + </target> + + <target name="bc.run" depends="bc.init, pack.lib"> + <java + fork="true" + failonerror="true" + classname="com.typesafe.tools.mima.cli.Main"> + <arg value="--prev"/> + <arg value="${org.scala-lang:scala-library:jar}"/> + <arg value="--curr"/> + <arg value="${build-pack.dir}/lib/scala-library.jar"/> + <classpath> + <path refid="mima.classpath"/> + </classpath> + </java> + </target> + + <!-- =========================================================================== DISTRIBUTION ============================================================================ --> diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 918aedce51..31974b5b76 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -120,88 +120,102 @@ trait GenTrees { // unlike in `reifyBoundType` we can skip checking for `tpe` being local or not local w.r.t the reifee // a single check for a symbol of the bound term should be enough // that's because only Idents and Thises can be bound terms, and they cannot host complex types - private def reifyBoundTerm(tree: Tree): Tree = tree match { - case tree @ This(_) if tree.symbol == NoSymbol => - throw new Error("unexpected: bound term that doesn't have a symbol: " + showRaw(tree)) - case tree @ This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass && !tree.symbol.isLocalToReifee => - val sym = tree.symbol - if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) - if (reifyDebug) println("Free: " + sym) - mirrorBuildCall(nme.Ident, reifyFreeTerm(This(sym))) - case tree @ This(_) if !tree.symbol.isLocalToReifee => - if (reifyDebug) println("This for %s, reified as This".format(tree.symbol)) - mirrorBuildCall(nme.This, reify(tree.symbol)) - case tree @ This(_) if tree.symbol.isLocalToReifee => - mirrorCall(nme.This, reify(tree.qual)) - case tree @ Ident(_) if tree.symbol == NoSymbol => - // this sometimes happens, e.g. for binds that don't have a body - // or for untyped code generated during previous phases - // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") - mirrorCall(nme.Ident, reify(tree.name)) - case tree @ Ident(_) if !tree.symbol.isLocalToReifee => - if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { - captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reification here. - mirrorCall(nme.Select, mirrorBuildCall(nme.Ident, reify(tree.symbol)), reify(nme.elem)) - } else { - mirrorBuildCall(nme.Ident, reify(tree.symbol)) - } - case tree @ Ident(_) if tree.symbol.isLocalToReifee => - mirrorCall(nme.Ident, reify(tree.name)) - case _ => - throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) + private def reifyBoundTerm(tree: Tree): Tree = { + val sym = tree.symbol + + tree match { + case This(qual) => + assert(sym != NoSymbol, "unexpected: bound term that doesn't have a symbol: " + showRaw(tree)) + if (sym.isLocalToReifee) + mirrorCall(nme.This, reify(qual)) + else if (sym.isClass && !sym.isModuleClass) { + if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) + if (reifyDebug) println("Free: " + sym) + mirrorBuildCall(nme.Ident, reifyFreeTerm(This(sym))) + } + else { + if (reifyDebug) println("This for %s, reified as This".format(sym)) + mirrorBuildCall(nme.This, reify(sym)) + } + + case Ident(name) => + if (sym == NoSymbol) { + // this sometimes happens, e.g. for binds that don't have a body + // or for untyped code generated during previous phases + // (see a comment in Reifiers about the latter, starting with "why do we resetAllAttrs?") + mirrorCall(nme.Ident, reify(name)) + } + else if (!sym.isLocalToReifee) { + if (sym.isVariable && sym.owner.isTerm) { + captureVariable(sym) // Note order dependency: captureVariable needs to come before reification here. + mirrorCall(nme.Select, mirrorBuildCall(nme.Ident, reify(sym)), reify(nme.elem)) + } + else mirrorBuildCall(nme.Ident, reify(sym)) + } + else mirrorCall(nme.Ident, reify(name)) + + case Select(qual, name) => + if (sym == NoSymbol || sym.name == name) + reifyProduct(tree) + else + reifyProduct(Select(qual, sym.name)) + + case _ => + throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) + } } private def reifyBoundType(tree: Tree): Tree = { + val sym = tree.symbol + val tpe = tree.tpe + def reifyBoundType(tree: Tree): Tree = { - if (tree.tpe == null) - throw new Error("unexpected: bound type that doesn't have a tpe: " + showRaw(tree)) + assert(tpe != null, "unexpected: bound type that doesn't have a tpe: " + showRaw(tree)) // if a symbol or a type of the scrutinee are local to reifee // (e.g. point to a locally declared class or to a path-dependent thingie that depends on a local variable) // then we can reify the scrutinee as a symless AST and that will definitely be hygienic // why? because then typechecking of a scrutinee doesn't depend on the environment external to the quasiquote // otherwise we need to reify the corresponding type - if (tree.symbol.isLocalToReifee || tree.tpe.isLocalToReifee) + if (sym.isLocalToReifee || tpe.isLocalToReifee) reifyProduct(tree) else { - val sym = tree.symbol - val tpe = tree.tpe if (reifyDebug) println("reifying bound type %s (underlying type is %s)".format(sym, tpe)) if (tpe.isSpliceable) { val spliced = spliceType(tpe) + if (spliced == EmptyTree) { if (reifyDebug) println("splicing failed: reify as is") mirrorBuildCall(nme.TypeTree, reify(tpe)) - } else { - spliced match { - case TypeRefToFreeType(freeType) => - if (reifyDebug) println("splicing returned a free type: " + freeType) - Ident(freeType) - case _ => - if (reifyDebug) println("splicing succeeded: " + spliced) - mirrorBuildCall(nme.TypeTree, spliced) - } } - } else { - if (sym.isLocatable) { - if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) - mirrorBuildCall(nme.Ident, reify(sym)) - } else { - if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) - mirrorBuildCall(nme.TypeTree, reify(tpe)) + else spliced match { + case TypeRefToFreeType(freeType) => + if (reifyDebug) println("splicing returned a free type: " + freeType) + Ident(freeType) + case _ => + if (reifyDebug) println("splicing succeeded: " + spliced) + mirrorBuildCall(nme.TypeTree, spliced) } } + else if (sym.isLocatable) { + if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) + mirrorBuildCall(nme.Ident, reify(sym)) + } + else { + if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) + mirrorBuildCall(nme.TypeTree, reify(tpe)) + } } } tree match { - case Select(_, _) => - reifyBoundType(tree) - case SelectFromTypeTree(_, _) => - reifyBoundType(tree) - case Ident(_) => + case Select(qual, name) if name != sym.name => + reifyBoundType(Select(qual, sym.name)) + + case Select(_, _) | SelectFromTypeTree(_, _) | Ident(_) => reifyBoundType(tree) + case _ => throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass)) } diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala index b60d15c1d4..ebbcb95481 100644 --- a/src/compiler/scala/reflect/reify/utils/Extractors.scala +++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala @@ -251,6 +251,8 @@ trait Extractors { object BoundTerm { def unapply(tree: Tree): Option[Tree] = tree match { + case Select(_, name) if name.isTermName => + Some(tree) case Ident(name) if name.isTermName => Some(tree) case This(_) => diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 4e7ba60d5e..355a1fd262 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -23,7 +23,7 @@ trait CompilationUnits { self: Global => /** One unit of compilation that has been submitted to the compiler. * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ - class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { + class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { self => /** the fresh name creator */ var fresh: FreshNameCreator = new FreshNameCreator.Default @@ -57,7 +57,23 @@ trait CompilationUnits { self: Global => /** Synthetic definitions generated by namer, eliminated by typer. */ - val synthetics = mutable.HashMap[Symbol, Tree]() + object synthetics { + private val map = mutable.HashMap[Symbol, Tree]() + def update(sym: Symbol, tree: Tree) { + debuglog(s"adding synthetic ($sym, $tree) to $self") + map.update(sym, tree) + } + def -=(sym: Symbol) { + debuglog(s"removing synthetic $sym from $self") + map -= sym + } + def get(sym: Symbol): Option[Tree] = logResultIf[Option[Tree]](s"found synthetic for $sym in $self", _.isDefined) { + map get sym + } + def keys: Iterable[Symbol] = map.keys + def clear(): Unit = map.clear() + override def toString = map.toString + } /** things to check at end of compilation unit */ val toCheck = new ListBuffer[() => Unit] diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 6eb05c4402..d185ed0c34 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -21,7 +21,7 @@ import asm.Label * * Documentation at http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2012Q2/GenASM.pdf */ -abstract class GenASM extends SubComponent with BytecodeWriters { +abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { import global._ import icodes._ import icodes.opcodes._ @@ -32,20 +32,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { /** Create a new phase */ override def newPhase(p: Phase): Phase = new AsmPhase(p) - private def outputDirectory(sym: Symbol): AbstractFile = - settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) - - private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { - var dir = base - val pathParts = clsName.split("[./]").toList - for (part <- pathParts.init) { - dir = dir.subdirectoryNamed(part) - } - dir.fileNamed(pathParts.last + suffix) - } - private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = - getFile(outputDirectory(sym), clsName, suffix) - /** JVM code generation phase */ class AsmPhase(prev: Phase) extends ICodePhase(prev) { @@ -55,62 +41,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo") - def isJavaEntryPoint(icls: IClass) = { - val sym = icls.symbol - def fail(msg: String, pos: Position = sym.pos) = { - icls.cunit.warning(sym.pos, - sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + - " Reason: " + msg - // TODO: make this next claim true, if possible - // by generating valid main methods as static in module classes - // not sure what the jvm allows here - // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead." - ) - false - } - def failNoForwarder(msg: String) = { - fail(msg + ", which means no static forwarder can be generated.\n") - } - val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil - val hasApproximate = possibles exists { m => - m.info match { - case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass - case _ => false - } - } - // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. - hasApproximate && { - // Before erasure so we can identify generic mains. - beforeErasure { - val companion = sym.linkedClassOfClass - val companionMain = companion.tpe.member(nme.main) - - if (hasJavaMainMethod(companion)) - failNoForwarder("companion contains its own main method") - else if (companion.tpe.member(nme.main) != NoSymbol) - // this is only because forwarders aren't smart enough yet - failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") - else if (companion.isTrait) - failNoForwarder("companion is a trait") - // Now either succeeed, or issue some additional warnings for things which look like - // attempts to be java main methods. - else possibles exists { m => - m.info match { - case PolyType(_, _) => - fail("main methods cannot be generic.") - case MethodType(params, res) => - if (res.typeSymbol :: params exists (_.isAbstractType)) - fail("main methods cannot refer to type parameters or abstract types.", m.pos) - else - isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) - case tp => - fail("don't know what this is: " + tp, m.pos) - } - } - } - } - } - private def initBytecodeWriter(entryPoints: List[IClass]): BytecodeWriter = { settings.outputDirs.getSingleOutput match { case Some(f) if f hasExtension "jar" => @@ -160,7 +90,14 @@ abstract class GenASM extends SubComponent with BytecodeWriters { } // For predictably ordered error messages. - var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) + var sortedClasses = classes.values.toList sortBy (_.symbol.fullName) + + // Warn when classes will overwrite one another on case-insensitive systems. + for ((_, v1 :: v2 :: _) <- sortedClasses groupBy (_.symbol.javaClassName.toString.toLowerCase)) { + v1.cunit.warning(v1.symbol.pos, + s"Class ${v1.symbol.javaClassName} differs only in case from ${v2.symbol.javaClassName}. " + + "Such classes will overwrite one another on case-insensitive filesystems.") + } debuglog("Created new bytecode generator for " + classes.size + " classes.") val bytecodeWriter = initBytecodeWriter(sortedClasses filter isJavaEntryPoint) @@ -1090,12 +1027,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // a plain class lacking companion module, for details see `isCandidateForForwarders`). // ----------------------------------------------------------------------------------------- - val ExcludedForwarderFlags = { - import Flags._ - // Should include DEFERRED but this breaks findMember. - ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags ) - } - /** Add a forwarder for method m. Used only from addForwarders(). */ private def addForwarder(isRemoteClass: Boolean, jclass: asm.ClassVisitor, module: Symbol, m: Symbol) { val moduleName = javaName(module) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 3d29b2590e..fe0020e074 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -26,7 +26,7 @@ import scala.language.postfixOps * @version 1.0 * */ -abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with BytecodeWriters { +abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with BytecodeWriters with GenJVMASM { import global._ import icodes._ import icodes.opcodes._ @@ -37,20 +37,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with /** Create a new phase */ override def newPhase(p: Phase): Phase = new JvmPhase(p) - private def outputDirectory(sym: Symbol): AbstractFile = - settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) - - private def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { - var dir = base - val pathParts = clsName.split("[./]").toList - for (part <- pathParts.init) { - dir = dir.subdirectoryNamed(part) - } - dir.fileNamed(pathParts.last + suffix) - } - private def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = - getFile(outputDirectory(sym), clsName, suffix) - /** JVM code generation phase */ class JvmPhase(prev: Phase) extends ICodePhase(prev) { @@ -58,63 +44,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with override def erasedTypes = true def apply(cls: IClass) = sys.error("no implementation") - def isJavaEntryPoint(clasz: IClass) = { - val sym = clasz.symbol - def fail(msg: String, pos: Position = sym.pos) = { - clasz.cunit.warning(sym.pos, - sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + - " Reason: " + msg - // TODO: make this next claim true, if possible - // by generating valid main methods as static in module classes - // not sure what the jvm allows here - // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead." - ) - false - } - def failNoForwarder(msg: String) = { - fail(msg + ", which means no static forwarder can be generated.\n") - } - val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil - val hasApproximate = possibles exists { m => - m.info match { - case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass - case _ => false - } - } - // At this point it's a module with a main-looking method, so either - // succeed or warn that it isn't. - hasApproximate && { - // Before erasure so we can identify generic mains. - beforeErasure { - val companion = sym.linkedClassOfClass - val companionMain = companion.tpe.member(nme.main) - - if (hasJavaMainMethod(companion)) - failNoForwarder("companion contains its own main method") - else if (companion.tpe.member(nme.main) != NoSymbol) - // this is only because forwarders aren't smart enough yet - failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") - else if (companion.isTrait) - failNoForwarder("companion is a trait") - // Now either succeeed, or issue some additional warnings for things which look like - // attempts to be java main methods. - else possibles exists { m => - m.info match { - case PolyType(_, _) => - fail("main methods cannot be generic.") - case MethodType(params, res) => - if (res.typeSymbol :: params exists (_.isAbstractType)) - fail("main methods cannot refer to type parameters or abstract types.", m.pos) - else - isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) - case tp => - fail("don't know what this is: " + tp, m.pos) - } - } - } - } - } - override def run() { // we reinstantiate the bytecode generator at each run, to allow the GC // to collect everything @@ -210,12 +139,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val BeanDisplayNameAttr = rootMirror.getRequiredClass("scala.beans.BeanDisplayName") val BeanDescriptionAttr = rootMirror.getRequiredClass("scala.beans.BeanDescription") - final val ExcludedForwarderFlags = { - import Flags._ - // Should include DEFERRED but this breaks findMember. - ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags ) - } - // Additional interface parents based on annotations and other cues def newParentForAttr(attr: Symbol): Option[Symbol] = attr match { case SerializableAttr => Some(SerializableClass) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala new file mode 100644 index 0000000000..49c0fa2757 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala @@ -0,0 +1,97 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Jason Zaugg + */ + +package scala.tools.nsc +package backend.jvm +import scala.tools.nsc.io.AbstractFile +import scala.tools.nsc.symtab._ + +/** Code shared between the legagy backend [[scala.tools.nsc.backend.jvm.GenJVM]] + * and the new backend [[scala.tools.nsc.backend.jvm.GenASM]]. There should be + * more here, but for now I'm starting with the refactorings that are either + * straightforward to review or necessary for maintenance. + */ +trait GenJVMASM { + val global: Global + import global._ + import icodes._ + import definitions._ + + protected def outputDirectory(sym: Symbol): AbstractFile = + settings.outputDirs outputDirFor beforeFlatten(sym.sourceFile) + + protected def getFile(base: AbstractFile, clsName: String, suffix: String): AbstractFile = { + var dir = base + val pathParts = clsName.split("[./]").toList + for (part <- pathParts.init) { + dir = dir.subdirectoryNamed(part) + } + dir.fileNamed(pathParts.last + suffix) + } + protected def getFile(sym: Symbol, clsName: String, suffix: String): AbstractFile = + getFile(outputDirectory(sym), clsName, suffix) + + protected val ExcludedForwarderFlags = { + import Flags._ + // Should include DEFERRED but this breaks findMember. + ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | EXPANDEDNAME | BridgeAndPrivateFlags | MACRO ) + } + + protected def isJavaEntryPoint(icls: IClass) = { + val sym = icls.symbol + def fail(msg: String, pos: Position = sym.pos) = { + icls.cunit.warning(sym.pos, + sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + + " Reason: " + msg + // TODO: make this next claim true, if possible + // by generating valid main methods as static in module classes + // not sure what the jvm allows here + // + " You can still run the program by calling it as " + sym.javaSimpleName + " instead." + ) + false + } + def failNoForwarder(msg: String) = { + fail(msg + ", which means no static forwarder can be generated.\n") + } + val possibles = if (sym.hasModuleFlag) (sym.tpe nonPrivateMember nme.main).alternatives else Nil + val hasApproximate = possibles exists { m => + m.info match { + case MethodType(p :: Nil, _) => p.tpe.typeSymbol == ArrayClass + case _ => false + } + } + // At this point it's a module with a main-looking method, so either succeed or warn that it isn't. + hasApproximate && { + // Before erasure so we can identify generic mains. + beforeErasure { + val companion = sym.linkedClassOfClass + val companionMain = companion.tpe.member(nme.main) + + if (hasJavaMainMethod(companion)) + failNoForwarder("companion contains its own main method") + else if (companion.tpe.member(nme.main) != NoSymbol) + // this is only because forwarders aren't smart enough yet + failNoForwarder("companion contains its own main method (implementation restriction: no main is allowed, regardless of signature)") + else if (companion.isTrait) + failNoForwarder("companion is a trait") + // Now either succeeed, or issue some additional warnings for things which look like + // attempts to be java main methods. + else possibles exists { m => + m.info match { + case PolyType(_, _) => + fail("main methods cannot be generic.") + case MethodType(params, res) => + if (res.typeSymbol :: params exists (_.isAbstractType)) + fail("main methods cannot refer to type parameters or abstract types.", m.pos) + else + isJavaMainMethod(m) || fail("main method must have exact signature (Array[String])Unit", m.pos) + case tp => + fail("don't know what this is: " + tp, m.pos) + } + } + } + } + } +} diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index bb14c3dce0..23f932b5b4 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -147,18 +147,18 @@ abstract class ClosureElimination extends SubComponent { case _ => } - case UNBOX(_) => + case UNBOX(boxType) => info.stack match { case Deref(LocalVar(loc1)) :: _ if info.bindings isDefinedAt LocalVar(loc1) => val value = info.getBinding(loc1) value match { - case Boxed(LocalVar(loc2)) => + case Boxed(LocalVar(loc2)) if loc2.kind == boxType => bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil) debuglog("replaced " + i + " with " + info.getBinding(loc2)) case _ => () } - case Boxed(LocalVar(loc1)) :: _ => + case Boxed(LocalVar(loc1)) :: _ if loc1.kind == boxType => val loc2 = info.getAlias(loc1) bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil) debuglog("replaced " + i + " with " + LocalVar(loc2)) diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 3ae1210ebf..8ced574676 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -950,7 +950,16 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { // units.filter should return only one element (currentRun.units filter (_.source.file == aSym.sourceFile)).toList match { case List(unit) => - (unit.body find (_.symbol == aSym)) match { + // SI-4922 `sym == aSym` is insufficent if `aSym` is a clone of symbol + // of the parameter in the tree, as can happen with type parametric methods. + def isCorrespondingParam(sym: Symbol) = ( + sym != null && + sym != NoSymbol && + sym.owner == aSym.owner && + sym.name == aSym.name && + sym.isParamWithDefault + ) + (unit.body find (t => isCorrespondingParam(t.symbol))) match { case Some(ValDef(_,_,_,rhs)) => makeTree(rhs) case _ => None } diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index 12fb8f1507..67519cf90c 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -120,7 +120,7 @@ trait MemberHandlers { if (replProps.vids) """" + " @ " + "%%8x".format(System.identityHashCode(%s)) + " """.trim.format(req fullPath name) else "" - """ + "%s%s: %s = " + %s""".format(prettyName, vidString, string2code(req typeOf name), resultString) + """ + "%s%s: %s = " + %s""".format(string2code(prettyName), vidString, string2code(req typeOf name), resultString) } } } @@ -147,8 +147,7 @@ trait MemberHandlers { override def resultExtractionCode(req: Request) = { val lhsType = string2code(req lookupTypeOf name) val res = string2code(req fullPath name) - - """ + "%s: %s = " + %s + "\n" """.format(lhs, lhsType, res) + "\n" + """ + "%s: %s = " + %s + "\n" """.format(string2code(lhs.toString), lhsType, res) + "\n" } } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index ebbb1d7798..57bdaea17a 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -269,7 +269,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { /** Mix in members of implementation class mixinClass into class clazz */ def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) { - assert(mixinClass.isImplClass, "Not an impl class:" + + if (!mixinClass.isImplClass) debugwarn ("Impl class flag is not set " + ((mixinClass.debugLocationString, mixinInterface.debugLocationString))) for (member <- mixinClass.info.decls ; if isForwarded(member)) { @@ -360,7 +360,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { // first complete the superclass with mixed in members addMixedinMembers(clazz.superClass, unit) - //Console.println("adding members of " + clazz.info.baseClasses.tail.takeWhile(superclazz !=) + " to " + clazz);//DEBUG for (mc <- clazz.mixinClasses ; if mc hasFlag lateINTERFACE) { // @SEAN: adding trait tracking so we don't have to recompile transitive closures unit.depends += mc diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 2f79472cfb..bbab545d9e 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -965,6 +965,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case (NoSymbol, _) => None case (overridden, env) => val om = specializedOverload(clazz, overridden, env) + foreachWithIndex(om.paramss) { (params, i) => + foreachWithIndex(params) { (param, j) => + param.name = overriding.paramss(i)(j).name // SI-6555 Retain the parameter names from the subclass. + } + } debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info)) typeEnv(om) = env addConcreteSpecMethod(overriding) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 95cb052fda..a767850cba 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -327,8 +327,16 @@ abstract class TailCalls extends Transform { transformTrees(cases).asInstanceOf[List[CaseDef]] ) + case Try(block, catches, finalizer @ EmptyTree) => + // SI-1672 Catches are in tail position when there is no finalizer + treeCopy.Try(tree, + noTailTransform(block), + transformTrees(catches).asInstanceOf[List[CaseDef]], + EmptyTree + ) + case Try(block, catches, finalizer) => - // no calls inside a try are in tail position, but keep recursing for nested functions + // no calls inside a try are in tail position if there is a finalizer, but keep recursing for nested functions treeCopy.Try(tree, noTailTransform(block), noTailTransforms(catches).asInstanceOf[List[CaseDef]], diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 9829fd0e57..838ea7d5a0 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -251,7 +251,10 @@ abstract class UnCurry extends InfoTransform val applyMethodDef = { val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL) - methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe) + val paramSyms = map2(formals, fun.vparams) { + (tp, param) => methSym.newSyntheticValueParam(tp, param.name) + } + methSym setInfoAndEnter MethodType(paramSyms, restpe) fun.vparams foreach (_.symbol.owner = methSym) fun.body changeOwner (fun.symbol -> methSym) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index fc10f68454..ad01de9447 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -149,9 +149,20 @@ trait Implicits { class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter) { override def toString = "SearchResult(%s, %s)".format(tree, if (subst.isEmpty) "" else subst) + + def isFailure = false + def isAmbiguousFailure = false + final def isSuccess = !isFailure } - lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) + lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + override def isFailure = true + } + + lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { + override def isFailure = true + override def isAmbiguousFailure = true + } /** A class that records an available implicit * @param name The name of the implicit @@ -831,7 +842,7 @@ trait Implicits { catch divergenceHandler tryImplicitInfo(i) match { - case SearchFailure => + case sr if sr.isFailure => // We don't want errors that occur during checking implicit info // to influence the check of further infos. context.condBufferFlush(_.kind != ErrorKinds.Divergent) @@ -871,14 +882,14 @@ trait Implicits { rest find (alt => !improves(chosen, alt)) match { case Some(competing) => AmbiguousImplicitError(chosen, competing, "both", "and", "")(isView, pt, tree)(context) - return SearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala + return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala case _ => if (isView) chosen.useCountView += 1 else chosen.useCountArg += 1 } } - if (best == SearchFailure) { + if (best.isFailure) { /** If there is no winner, and we witnessed and caught divergence, * now we can throw it for the error message. */ @@ -1377,24 +1388,25 @@ trait Implicits { var result = searchImplicit(context.implicitss, true) - if (result == SearchFailure) { + if (result.isFailure) { if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart) } else { if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart) if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits) } - if (result == SearchFailure) { + if (result.isFailure) { val previousErrs = context.flushAndReturnBuffer() val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null + val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits result = materializeImplicit(pt) // `materializeImplicit` does some preprocessing for `pt` // is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`? - if (result == SearchFailure) result = searchImplicit(implicitsOfExpectedType, false) + if (result.isFailure && !wasAmbigious) result = searchImplicit(implicitsOfExpectedType, false) - if (result == SearchFailure) { + if (result.isFailure) { context.updateBuffer(previousErrs) if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart) } else { @@ -1403,7 +1415,7 @@ trait Implicits { } } - if (result == SearchFailure && settings.debug.value) + if (result.isFailure && settings.debug.value) log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType) result diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index fa9a4ba9ea..3f546c9a51 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1255,7 +1255,11 @@ trait Namers extends MethodSynthesis { case defn: MemberDef => val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann => // need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892. - AnnotationInfo lazily beforeTyper(typer typedAnnotation ann) + AnnotationInfo lazily { + val context1 = typer.context.make(ann) + context1.setReportErrors() + beforeTyper(newTyper(context1) typedAnnotation ann) + } } if (ainfos.nonEmpty) { annotated setAnnotations ainfos diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index fbeb401c7d..3e1d3fdcc4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1264,13 +1264,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val cdef = ClassDef(mods | MODULE, name.toTypeName, Nil, impl) setSymbol classSym setType NoType def findOrCreateModuleVar() = localTyper.typedPos(tree.pos) { - lazy val createModuleVar = gen.mkModuleVarDef(sym) - sym.enclClass.info.decl(nme.moduleVarName(sym.name.toTermName)) match { - // In case we are dealing with local symbol then we already have - // to correct error with forward reference - case NoSymbol => createModuleVar - case vsym => ValDef(vsym) - } + // See SI-5012, SI-6712. + val vsym = ( + if (sym.owner.isTerm) NoSymbol + else sym.enclClass.info.decl(nme.moduleVarName(sym.name.toTermName)) + ) + // In case we are dealing with local symbol then we already have + // to correct error with forward reference + if (vsym == NoSymbol) gen.mkModuleVarDef(sym) + else ValDef(vsym) } def createStaticModuleAccessor() = afterRefchecks { val method = ( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9e07b51b77..83ded04c39 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -134,7 +134,7 @@ trait Typers extends Modes with Adaptations with Tags { val res = if (paramFailed || (paramTp.isError && {paramFailed = true; true})) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) argResultsBuff += res - if (res != SearchFailure) { + if (res.isSuccess) { argBuff += mkArg(res.tree, param.name) } else { mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args @@ -763,7 +763,7 @@ trait Typers extends Modes with Adaptations with Tags { featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name def action(): Boolean = { - def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context) != SearchFailure + def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context).isSuccess def hasOption = settings.language.value exists (s => s == featureName || s == "_") val OK = hasImport || hasOption if (!OK) { @@ -2956,7 +2956,11 @@ trait Typers extends Modes with Adaptations with Tags { var moreToAdd = true while (moreToAdd) { val initElems = scope.elems - for (sym <- scope) + // SI-5877 The decls of a package include decls of the package object. But we don't want to add + // the corresponding synthetics to the package class, only to the package object class. + def shouldAdd(sym: Symbol) = + inBlock || !isInPackageObject(sym, context.owner) + for (sym <- scope if shouldAdd(sym)) for (tree <- context.unit.synthetics get sym) { newStats += typedStat(tree) // might add even more synthetics to the scope context.unit.synthetics -= sym diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 9115b9e5fb..5e6126a7cf 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -10,10 +10,11 @@ package scala.collection package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } -import Wrappers._ import scala.language.implicitConversions trait WrapAsJava { + import Wrappers._ + /** * Implicitly converts a Scala Iterator to a Java Iterator. * The returned Java Iterator is backed by the provided Scala diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index 5a5d204ece..ffcca62291 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -10,11 +10,13 @@ package scala.collection package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } -import Wrappers._ import scala.language.implicitConversions trait LowPriorityWrapAsScala { this: WrapAsScala => + + import Wrappers._ + /** * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap. * The returned Scala ConcurrentMap is backed by the provided Java @@ -34,6 +36,7 @@ trait LowPriorityWrapAsScala { } trait WrapAsScala extends LowPriorityWrapAsScala { + import Wrappers._ /** * Implicitly converts a Java `Iterator` to a Scala `Iterator`. * diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 3b6ab81146..802e16605d 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -33,7 +33,6 @@ import scala.collection.parallel.immutable.ParRange * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#ranges "Scala's Collection Library overview"]] * section on `Ranges` for more information. * - * @define Coll Range * @define coll range * @define mayNotTerminateInf * @define willNotTerminateInf diff --git a/src/library/scala/collection/mutable/MutableList.scala b/src/library/scala/collection/mutable/MutableList.scala index 183de5b727..fd92d2e555 100644 --- a/src/library/scala/collection/mutable/MutableList.scala +++ b/src/library/scala/collection/mutable/MutableList.scala @@ -56,12 +56,16 @@ extends AbstractSeq[A] /** Returns the rest of this list */ override def tail: MutableList[A] = { - require(nonEmpty, "tail of empty list") val tl = new MutableList[A] + tailImpl(tl) + tl + } + + protected final def tailImpl(tl: MutableList[A]) { + require(nonEmpty, "tail of empty list") tl.first0 = first0.tail - tl.last0 = last0 tl.len = len - 1 - tl + tl.last0 = if (tl.len == 0) tl.first0 else last0 } /** Prepends a single element to this list. This operation takes constant diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index 5ea012eb9f..b947fa3cca 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -66,7 +66,7 @@ extends MutableList[A] else { val res = first0.elem first0 = first0.next - len -= 1 + decrementLength() res } @@ -82,11 +82,11 @@ extends MutableList[A] else if (p(first0.elem)) { val res: Option[A] = Some(first0.elem) first0 = first0.next - len -= 1 + decrementLength() res } else { val optElem = removeFromList(p) - if (optElem != None) len -= 1 + if (optElem != None) decrementLength() optElem } @@ -119,7 +119,7 @@ extends MutableList[A] while ((first0.nonEmpty) && p(first0.elem)) { res += first0.elem first0 = first0.next - len -= 1 + decrementLength() } if (first0.isEmpty) res else removeAllFromList(p, res) @@ -130,10 +130,10 @@ extends MutableList[A] var leftlst = first0 while (leftlst.next.nonEmpty) { if (p(leftlst.next.elem)) { - res += leftlst.next.elem - if (leftlst.next eq last0) last0 = leftlst - leftlst.next = leftlst.next.next - len -= 1 + res += leftlst.next.elem + if (leftlst.next eq last0) last0 = leftlst + leftlst.next = leftlst.next.next + decrementLength() } else leftlst = leftlst.next } res @@ -154,7 +154,7 @@ extends MutableList[A] else { val res: Option[LinkedList[A]] = Some(cell.next) cell.next = cell.next.next - len -= 1 + decrementLength() res } } @@ -170,11 +170,8 @@ extends MutableList[A] // TODO - Don't override this just for new to create appropriate type.... override def tail: Queue[A] = { - require(nonEmpty, "tail of empty list") val tl = new Queue[A] - tl.first0 = first0.tail - tl.last0 = last0 - tl.len = len - 1 + tailImpl(tl) tl } @@ -183,6 +180,11 @@ extends MutableList[A] bf ++= seq bf.result } + + private[this] def decrementLength() { + len -= 1 + if (len == 0) last0 = first0 + } } diff --git a/src/library/scala/util/Random.scala b/src/library/scala/util/Random.scala index 24c4cd7a32..2b11594f66 100644 --- a/src/library/scala/util/Random.scala +++ b/src/library/scala/util/Random.scala @@ -17,7 +17,7 @@ import scala.language.{implicitConversions, higherKinds} * @author Stephane Micheloud * */ -class Random(val self: java.util.Random) { +class Random(val self: java.util.Random) extends AnyRef with Serializable { /** Creates a new random number generator using a single long seed. */ def this(seed: Long) = this(new java.util.Random(seed)) diff --git a/test/files/jvm/serialization.scala b/test/files/jvm/serialization.scala index 34b64938b4..f2c47aad77 100644 --- a/test/files/jvm/serialization.scala +++ b/test/files/jvm/serialization.scala @@ -604,6 +604,7 @@ object Test { Test7 Test8 Test9_parallel + Test10_util } } @@ -669,3 +670,17 @@ object Test9_parallel { throw e } } + +//############################################################################ +// Test classes in package scala.util + +object Test10_util { + import scala.util.Random + def rep[A](n: Int)(f: => A) { if (n > 0) { f; rep(n-1)(f) } } + + try { + val random = new Random(345) + val random2: Random = read(write(random)) + rep(5) { assert(random.nextInt == random2.nextInt) } + } +} diff --git a/test/files/neg/case-collision.check b/test/files/neg/case-collision.check new file mode 100644 index 0000000000..4edc6f1205 --- /dev/null +++ b/test/files/neg/case-collision.check @@ -0,0 +1,10 @@ +case-collision.scala:5: error: Class foo.BIPPY differs only in case from foo.Bippy. Such classes will overwrite one another on case-insensitive filesystems. +class BIPPY + ^ +case-collision.scala:11: error: Class foo.HyRaX$ differs only in case from foo.Hyrax$. Such classes will overwrite one another on case-insensitive filesystems. +object HyRaX + ^ +case-collision.scala:8: error: Class foo.DINGO$ differs only in case from foo.Dingo$. Such classes will overwrite one another on case-insensitive filesystems. +object DINGO + ^ +three errors found diff --git a/test/files/neg/case-collision.flags b/test/files/neg/case-collision.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/case-collision.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/case-collision.scala b/test/files/neg/case-collision.scala new file mode 100644 index 0000000000..241169a77a --- /dev/null +++ b/test/files/neg/case-collision.scala @@ -0,0 +1,11 @@ +package foo + +class Bippy + +class BIPPY + +object Dingo +object DINGO + +case class Hyrax() +object HyRaX diff --git a/test/files/neg/t1672b.check b/test/files/neg/t1672b.check new file mode 100644 index 0000000000..60ccf77174 --- /dev/null +++ b/test/files/neg/t1672b.check @@ -0,0 +1,16 @@ +t1672b.scala:3: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position + def bar : Nothing = { + ^ +t1672b.scala:14: error: could not optimize @tailrec annotated method baz: it contains a recursive call not in tail position + def baz : Nothing = { + ^ +t1672b.scala:29: error: could not optimize @tailrec annotated method boz: it contains a recursive call not in tail position + case _: Throwable => boz; ??? + ^ +t1672b.scala:34: error: could not optimize @tailrec annotated method bez: it contains a recursive call not in tail position + def bez : Nothing = { + ^ +t1672b.scala:46: error: could not optimize @tailrec annotated method bar: it contains a recursive call not in tail position + else 1 + (try { + ^ +5 errors found diff --git a/test/files/neg/t1672b.scala b/test/files/neg/t1672b.scala new file mode 100644 index 0000000000..0ccdd03633 --- /dev/null +++ b/test/files/neg/t1672b.scala @@ -0,0 +1,52 @@ +object Test { + @annotation.tailrec + def bar : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => bar + } finally { + bar + } + } + + @annotation.tailrec + def baz : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => baz + } finally { + ??? + } + } + + @annotation.tailrec + def boz : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => boz; ??? + } + } + + @annotation.tailrec + def bez : Nothing = { + try { + bez + } finally { + ??? + } + } + + // the `liftedTree` local method will prevent a tail call here. + @annotation.tailrec + def bar(i : Int) : Int = { + if (i == 0) 0 + else 1 + (try { + throw new RuntimeException + } catch { + case _: Throwable => bar(i - 1) + }) + } +} diff --git a/test/files/neg/t6260.check b/test/files/neg/t6260.check index 2b7f1a8bfb..46e9bd1dfc 100644 --- a/test/files/neg/t6260.check +++ b/test/files/neg/t6260.check @@ -1,10 +1,10 @@ -t6260.scala:3: error: bridge generated for member method apply: (x$1: Box[X])Box[Y] in anonymous class $anonfun +t6260.scala:3: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in anonymous class $anonfun which overrides method apply: (v1: T1)R in trait Function1 clashes with definition of the member itself; both have erased type (v1: Object)Object ((bx: Box[X]) => new Box(f(bx.x)))(this) ^ -t6260.scala:8: error: bridge generated for member method apply: (x$1: Box[X])Box[Y] in anonymous class $anonfun +t6260.scala:8: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in anonymous class $anonfun which overrides method apply: (v1: T1)R in trait Function1 clashes with definition of the member itself; both have erased type (v1: Object)Object diff --git a/test/files/neg/t6535.check b/test/files/neg/t6535.check new file mode 100644 index 0000000000..1225ea70db --- /dev/null +++ b/test/files/neg/t6535.check @@ -0,0 +1,6 @@ +t6535.scala:2: error: encountered unrecoverable cycle resolving import. +Note: this is often due in part to a class depending on a definition nested within its companion. +If applicable, you may wish to try moving some members into another object. + import Bs.B._ + ^ +one error found diff --git a/test/files/neg/t6535.scala b/test/files/neg/t6535.scala new file mode 100644 index 0000000000..30a750311c --- /dev/null +++ b/test/files/neg/t6535.scala @@ -0,0 +1,15 @@ +object As { + import Bs.B._ + + object A + extends scala.AnyRef // needed for the cycle; + // replacing with a locally defined closs doesn't + // hit the locked import and hence doesn't cycle. +} + +object Bs { + import As.A._ + + object B + extends scala.AnyRef // scala.Immutable, ... +} diff --git a/test/files/neg/t6558.check b/test/files/neg/t6558.check new file mode 100644 index 0000000000..1b39ef9986 --- /dev/null +++ b/test/files/neg/t6558.check @@ -0,0 +1,10 @@ +t6558.scala:19: error: not found: type classs + @classs + ^ +t6558.scala:22: error: not found: type typeparam + class D[@typeparam T] + ^ +t6558.scala:25: error: not found: type valueparam + @valueparam x: Any + ^ +three errors found diff --git a/test/files/neg/t6558.scala b/test/files/neg/t6558.scala new file mode 100644 index 0000000000..bdc441698f --- /dev/null +++ b/test/files/neg/t6558.scala @@ -0,0 +1,27 @@ +class AnnotNotFound { + def foo(a: Any) = () + + foo { + // Not yet issued in the context of this file, see SI-6758 + // This error is issued in t6558b.scala + @inargument + def foo = 0 + foo + } + + () => { + // As per above + @infunction + def foo = 0 + () + } + + @classs + class C + + class D[@typeparam T] + + class E( + @valueparam x: Any + ) +} diff --git a/test/files/neg/t6558b.check b/test/files/neg/t6558b.check new file mode 100644 index 0000000000..cfa384fc08 --- /dev/null +++ b/test/files/neg/t6558b.check @@ -0,0 +1,7 @@ +t6558b.scala:5: error: not found: type inargument + @inargument + ^ +t6558b.scala:11: error: not found: type infunction + @infunction + ^ +two errors found diff --git a/test/files/neg/t6558b.scala b/test/files/neg/t6558b.scala new file mode 100644 index 0000000000..2aa06f69cf --- /dev/null +++ b/test/files/neg/t6558b.scala @@ -0,0 +1,15 @@ +class AnnotNotFound { + def foo(a: Any) = () + + foo { + @inargument + def foo = 0 + foo + } + + () => { + @infunction + def foo = 0 + () + } +} diff --git a/test/files/neg/t6667.check b/test/files/neg/t6667.check new file mode 100644 index 0000000000..43313fa4fe --- /dev/null +++ b/test/files/neg/t6667.check @@ -0,0 +1,13 @@ +t6667.scala:8: error: ambiguous implicit values: + both value inScope1 in object Test of type => C + and value inScope2 in object Test of type => C + match expected type C + implicitly[C]: Unit // C.companion was used; whereas the ambiguity should abort the implicit search. + ^ +t6667.scala:9: error: ambiguous implicit values: + both value inScope1 in object Test of type => C + and value inScope2 in object Test of type => C + match expected type C + implicitly[C] // ambiguity reported, rather than falling back to C.companion + ^ +two errors found diff --git a/test/files/neg/t6667.scala b/test/files/neg/t6667.scala new file mode 100644 index 0000000000..fb857ebd33 --- /dev/null +++ b/test/files/neg/t6667.scala @@ -0,0 +1,10 @@ +class C +object C { + implicit def companion = new C +} + +object Test { + implicit val inScope1, inScope2 = new C + implicitly[C]: Unit // C.companion was used; whereas the ambiguity should abort the implicit search. + implicitly[C] // ambiguity reported, rather than falling back to C.companion +} diff --git a/test/files/neg/t6667b.check b/test/files/neg/t6667b.check new file mode 100644 index 0000000000..99cea9a47c --- /dev/null +++ b/test/files/neg/t6667b.check @@ -0,0 +1,13 @@ +t6667b.scala:16: error: ambiguous implicit values: + both value a in object Test of type => Test.Box + and value b of type Test.Box + match expected type Test.Box + new Test() + ^ +t6667b.scala:19: error: ambiguous implicit values: + both value a in object Test of type => Test.Box + and value b of type Test.Box + match expected type Test.Box + new Test() + ^ +two errors found diff --git a/test/files/neg/t6667b.scala b/test/files/neg/t6667b.scala new file mode 100644 index 0000000000..4e64e1af17 --- /dev/null +++ b/test/files/neg/t6667b.scala @@ -0,0 +1,25 @@ +object Test { + abstract class Box { + val value: Int + } + + implicit val a: Box = new Box { + val value= 1 + } + + def main(args: Array[String]) { + implicit val b: Box= new Box { + val value= 2 + } + + new Object { + new Test() + } + // compare with: + new Test() + } +} + +class Test()(implicit x: Test.Box) { + println(x.value) +} diff --git a/test/files/pos/t1672.scala b/test/files/pos/t1672.scala new file mode 100644 index 0000000000..5ee6bb1759 --- /dev/null +++ b/test/files/pos/t1672.scala @@ -0,0 +1,10 @@ +object Test { + @annotation.tailrec + def bar : Nothing = { + try { + throw new RuntimeException + } catch { + case _: Throwable => bar + } + } +} diff --git a/test/files/pos/t5877.scala b/test/files/pos/t5877.scala new file mode 100644 index 0000000000..c7827df99f --- /dev/null +++ b/test/files/pos/t5877.scala @@ -0,0 +1,14 @@ +package foo { + class Foo + + object Test { + new Foo().huzzah + } +} + +package object foo { + // Crasher: No synthetics for method PimpedFoo2: synthetics contains + implicit class PimpedFoo2(value: Foo) { + def huzzah = "" + } +} diff --git a/test/files/pos/t5877b.scala b/test/files/pos/t5877b.scala new file mode 100644 index 0000000000..6b8cbd473e --- /dev/null +++ b/test/files/pos/t5877b.scala @@ -0,0 +1,13 @@ +package foo + +class Foo + +object Test { + new Foo().huzzah +} + +object `package` { + implicit class PimpedFoo2(value: Foo) { + def huzzah = "" + } +} diff --git a/test/files/pos/t6547.flags b/test/files/pos/t6547.flags new file mode 100644 index 0000000000..c9b68d70dc --- /dev/null +++ b/test/files/pos/t6547.flags @@ -0,0 +1 @@ +-optimise diff --git a/test/files/pos/t6547.scala b/test/files/pos/t6547.scala new file mode 100644 index 0000000000..53bd798219 --- /dev/null +++ b/test/files/pos/t6547.scala @@ -0,0 +1,6 @@ +trait ConfigurableDefault[@specialized V] { + def fillArray(arr: Array[V], v: V) = (arr: Any) match { + case x: Array[Int] => null + case x: Array[Long] => v.asInstanceOf[Long] + } +} diff --git a/test/files/pos/t6712.scala b/test/files/pos/t6712.scala new file mode 100644 index 0000000000..3c96eb14fb --- /dev/null +++ b/test/files/pos/t6712.scala @@ -0,0 +1,5 @@ +class H { + object O + + def foo() { object O } +} diff --git a/test/files/run/reify_renamed_term_basic.check b/test/files/run/reify_renamed_term_basic.check new file mode 100644 index 0000000000..e78f94fffd --- /dev/null +++ b/test/files/run/reify_renamed_term_basic.check @@ -0,0 +1 @@ +((),(),()) diff --git a/test/files/run/reify_renamed_term_basic.scala b/test/files/run/reify_renamed_term_basic.scala new file mode 100644 index 0000000000..cd76def395 --- /dev/null +++ b/test/files/run/reify_renamed_term_basic.scala @@ -0,0 +1,20 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object A { + object B { + val c = () + } +} + +object Test extends App { + import A.{B => X} + import A.B.{c => y} + import X.{c => z} + + val expr = reify ( + X.c, y, z + ) + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_local_to_reifee.check b/test/files/run/reify_renamed_term_local_to_reifee.check new file mode 100644 index 0000000000..e78f94fffd --- /dev/null +++ b/test/files/run/reify_renamed_term_local_to_reifee.check @@ -0,0 +1 @@ +((),(),()) diff --git a/test/files/run/reify_renamed_term_local_to_reifee.scala b/test/files/run/reify_renamed_term_local_to_reifee.scala new file mode 100644 index 0000000000..1860316a5b --- /dev/null +++ b/test/files/run/reify_renamed_term_local_to_reifee.scala @@ -0,0 +1,20 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object A { + object B { + val c = () + } +} + +object Test extends App { + val expr = reify { + import A.{B => X} + import A.B.{c => y} + import X.{c => z} + + (X.c, y, z) + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_overloaded_method.check b/test/files/run/reify_renamed_term_overloaded_method.check new file mode 100644 index 0000000000..48082f72f0 --- /dev/null +++ b/test/files/run/reify_renamed_term_overloaded_method.check @@ -0,0 +1 @@ +12 diff --git a/test/files/run/reify_renamed_term_overloaded_method.scala b/test/files/run/reify_renamed_term_overloaded_method.scala new file mode 100644 index 0000000000..3ef442d203 --- /dev/null +++ b/test/files/run/reify_renamed_term_overloaded_method.scala @@ -0,0 +1,17 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + def show(i: Int) = i.toString + def show(s: String) = s +} + +object Test extends App { + import O.{show => s} + + val expr = reify { + s("1") + s(2) + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_term_si5841.check b/test/files/run/reify_renamed_term_si5841.check new file mode 100644 index 0000000000..6031277b76 --- /dev/null +++ b/test/files/run/reify_renamed_term_si5841.check @@ -0,0 +1 @@ +class scala.reflect.runtime.JavaUniverse diff --git a/test/files/run/reify_renamed_term_si5841.scala b/test/files/run/reify_renamed_term_si5841.scala new file mode 100644 index 0000000000..ef18d650bf --- /dev/null +++ b/test/files/run/reify_renamed_term_si5841.scala @@ -0,0 +1,7 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{universe => ru} +import scala.tools.reflect.Eval + +object Test extends App { + println(reify{ru}.eval.getClass) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_basic.check b/test/files/run/reify_renamed_type_basic.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_basic.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_basic.scala b/test/files/run/reify_renamed_type_basic.scala new file mode 100644 index 0000000000..23729e5c54 --- /dev/null +++ b/test/files/run/reify_renamed_type_basic.scala @@ -0,0 +1,16 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + type A = Unit +} + +object Test extends App { + import O.{A => X} + + def expr = reify { + val a: X = () + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_local_to_reifee.check b/test/files/run/reify_renamed_type_local_to_reifee.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_local_to_reifee.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_local_to_reifee.scala b/test/files/run/reify_renamed_type_local_to_reifee.scala new file mode 100644 index 0000000000..ed1bad239e --- /dev/null +++ b/test/files/run/reify_renamed_type_local_to_reifee.scala @@ -0,0 +1,24 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +object O { + type A = Unit +} + +object Test extends App { + val expr = reify { + import O.{A => X} + + val a: X = () + + object P { + type B = Unit + } + + import P.{B => Y} + + val b: Y = () + } + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/reify_renamed_type_spliceable.check b/test/files/run/reify_renamed_type_spliceable.check new file mode 100644 index 0000000000..6a452c185a --- /dev/null +++ b/test/files/run/reify_renamed_type_spliceable.check @@ -0,0 +1 @@ +() diff --git a/test/files/run/reify_renamed_type_spliceable.scala b/test/files/run/reify_renamed_type_spliceable.scala new file mode 100644 index 0000000000..9c2cff5199 --- /dev/null +++ b/test/files/run/reify_renamed_type_spliceable.scala @@ -0,0 +1,21 @@ +import scala.reflect.runtime.universe._ +import scala.tools.reflect.Eval + +abstract class C { + type T >: Null +} + +object Test extends App { + def foo(c: C) = { + import c.{T => U} + reify { + val x: U = null + } + } + + val expr = foo(new C { + type T = AnyRef + }) + + println(expr.eval) +}
\ No newline at end of file diff --git a/test/files/run/t1672.scala b/test/files/run/t1672.scala new file mode 100644 index 0000000000..ee025b9031 --- /dev/null +++ b/test/files/run/t1672.scala @@ -0,0 +1,28 @@ +object Test { + @annotation.tailrec + def bar(i : Int) : Int = { + if (i == 0) 0 + else try { + throw new RuntimeException + } catch { + case _: Throwable => bar(i - 1) + } + } + + @annotation.tailrec + def nestedTry1(i : Int) : Int = { + if (i == 0) 0 + else try { + throw new RuntimeException + } catch { + case _: Throwable => + try { ??? } catch { case _: Throwable => nestedTry1(i - 1) } + } + } + + def main(args: Array[String]) { + assert(bar(2) == 0) + + assert(nestedTry1(2) == 0) + } +} diff --git a/test/files/run/t5789.check b/test/files/run/t5789.check new file mode 100644 index 0000000000..ea8d4966b1 --- /dev/null +++ b/test/files/run/t5789.check @@ -0,0 +1,14 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> val n = 2 +n: Int = 2 + +scala> () => n +res0: () => Int = <function0> + +scala> + +scala> diff --git a/test/files/run/t5789.scala b/test/files/run/t5789.scala new file mode 100644 index 0000000000..461f6a4aae --- /dev/null +++ b/test/files/run/t5789.scala @@ -0,0 +1,14 @@ + +import scala.tools.nsc._ +import interpreter.ILoop +import scala.tools.partest.ReplTest + + +object Test extends ReplTest { + override def extraSettings = "-Yinline" + def code = """ + val n = 2 + () => n + """ +} + diff --git a/test/files/run/t5894.scala b/test/files/run/t5894.scala new file mode 100644 index 0000000000..abeec32365 --- /dev/null +++ b/test/files/run/t5894.scala @@ -0,0 +1,17 @@ +import language.experimental.macros + +class Test + +object Test { + def foo = macro fooImpl + def fooImpl(c: reflect.macros.Context) = c.literalUnit + + def main(args: Array[String]) { + try { + val method = classOf[Test].getMethod("foo") + sys.error("Static forwarder generated for macro: " + method) + } catch { + case _: NoSuchMethodException => // okay + } + } +} diff --git a/test/files/run/t6549.check b/test/files/run/t6549.check new file mode 100644 index 0000000000..bc78aac741 --- /dev/null +++ b/test/files/run/t6549.check @@ -0,0 +1,32 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> case class `X"`(var xxx: Any) +defined class X$u0022 + +scala> val m = Map(("": Any) -> `X"`("\""), ('s: Any) -> `X"`("\"")) +m: scala.collection.immutable.Map[Any,X"] = Map("" -> X"("), 's -> X"(")) + +scala> m("") +res0: X" = X"(") + +scala> m("").xxx +res1: Any = " + +scala> m("").xxx = 0 +m("").xxx: Any = 0 + +scala> m("").xxx = "\"" +m("").xxx: Any = " + +scala> m('s).xxx = 's +m(scala.Symbol("s")).xxx: Any = 's + +scala> val `"` = 0 +": Int = 0 + +scala> + +scala> diff --git a/test/files/run/t6549.scala b/test/files/run/t6549.scala new file mode 100644 index 0000000000..7335661dc7 --- /dev/null +++ b/test/files/run/t6549.scala @@ -0,0 +1,22 @@ +import scala.tools.partest.ReplTest + +// Check that the fragments of code generated in +// in the REPL correctly escape values added to +// literal strings. +// +// Before, we saw: +// scala> m("").x = 77 +// <console>:10: error: ')' expected but string literal found. +// + "m("").x: Int = " + `$ires8` + "\n" +object Test extends ReplTest { + def code = """ + |case class `X"`(var xxx: Any) + |val m = Map(("": Any) -> `X"`("\""), ('s: Any) -> `X"`("\"")) + |m("") + |m("").xxx + |m("").xxx = 0 + |m("").xxx = "\"" + |m('s).xxx = 's + |val `"` = 0 + """.stripMargin +} diff --git a/test/files/run/t6555.check b/test/files/run/t6555.check new file mode 100644 index 0000000000..04117b7c2f --- /dev/null +++ b/test/files/run/t6555.check @@ -0,0 +1,22 @@ +[[syntax trees at end of specialize]] // newSource1 +package <empty> { + class Foo extends Object { + def <init>(): Foo = { + Foo.super.<init>(); + () + }; + private[this] val f: Int => Int = { + @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1$mcII$sp with Serializable { + def <init>(): anonymous class $anonfun = { + $anonfun.super.<init>(); + () + }; + final def apply(param: Int): Int = $anonfun.this.apply$mcII$sp(param); + <specialized> def apply$mcII$sp(param: Int): Int = param + }; + (new anonymous class $anonfun(): Int => Int) + }; + <stable> <accessor> def f(): Int => Int = Foo.this.f + } +} + diff --git a/test/files/run/t6555.scala b/test/files/run/t6555.scala new file mode 100644 index 0000000000..b1a6137786 --- /dev/null +++ b/test/files/run/t6555.scala @@ -0,0 +1,15 @@ +import scala.tools.partest._ +import java.io.{Console => _, _} + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -Xprint:specialize -d " + testOutput.path + + override def code = "class Foo { val f = (param: Int) => param } " + + override def show(): Unit = { + Console.withErr(System.out) { + compile() + } + } +} diff --git a/test/files/run/t6614.check b/test/files/run/t6614.check new file mode 100644 index 0000000000..2e80ebda8b --- /dev/null +++ b/test/files/run/t6614.check @@ -0,0 +1,11 @@ +(ArrayStack(),true) +(ArrayStack(0),true) +(ArrayStack(0, 1),true) +(ArrayStack(0, 1, 2),true) +(ArrayStack(0, 1, 2, 3),true) +(ArrayStack(0, 1, 2, 3, 4),true) +(ArrayStack(0, 1, 2, 3, 4, 5),true) +(ArrayStack(0, 1, 2, 3, 4, 5, 6),true) +(ArrayStack(0, 1, 2, 3, 4, 5, 6, 7),true) +(ArrayStack(0, 1, 2, 3, 4, 5, 6, 7, 8),true) +(ArrayStack(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),true) diff --git a/test/files/run/t6614.scala b/test/files/run/t6614.scala new file mode 100644 index 0000000000..3ad9f36fc4 --- /dev/null +++ b/test/files/run/t6614.scala @@ -0,0 +1,8 @@ +object Test extends App { + import scala.collection.mutable.ArrayStack + + println((for (i <- 0 to 10) yield { + val in = ArrayStack.tabulate(i)(_.toString) + (in, (in filter (_ => true)) == in) + }).mkString("\n")) +} diff --git a/test/files/run/t6690.scala b/test/files/run/t6690.scala new file mode 100644 index 0000000000..43ede967a0 --- /dev/null +++ b/test/files/run/t6690.scala @@ -0,0 +1,62 @@ +import scala.collection.mutable + +object Test extends App { + def last0(ml: mutable.MutableList[Int]) = + ml.asInstanceOf[{def last0: mutable.LinkedList[Int]}].last0 + + def first0(ml: mutable.MutableList[Int]) = + ml.asInstanceOf[{def first0: mutable.LinkedList[Int]}].first0 + + val f = mutable.Queue[Int]() + def check(desc: String) { + assert(f.length == 0, s"$desc: non empty: $f") + assert(last0(f).isEmpty, s"$desc: last0 leak: ${last0(f)}") + assert(first0(f).isEmpty, s"$desc: first0 leak: ${last0(f)}") + } + + f.enqueue(1) + f.dequeue() + check("dequeue 1") + + f.enqueue(1) + f.enqueue(2) + f.dequeue() + assert(last0(f).toList == List(2), last0(f)) + f.dequeue() + check("dequeue 2") + + f.enqueue(1) + f.dequeueAll(_ => false) + f.dequeueAll(_ => true) + check("dequeueAll") + + f.enqueue(1) + f.dequeueFirst(_ => true) + check("dequeueFirst") + + { + f.enqueue(1) + val tail = f.tail + assert(last0(tail).isEmpty, last0(tail)) + assert(first0(tail).isEmpty, first0(tail)) + } + + { + val ml = mutable.MutableList[Int]() + 1 +=: ml + val tail = ml.tail + assert(last0(tail).isEmpty, last0(tail)) + assert(first0(tail).isEmpty, first0(tail)) + } + + { + val ml = mutable.MutableList[Int]() + 1 +=: ml + ml += 2 + val tail = ml.tail + assert(last0(tail).toList == List(2), last0(tail)) + assert(first0(tail) == last0(tail).toList, first0(tail)) + assert(last0(tail.tail).toList == Nil, last0(tail.tail).toList) + assert(first0(tail.tail) == Nil, first0(tail.tail)) + } +} diff --git a/test/scaladoc/run/t4922.check b/test/scaladoc/run/t4922.check new file mode 100644 index 0000000000..619c56180b --- /dev/null +++ b/test/scaladoc/run/t4922.check @@ -0,0 +1 @@ +Done. diff --git a/test/scaladoc/run/t4922.scala b/test/scaladoc/run/t4922.scala new file mode 100644 index 0000000000..bce87ac980 --- /dev/null +++ b/test/scaladoc/run/t4922.scala @@ -0,0 +1,32 @@ +import scala.tools.nsc.doc.model._ +import scala.tools.partest.ScaladocModelTest + +object Test extends ScaladocModelTest { + + // Test code + override def code = """ + // This the default values should be displayed + + object Test { + def f (a: Any = "".isEmpty) = () + def g[A](b: A = null) = () + } + """ + + // no need for special settings + def scaladocSettings = "" + + def testModel(rootPackage: Package) = { + // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s)) + import access._ + + val Test = rootPackage._object("Test") + val f = Test._method("f") + val g = Test._method("g") + + def assertEqual(s1: String, s2: String) = assert(s1 == s2, s1 + " == " + s2) + + assertEqual(f.valueParams(0)(0).defaultValue.get.expression, "\"\".isEmpty") + assertEqual(g.valueParams(0)(0).defaultValue.get.expression, "null") + } +}
\ No newline at end of file |