diff options
106 files changed, 1105 insertions, 401 deletions
diff --git a/lib/ant/ant-contrib.jar.desired.sha1 b/lib/ant/ant-contrib.jar.desired.sha1 index 56745657c5..65bcd122bf 100644 --- a/lib/ant/ant-contrib.jar.desired.sha1 +++ b/lib/ant/ant-contrib.jar.desired.sha1 @@ -1 +1 @@ -943cd5c8802b2a3a64a010efb86ec19bac142e40 ?ant-contrib.jar +943cd5c8802b2a3a64a010efb86ec19bac142e40 *ant-contrib.jar diff --git a/lib/ant/ant-dotnet-1.0.jar.desired.sha1 b/lib/ant/ant-dotnet-1.0.jar.desired.sha1 index 1f1dc9b8c1..d8b6a1ca85 100644 --- a/lib/ant/ant-dotnet-1.0.jar.desired.sha1 +++ b/lib/ant/ant-dotnet-1.0.jar.desired.sha1 @@ -1 +1 @@ -3fc1e35ca8c991fc3488548f7a276bd9053c179d ?ant-dotnet-1.0.jar +3fc1e35ca8c991fc3488548f7a276bd9053c179d *ant-dotnet-1.0.jar diff --git a/lib/ant/ant.jar.desired.sha1 b/lib/ant/ant.jar.desired.sha1 index 852b3397cb..bcb610d6de 100644 --- a/lib/ant/ant.jar.desired.sha1 +++ b/lib/ant/ant.jar.desired.sha1 @@ -1 +1 @@ -7b456ca6b93900f96e58cc8371f03d90a9c1c8d1 ?ant.jar +7b456ca6b93900f96e58cc8371f03d90a9c1c8d1 *ant.jar diff --git a/lib/ant/maven-ant-tasks-2.1.1.jar.desired.sha1 b/lib/ant/maven-ant-tasks-2.1.1.jar.desired.sha1 index 06dcb1e312..53f87c3461 100644 --- a/lib/ant/maven-ant-tasks-2.1.1.jar.desired.sha1 +++ b/lib/ant/maven-ant-tasks-2.1.1.jar.desired.sha1 @@ -1 +1 @@ -7e50e3e227d834695f1e0bf018a7326e06ee4c86 ?maven-ant-tasks-2.1.1.jar +7e50e3e227d834695f1e0bf018a7326e06ee4c86 *maven-ant-tasks-2.1.1.jar diff --git a/lib/ant/vizant.jar.desired.sha1 b/lib/ant/vizant.jar.desired.sha1 index 00ff17d159..998da4643a 100644 --- a/lib/ant/vizant.jar.desired.sha1 +++ b/lib/ant/vizant.jar.desired.sha1 @@ -1 +1 @@ -2c61d6e9a912b3253194d5d6d3e1db7e2545ac4b ?vizant.jar +2c61d6e9a912b3253194d5d6d3e1db7e2545ac4b *vizant.jar diff --git a/lib/fjbg.jar.desired.sha1 b/lib/fjbg.jar.desired.sha1 index d24a5d01fc..6f3ccc77bd 100644 --- a/lib/fjbg.jar.desired.sha1 +++ b/lib/fjbg.jar.desired.sha1 @@ -1 +1 @@ -c3f9b576c91cb9761932ad936ccc4a71f33d2ef2 ?fjbg.jar +8acc87f222210b4a5eb2675477602fc1759e7684 *fjbg.jar diff --git a/lib/forkjoin.jar.desired.sha1 b/lib/forkjoin.jar.desired.sha1 index d31539daf4..8b24962e2c 100644 --- a/lib/forkjoin.jar.desired.sha1 +++ b/lib/forkjoin.jar.desired.sha1 @@ -1 +1 @@ -b5baf94dff8d3ca991d44a59add7bcbf6640379b ?forkjoin.jar +f93a2525b5616d3a4bee7848fabbb2856b56f653 *forkjoin.jar diff --git a/lib/jline.jar.desired.sha1 b/lib/jline.jar.desired.sha1 index 8acb0c9b14..b0426130ac 100644 --- a/lib/jline.jar.desired.sha1 +++ b/lib/jline.jar.desired.sha1 @@ -1 +1 @@ -a5261e70728c1847639e2b47d953441d0b217bcb ?jline.jar +a5261e70728c1847639e2b47d953441d0b217bcb *jline.jar diff --git a/lib/msil.jar.desired.sha1 b/lib/msil.jar.desired.sha1 index 2c2fe79dda..9396b273ab 100644 --- a/lib/msil.jar.desired.sha1 +++ b/lib/msil.jar.desired.sha1 @@ -1 +1 @@ -d48cb950ceded82a5e0ffae8ef2c68d0923ed00c ?msil.jar +d48cb950ceded82a5e0ffae8ef2c68d0923ed00c *msil.jar diff --git a/lib/scala-compiler-src.jar.desired.sha1 b/lib/scala-compiler-src.jar.desired.sha1 new file mode 100644 index 0000000000..48b3d3284e --- /dev/null +++ b/lib/scala-compiler-src.jar.desired.sha1 @@ -0,0 +1 @@ +259fd9f0a50ed6003248a01a366a97a5549aa386 ?scala-compiler-src.jar diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index 9a47d9f730..a8dbdb0a38 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -554bcc4a543360c8dc48fde91124dc57319d3460 ?scala-compiler.jar +42f7367cc6ac59022d098e6091e5425390b9c925 ?scala-compiler.jar diff --git a/lib/scala-library-src.jar.desired.sha1 b/lib/scala-library-src.jar.desired.sha1 index 1ec21bc6ee..3379287733 100644 --- a/lib/scala-library-src.jar.desired.sha1 +++ b/lib/scala-library-src.jar.desired.sha1 @@ -1 +1 @@ -7db4c7523f0e268ce58de2ab4ae6a3dd0e903f43 ?scala-library-src.jar +e31e38414fd19c10add3e65bf77c2fd7c6c26f7d ?scala-library-src.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index ec73b5f7b8..bef528ce26 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -071d32b24daaeaf961675f248758fedd31a806ed ?scala-library.jar +2418c95bf7db34f87ebda4a5eaa918fe85047afb ?scala-library.jar diff --git a/lib/scala-reflect-src.jar.desired.sha1 b/lib/scala-reflect-src.jar.desired.sha1 new file mode 100644 index 0000000000..b3a5f03efe --- /dev/null +++ b/lib/scala-reflect-src.jar.desired.sha1 @@ -0,0 +1 @@ +51c64d77ad4c4233a06cea7ea80b0fb77e9867c4 ?scala-reflect-src.jar diff --git a/lib/scala-reflect.jar.desired.sha1 b/lib/scala-reflect.jar.desired.sha1 index 4be2e84aef..4d913d73ab 100644 --- a/lib/scala-reflect.jar.desired.sha1 +++ b/lib/scala-reflect.jar.desired.sha1 @@ -1 +1 @@ -b6e2bbbc1707104119adcb09aeb666690419c424 ?scala-reflect.jar +5656bf2f17bb9f22b3ba61a83393a9794eaa5429 ?scala-reflect.jar diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 327a864e3b..e378d71944 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -319,7 +319,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def ccon = Class.forName(name).getConstructor(classOf[CharsetDecoder], classOf[Reporter]) try Some(ccon.newInstance(charset.newDecoder(), reporter).asInstanceOf[SourceReader]) - catch { case x: Exception => + catch { case ex: Throwable => globalError("exception while trying to instantiate source reader '" + name + "'") None } @@ -1546,7 +1546,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) - catch { case ex => + catch { case ex: Throwable => val shown = if (settings.verbose.value) { val pw = new java.io.PrintWriter(new java.io.StringWriter) ex.printStackTrace(pw) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index c3fbf31cc6..7a5615ac26 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -516,7 +516,7 @@ abstract class TypeFlowAnalysis { * but the effect on method size could be explored. */ putOnRadar(m.linearizedBlocks(linearizer)) populatePerimeter() - assert(relevantBBs.isEmpty || relevantBBs.contains(m.startBlock), "you gave me dead code") + // usually but not always true (counterexample in SI-6015) `(relevantBBs.isEmpty || relevantBBs.contains(m.startBlock))` } def conclusives(b: BasicBlock): List[opcodes.CALL_METHOD] = { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index ac2780f53e..8d243a1dd0 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -295,6 +295,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0,
if (sym.isStaticMember) ACC_STATIC else 0,
if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
+ if (sym.isHidden) ACC_SYNTHETIC else 0,
if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
if (sym.isVarargsMethod) ACC_VARARGS else 0,
if (sym.hasFlag(Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0
@@ -849,7 +850,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // without it. This is particularly bad because the availability of
// generic information could disappear as a consequence of a seemingly
// unrelated change.
- sym.isSynthetic
+ sym.isHidden
|| sym.isLiftedMethod
|| sym.isBridge
|| (sym.ownerChain exists (_.isImplClass))
@@ -1322,7 +1323,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // Additional interface parents based on annotations and other cues
def newParentForAttr(attr: Symbol): Option[Symbol] = attr match {
case SerializableAttr => Some(SerializableClass)
- case CloneableAttr => Some(JavaCloneableClass)
+ case CloneableAttr => Some(CloneableClass)
case RemoteAttr => Some(RemoteInterfaceClass)
case _ => None
}
@@ -2191,9 +2192,15 @@ abstract class GenASM extends SubComponent with BytecodeWriters { val st = pending.getOrElseUpdate(lv, mutable.Stack.empty[Label])
st.push(start)
}
- def popScope(lv: Local, end: Label) {
- val start = pending(lv).pop()
- seen ::= LocVarEntry(lv, start, end)
+ def popScope(lv: Local, end: Label, iPos: Position) {
+ pending.get(lv) match {
+ case Some(st) if st.nonEmpty =>
+ val start = st.pop()
+ seen ::= LocVarEntry(lv, start, end)
+ case _ =>
+ // TODO SI-6049
+ getCurrentCUnit().warning(iPos, "Visited SCOPE_EXIT before visiting corresponding SCOPE_ENTER. SI-6049")
+ }
}
def getMerged(): collection.Map[Local, List[Interval]] = {
@@ -2406,7 +2413,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { // similarly, these labels aren't tracked in the `labels` map.
val end = new asm.Label
jmethod.visitLabel(end)
- scoping.popScope(lv, end)
+ scoping.popScope(lv, end, instr.pos)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 21260d399c..9661ae6b3e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -727,7 +727,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with // without it. This is particularly bad because the availability of // generic information could disappear as a consequence of a seemingly // unrelated change. - sym.isSynthetic + sym.isHidden || sym.isLiftedMethod || sym.isBridge || (sym.ownerChain exists (_.isImplClass)) @@ -1972,6 +1972,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0, if (sym.isStaticMember) ACC_STATIC else 0, if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, + if (sym.isHidden) ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, if (sym.isVarargsMethod) ACC_VARARGS else 0, if (sym.hasFlag(Flags.SYNCHRONIZED)) JAVA_ACC_SYNCHRONIZED else 0 diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala index f622f11ffd..afb8985700 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala @@ -82,13 +82,17 @@ abstract class InteractiveTest /** Test's entry point */ def main(args: Array[String]) { + try execute() + finally shutdown() + } + + protected def execute(): Unit = { loadSources() - runTests() - shutdown() + runDefaultTests() } /** Load all sources before executing the test. */ - private def loadSources() { + protected def loadSources() { // ask the presentation compiler to track all sources. We do // not wait for the file to be entirely typed because we do want // to exercise the presentation compiler on scoped type requests. @@ -100,7 +104,7 @@ abstract class InteractiveTest } /** Run all defined `PresentationCompilerTestDef` */ - protected def runTests() { + protected def runDefaultTests() { //TODO: integrate random tests!, i.e.: if (runRandomTests) randomTests(20, sourceFiles) testActions.foreach(_.runTest()) } @@ -109,7 +113,7 @@ abstract class InteractiveTest private def randomTests(n: Int, files: Array[SourceFile]) { val tester = new Tester(n, files, settings) { override val compiler = self.compiler - override val reporter = compilerReporter + override val reporter = new reporters.StoreReporter } tester.run() } diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala index 36671555d1..4d85ab9d88 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTestSettings.scala @@ -4,10 +4,8 @@ package tests import java.io.File.pathSeparatorChar import java.io.File.separatorChar - import scala.tools.nsc.interactive.tests.core.PresentationCompilerInstance -import scala.tools.nsc.io.File - +import scala.tools.nsc.io.{File,Path} import core.Reporter import core.TestSettings @@ -46,6 +44,11 @@ trait InteractiveTestSettings extends TestSettings with PresentationCompilerInst println("error processing arguments (unprocessed: %s)".format(rest)) case _ => () } + + // Make the --sourcepath path provided in the .flags file (if any) relative to the test's base directory + if(settings.sourcepath.isSetByUser) + settings.sourcepath.value = (baseDir / Path(settings.sourcepath.value)).path + adjustPaths(settings.bootclasspath, settings.classpath, settings.javabootclasspath, settings.sourcepath) } diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index 8ccb5aa075..5c1837b3bf 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -2,12 +2,15 @@ package scala.tools.nsc package interactive package tests.core -import reporters.StoreReporter +import reporters.{Reporter => CompilerReporter} +import scala.reflect.internal.util.Position /** Trait encapsulating the creation of a presentation compiler's instance.*/ -private[tests] trait PresentationCompilerInstance { +private[tests] trait PresentationCompilerInstance extends TestSettings { protected val settings = new Settings - protected val compilerReporter = new StoreReporter + protected val compilerReporter: CompilerReporter = new InteractiveReporter { + override def compiler = PresentationCompilerInstance.this.compiler + } protected lazy val compiler: Global = { prepareSettings(settings) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 65b0ff1e6d..60e11291c1 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -645,7 +645,14 @@ abstract class ClassfileParser { // if this is a non-static inner class, remove the explicit outer parameter val newParams = innerClasses.get(currentClass) match { case Some(entry) if !isScalaRaw && !isStatic(entry.jflags) => - assert(params.head.tpe.typeSymbol == clazz.owner, params.head.tpe.typeSymbol + ": " + clazz.owner) + /* About `clazz.owner.isPackage` below: SI-5957 + * For every nested java class A$B, there are two symbols in the scala compiler. + * 1. created by SymbolLoader, because of the existence of the A$B.class file, owner: package + * 2. created by ClassfileParser of A when reading the inner classes, owner: A + * If symbol 1 gets completed (e.g. because the compiled source mentions `A$B`, not `A#B`), the + * ClassfileParser for 1 executes, and clazz.owner is the package. + */ + assert(params.head.tpe.typeSymbol == clazz.owner || clazz.owner.isPackage, params.head.tpe.typeSymbol + ": " + clazz.owner) params.tail case _ => params @@ -862,7 +869,7 @@ abstract class ClassfileParser { } else in.skip(attrLen) case tpnme.SyntheticATTR => - sym.setFlag(SYNTHETIC) + sym.setFlag(SYNTHETIC | HIDDEN) in.skip(attrLen) case tpnme.BridgeATTR => sym.setFlag(BRIDGE) diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 192cc94b90..cc5ed0f129 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -503,7 +503,7 @@ abstract class Pickler extends SubComponent { private def writeSymInfo(sym: Symbol) { writeRef(sym.name) writeRef(localizedOwner(sym)) - writeLongNat((rawFlagsToPickled(sym.flags & PickledFlags))) + writeLongNat((rawToPickledFlags(sym.flags & PickledFlags))) if (sym.hasAccessBoundary) writeRef(sym.privateWithin) writeRef(sym.info) } @@ -966,7 +966,7 @@ abstract class Pickler extends SubComponent { TREE case Modifiers(flags, privateWithin, _) => - val pflags = rawFlagsToPickled(flags) + val pflags = rawToPickledFlags(flags) writeNat((pflags >> 32).toInt) writeNat((pflags & 0xFFFFFFFF).toInt) writeRef(privateWithin) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 1276d62995..5115c49c87 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -351,7 +351,7 @@ abstract class Erasure extends AddInterfaces List()) if cast.symbol == Object_asInstanceOf && tpt.tpe.typeSymbol.isDerivedValueClass && - sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor => + sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox => Some(arg) case _ => None @@ -498,7 +498,8 @@ abstract class Erasure extends AddInterfaces ldef setType ldef.rhs.tpe case _ => val tree1 = tree.tpe match { - case ErasedValueType(clazz) => + case ErasedValueType(tref) => + val clazz = tref.sym tree match { case Unboxed(arg) if arg.tpe.typeSymbol == clazz => log("shortcircuiting unbox -> box "+arg); arg @@ -554,25 +555,26 @@ abstract class Erasure extends AddInterfaces ldef setType ldef.rhs.tpe case _ => val tree1 = pt match { - case ErasedValueType(clazz) => + case ErasedValueType(tref) => tree match { case Boxed(arg) if arg.tpe.isInstanceOf[ErasedValueType] => log("shortcircuiting box -> unbox "+arg) arg case _ => + val clazz = tref.sym log("not boxed: "+tree) val tree0 = adaptToType(tree, clazz.tpe) - cast(Apply(Select(tree0, clazz.firstParamAccessor), List()), pt) + cast(Apply(Select(tree0, clazz.derivedValueClassUnbox), List()), pt) } case _ => pt.typeSymbol match { - case UnitClass => - if (treeInfo isExprSafeToInline tree) UNIT - else BLOCK(tree, UNIT) - case x => - assert(x != ArrayClass) - // don't `setType pt` the Apply tree, as the Apply's fun won't be typechecked if the Apply tree already has a type - Apply(unboxMethod(pt.typeSymbol), tree) + case UnitClass => + if (treeInfo isExprSafeToInline tree) UNIT + else BLOCK(tree, UNIT) + case x => + assert(x != ArrayClass) + // don't `setType pt` the Apply tree, as the Apply's fun won't be typechecked if the Apply tree already has a type + Apply(unboxMethod(pt.typeSymbol), tree) } } typedPos(tree.pos)(tree1) @@ -601,7 +603,7 @@ abstract class Erasure extends AddInterfaces * @return the adapted tree */ private def adaptToType(tree: Tree, pt: Type): Tree = { - if (settings.debug.value && pt != WildcardType) + //if (settings.debug.value && pt != WildcardType) log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug if (tree.tpe <:< pt) tree @@ -629,7 +631,7 @@ abstract class Erasure extends AddInterfaces * - `x != y` for != in class Any becomes `!(x equals y)` with equals in class Object. * - x.asInstanceOf[T] becomes x.$asInstanceOf[T] * - x.isInstanceOf[T] becomes x.$isInstanceOf[T] - * - x.isInstanceOf[ErasedValueType(clazz)] becomes x.isInstanceOf[clazz.tpe] + * - x.isInstanceOf[ErasedValueType(tref)] becomes x.isInstanceOf[tref.sym.tpe] * - x.m where m is some other member of Any becomes x.m where m is a member of class Object. * - x.m where x has unboxed value type T and m is not a directly translated member of T becomes T.box(x).m * - x.m where x is a reference type and m is a directly translated member of value type T becomes x.TValue().m @@ -651,12 +653,33 @@ abstract class Erasure extends AddInterfaces atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) else */ - if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) unbox(qual1, targ.tpe) - else tree + if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) { + val noNullCheckNeeded = targ.tpe match { + case ErasedValueType(tref) => + atPhase(currentRun.erasurePhase) { + isPrimitiveValueClass(erasedValueClassArg(tref).typeSymbol) + } + case _ => + true + } + if (noNullCheckNeeded) unbox(qual1, targ.tpe) + else { + def nullConst = Literal(Constant(null)) setType NullClass.tpe + val untyped = +// util.trace("new asinstanceof test") { + gen.evalOnce(qual1, context.owner, context.unit) { qual => + If(Apply(Select(qual(), nme.eq), List(Literal(Constant(null)) setType NullClass.tpe)), + Literal(Constant(null)) setType targ.tpe, + unbox(qual(), targ.tpe)) + } +// } + typed(untyped) + } + } else tree case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_isInstanceOf => targ.tpe match { - case ErasedValueType(clazz) => targ.setType(clazz.tpe) + case ErasedValueType(tref) => targ.setType(tref.sym.tpe) case _ => } tree @@ -711,17 +734,22 @@ abstract class Erasure extends AddInterfaces val tree1 = try { tree match { case InjectDerivedValue(arg) => - val clazz = tree.symbol - val result = typed1(arg, mode, underlyingOfValueClass(clazz)) setType ErasedValueType(clazz) - log("transforming inject "+arg+":"+underlyingOfValueClass(clazz)+"/"+ErasedValueType(clazz)+" = "+result) - return result + (tree.attachments.get[TypeRefAttachment]: @unchecked) match { + case Some(itype) => + val tref = itype.tpe + val argPt = atPhase(currentRun.erasurePhase)(erasedValueClassArg(tref)) + log(s"transforming inject $arg -> $tref/$argPt") + val result = typed(arg, mode, argPt) + log(s"transformed inject $arg -> $tref/$argPt = $result:${result.tpe}") + return result setType ErasedValueType(tref) + } case _ => - super.typed1(adaptMember(tree), mode, pt) + super.typed1(adaptMember(tree), mode, pt) } } catch { case er: TypeError => - Console.println("exception when typing " + tree) + Console.println("exception when typing " + tree+"/"+tree.getClass) Console.println(er.msg + " in file " + context.owner.sourceFile) er.printStackTrace abort("unrecoverable error") @@ -731,6 +759,7 @@ abstract class Erasure extends AddInterfaces finally throw ex throw ex } + def adaptCase(cdef: CaseDef): CaseDef = { val newCdef = deriveCaseDef(cdef)(adaptToType(_, tree1.tpe)) newCdef setType newCdef.body.tpe @@ -970,8 +999,11 @@ abstract class Erasure extends AddInterfaces else tree + case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) => - InjectDerivedValue(arg) setSymbol tpt.tpe.typeSymbol +// println("inject derived: "+arg+" "+tpt.tpe) + InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol + new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef]) case Apply(fn, args) => def qualifier = fn match { case Select(qual, _) => qual @@ -1125,4 +1157,6 @@ abstract class Erasure extends AddInterfaces } } } + + private class TypeRefAttachment(val tpe: TypeRef) } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 1b8513373d..ab7bbc591b 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -92,7 +92,7 @@ abstract class ExplicitOuter extends InfoTransform else findOrElse(clazz.info.decls)(_.outerSource == clazz)(NoSymbol) } def newOuterAccessor(clazz: Symbol) = { - val accFlags = SYNTHETIC | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 ) + val accFlags = SYNTHETIC | HIDDEN | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 ) val sym = clazz.newMethod(nme.OUTER, clazz.pos, accFlags) val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType @@ -101,7 +101,7 @@ abstract class ExplicitOuter extends InfoTransform sym setInfo MethodType(Nil, restpe) } def newOuterField(clazz: Symbol) = { - val accFlags = SYNTHETIC | PARAMACCESSOR | ( if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED ) + val accFlags = SYNTHETIC | HIDDEN | PARAMACCESSOR | ( if (clazz.isEffectivelyFinal) PrivateLocal else PROTECTED ) val sym = clazz.newValue(nme.OUTER_LOCAL, clazz.pos, accFlags) sym setInfo clazz.outerClass.thisType diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index ef158a71f6..999d00520d 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -21,7 +21,8 @@ trait PostErasure extends InfoTransform with TypingTransformers { object elimErasedValueType extends TypeMap { def apply(tp: Type) = tp match { - case ErasedValueType(clazz) => erasure.underlyingOfValueClass(clazz) + case ErasedValueType(tref) => + atPhase(currentRun.erasurePhase)(erasure.erasedValueClassArg(tref)) case _ => mapOver(tp) } } @@ -38,7 +39,7 @@ trait PostErasure extends InfoTransform with TypingTransformers { acc), List()) if atPhase(currentRun.erasurePhase) { tpt.tpe.typeSymbol.isDerivedValueClass && - sel.symbol == tpt.tpe.typeSymbol.firstParamAccessor + sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox } => if (settings.debug.value) log("Removing "+tree+" -> "+arg) arg diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 49f5fca19d..ba6c43f9d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -562,7 +562,9 @@ trait ContextErrors { // SelectFromTypeTree def TypeSelectionFromVolatileTypeError(tree: Tree, qual: Tree) = { - issueNormalTypeError(tree, "illegal type selection from volatile type "+qual.tpe) + val hiBound = qual.tpe.bounds.hi + val addendum = if (hiBound =:= qual.tpe) "" else s" (with upper bound ${hiBound})" + issueNormalTypeError(tree, s"illegal type selection from volatile type ${qual.tpe}${addendum}") setError(tree) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 6428173577..9580cd5676 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -52,27 +52,6 @@ trait Namers extends MethodSynthesis { def newNamerFor(context: Context, tree: Tree): Namer = newNamer(context.makeNewScope(tree, tree.symbol)) - // In the typeCompleter (templateSig) of a case class (resp it's module), - // synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute - // their signatures, the corresponding ClassDef is needed. - // During naming, for each case class module symbol, the corresponding ClassDef - // is stored in this map. The map is cleared lazily, i.e. when the new symbol - // is created with the same name, the old one (if present) is wiped out, or the - // entry is deleted when it is used and no longer needed. - private val classOfModuleClass = perRunCaches.newWeakMap[Symbol, WeakReference[ClassDef]]() - - // Default getters of constructors are added to the companion object in the - // typeCompleter of the constructor (methodSig). To compute the signature, - // we need the ClassDef. To create and enter the symbols into the companion - // object, we need the templateNamer of that module class. - // This map is extended during naming of classes, the Namer is added in when - // it's available, i.e. in the type completer (templateSig) of the module class. - private[typechecker] val classAndNamerOfModule = perRunCaches.newMap[Symbol, (ClassDef, Namer)]() - - def resetNamer() { - classAndNamerOfModule.clear() - } - abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer => import NamerErrorGen._ @@ -618,7 +597,7 @@ trait Namers extends MethodSynthesis { MaxParametersCaseClassError(tree) val m = ensureCompanionObject(tree, caseModuleDef) - classOfModuleClass(m.moduleClass) = new WeakReference(tree) + m.moduleClass.addAttachment(new ClassForCaseCompanionAttachment(tree)) } val hasDefault = impl.body exists { case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault) @@ -626,7 +605,7 @@ trait Namers extends MethodSynthesis { } if (hasDefault) { val m = ensureCompanionObject(tree) - classAndNamerOfModule(m) = (tree, null) + m.addAttachment(new ConstructorDefaultsAttachment(tree, null)) } val owner = tree.symbol.owner if (settings.lint.value && owner.isPackageObjectClass && !mods.isImplicit) { @@ -657,7 +636,8 @@ trait Namers extends MethodSynthesis { if (sym.isLazy) sym.lazyAccessor andAlso enterIfNotThere - defaultParametersOfMethod(sym) foreach { symRef => enterIfNotThere(symRef()) } + for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment]) + defAtt.defaultGetters foreach enterIfNotThere } this.context } @@ -846,23 +826,20 @@ trait Namers extends MethodSynthesis { // add apply and unapply methods to companion objects of case classes, // unless they exist already; here, "clazz" is the module class if (clazz.isModuleClass) { - Namers.this.classOfModuleClass get clazz foreach { cdefRef => - val cdef = cdefRef() - if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer) - classOfModuleClass -= clazz + clazz.attachments.get[ClassForCaseCompanionAttachment] foreach { cma => + val cdef = cma.caseClass + assert(cdef.mods.isCase, "expected case class: "+ cdef) + addApplyUnapply(cdef, templateNamer) } } // add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because // the namer phase must traverse this copy method to create default getters for its parameters. // here, clazz is the ClassSymbol of the case class (not the module). - // @check: this seems to work only if the type completer of the class runs before the one of the - // module class: the one from the module class removes the entry from classOfModuleClass (see above). if (clazz.isClass && !clazz.hasModuleFlag) { val modClass = companionSymbolOf(clazz, context).moduleClass - Namers.this.classOfModuleClass get modClass map { cdefRef => - val cdef = cdefRef() - + modClass.attachments.get[ClassForCaseCompanionAttachment] foreach { cma => + val cdef = cma.caseClass def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol if (cdef.mods.isCase && !hasCopy(decls) && !parents.exists(p => hasCopy(p.typeSymbol.info.decls)) && @@ -874,9 +851,8 @@ trait Namers extends MethodSynthesis { // if default getters (for constructor defaults) need to be added to that module, here's the namer // to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods. val module = clazz.sourceModule - classAndNamerOfModule get module foreach { - case (cdef, _) => - classAndNamerOfModule(module) = (cdef, templateNamer) + for (cda <- module.attachments.get[ConstructorDefaultsAttachment]) { + cda.companionModuleClassNamer = templateNamer } ClassInfoType(parents, decls, clazz) } @@ -1097,13 +1073,15 @@ trait Namers extends MethodSynthesis { val module = companionSymbolOf(clazz, context) module.initialize // call type completer (typedTemplate), adds the // module's templateNamer to classAndNamerOfModule - classAndNamerOfModule get module match { - case s @ Some((cdef, nmr)) if nmr != null => - moduleNamer = s - (cdef, nmr) + module.attachments.get[ConstructorDefaultsAttachment] match { + // by martin: the null case can happen in IDE; this is really an ugly hack on top of an ugly hack but it seems to work + // later by lukas: disabled when fixing SI-5975, i think it cannot happen anymore + case Some(cda) /*if cma.companionModuleClassNamer == null*/ => + val p = (cda.classWithDefault, cda.companionModuleClassNamer) + moduleNamer = Some(p) + p case _ => return // fix #3649 (prevent crash in erroneous source code) - // nmr == null can happen in IDE; this is really an ugly hack on top[ of an ugly hack but it seems to work } } deftParams = cdef.tparams map copyUntypedInvariant @@ -1141,11 +1119,14 @@ trait Namers extends MethodSynthesis { clazz.resetFlag(INTERFACE) // there's a concrete member now val default = parentNamer.enterSyntheticSym(defaultTree) if (forInteractive && default.owner.isTerm) { - // enter into map from method symbols to default arguments. - // if compiling the same local block several times (which can happen in interactive mode) - // we might otherwise not find the default symbol, because the second time it the - // method symbol will be re-entered in the scope but the default parameter will not. - defaultParametersOfMethod(meth) += new WeakReference(default) + // save the default getters as attachments in the method symbol. if compiling the + // same local block several times (which can happen in interactive mode) we might + // otherwise not find the default symbol, because the second time it the method + // symbol will be re-entered in the scope but the default parameter will not. + val att = meth.attachments.get[DefaultsOfLocalMethodAttachment] match { + case Some(att) => att.defaultGetters += default + case None => meth.addAttachment(new DefaultsOfLocalMethodAttachment(default)) + } } } else if (baseHasDefault) { // the parameter does not have a default itself, but the diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 61443faba0..a0c1342026 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -21,8 +21,19 @@ trait NamesDefaults { self: Analyzer => import definitions._ import NamesDefaultsErrorsGen._ - val defaultParametersOfMethod = - perRunCaches.newWeakMap[Symbol, Set[WeakReference[Symbol]]]() withDefaultValue Set() + // Default getters of constructors are added to the companion object in the + // typeCompleter of the constructor (methodSig). To compute the signature, + // we need the ClassDef. To create and enter the symbols into the companion + // object, we need the templateNamer of that module class. These two are stored + // as an attachment in the companion module symbol + class ConstructorDefaultsAttachment(val classWithDefault: ClassDef, var companionModuleClassNamer: Namer) + + // To attach the default getters of local (term-owned) methods to the method symbol. + // Used in Namer.enterExistingSym: it needs to re-enter the method symbol and also + // default getters, which could not be found otherwise. + class DefaultsOfLocalMethodAttachment(val defaultGetters: mutable.Set[Symbol]) { + def this(default: Symbol) = this(mutable.Set(default)) + } case class NamedApplyInfo( qual: Option[Tree], diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 53c2d16928..b1e68e2757 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -8,7 +8,7 @@ package scala.tools.nsc package typechecker import symtab._ -import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC} +import Flags.{MUTABLE, METHOD, LABEL, SYNTHETIC, HIDDEN} import language.postfixOps import scala.tools.nsc.transform.TypingTransformers import scala.tools.nsc.transform.Transform @@ -949,7 +949,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix` // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor? - val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC + val outer = expectedTp.typeSymbol.newMethod(vpmName.outer) setInfo expectedTp.prefix setFlag SYNTHETIC | HIDDEN (Select(codegen._asInstanceOf(testedBinder, expectedTp), outer)) OBJ_EQ expectedOuter } @@ -1616,7 +1616,16 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL type Const <: AbsConst trait AbsConst { + // when we know V = C, which other equalities must hold + // in general, equality to some type implies equality to its supertypes + // (this multi-valued kind of equality is necessary for unreachability) + // note that we use subtyping as a model for implication between instanceof tests + // i.e., when S <:< T we assume x.isInstanceOf[S] implies x.isInstanceOf[T] + // unfortunately this is not true in general (see e.g. SI-6022) def implies(other: Const): Boolean + + // does V = C preclude V having value `other`? V = null is an exclusive assignment, + // but V = 1 does not preclude V = Int, or V = Any def excludes(other: Const): Boolean } @@ -2164,11 +2173,30 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL def isAny = wideTp.typeSymbol == AnyClass + // we use subtyping as a model for implication between instanceof tests + // i.e., when S <:< T we assume x.isInstanceOf[S] implies x.isInstanceOf[T] + // unfortunately this is not true in general: + // SI-6022 expects instanceOfTpImplies(ProductClass.tpe, AnyRefClass.tpe) + private def instanceOfTpImplies(tp: Type, tpImplied: Type) = { + val tpValue = tp.typeSymbol.isPrimitiveValueClass + + // pretend we're comparing to Any when we're actually comparing to AnyVal or AnyRef + // (and the subtype is respectively a value type or not a value type) + // this allows us to reuse subtyping as a model for implication between instanceOf tests + // the latter don't see a difference between AnyRef, Object or Any when comparing non-value types -- SI-6022 + val tpImpliedNormalizedToAny = + if ((tpValue && tpImplied =:= AnyValClass.tpe) || + (!tpValue && tpImplied =:= AnyRefClass.tpe)) AnyClass.tpe + else tpImplied + + tp <:< tpImpliedNormalizedToAny + } + final def implies(other: Const): Boolean = { val r = (this, other) match { case (_: ValueConst, _: ValueConst) => this == other // hashconsed - case (_: ValueConst, _: TypeConst) => tp <:< other.tp - case (_: TypeConst, _) => tp <:< other.tp + case (_: ValueConst, _: TypeConst) => instanceOfTpImplies(tp, other.tp) + case (_: TypeConst, _) => instanceOfTpImplies(tp, other.tp) case _ => false } // if(r) patmatDebug("implies : "+(this, other)) @@ -2185,12 +2213,12 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // this causes false negative for unreachability, but that's ok: // example: val X = 1; val Y = 1; (2: Int) match { case X => case Y => /* considered reachable */ } case (_: ValueConst, _: ValueConst) => this != other - case (_: ValueConst, _: TypeConst) => !((tp <:< other.tp) || (other.tp <:< wideTp)) - case (_: TypeConst, _: ValueConst) => !((other.tp <:< tp) || (tp <:< other.wideTp)) - case (_: TypeConst, _: TypeConst) => !((tp <:< other.tp) || (other.tp <:< tp)) + case (_: ValueConst, _: TypeConst) => !(instanceOfTpImplies(tp, other.tp) || instanceOfTpImplies(other.tp, wideTp)) + case (_: TypeConst, _: ValueConst) => !(instanceOfTpImplies(other.tp, tp) || instanceOfTpImplies(tp, other.wideTp)) + case (_: TypeConst, _: TypeConst) => !(instanceOfTpImplies(tp, other.tp) || instanceOfTpImplies(other.tp, tp)) case _ => false } - // if(r) patmatDebug("excludes : "+(this, this.tp, other, other.tp, (tp <:< other.tp), (tp <:< other.wideTp), (other.tp <:< tp), (other.tp <:< wideTp))) + // if(r) patmatDebug("excludes : "+(this, this.tp, other, other.tp)) // else patmatDebug("NOT excludes: "+(this, other)) r } @@ -2752,7 +2780,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL def simplify(c: Cond): Set[Cond] = c match { case AndCond(a, b) => simplify(a) ++ simplify(b) case OrCond(_, _) => Set(FalseCond) // TODO: make more precise - case NonNullCond(_) => Set(TrueCond) // not worth remembering + case NonNullCond(_) => Set(TrueCond) // not worth remembering case _ => Set(c) } val conds = simplify(cond) @@ -2768,7 +2796,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL case (priorTest, deps) => ((simplify(priorTest.cond) == nonTrivial) || // our conditions are implied by priorTest if it checks the same thing directly (nonTrivial subsetOf deps) // or if it depends on a superset of our conditions - ) && (deps subsetOf tested) // the conditions we've tested when we are here in the match satisfy the prior test, and hence what it tested + ) && (deps subsetOf tested) // the conditions we've tested when we are here in the match satisfy the prior test, and hence what it tested } foreach { case (priorTest, _) => // if so, note the dependency in both tests diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index f01e095856..5465a3b47f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -196,14 +196,14 @@ trait SyntheticMethods extends ast.TreeDSL { * (this.underlying == that.underlying */ def equalsDerivedValueClassMethod: Tree = createMethod(nme.equals_, List(AnyClass.tpe), BooleanClass.tpe) { m => - equalsCore(m, List(clazz.firstParamAccessor)) + equalsCore(m, List(clazz.derivedValueClassUnbox)) } /** The hashcode method for value classes * def hashCode(): Int = this.underlying.hashCode */ def hashCodeDerivedValueClassMethod: Tree = createMethod(nme.hashCode_, Nil, IntClass.tpe) { m => - Select(mkThisSelect(clazz.firstParamAccessor), nme.hashCode_) + Select(mkThisSelect(clazz.derivedValueClassUnbox), nme.hashCode_) } /** The _1, _2, etc. methods to implement ProductN. diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6aa93f9cec..5241974793 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -47,7 +47,6 @@ trait Typers extends Modes with Adaptations with Tags { def resetTyper() { //println("resetTyper called") resetContexts() - resetNamer() resetImplicits() transformed.clear() } @@ -1380,7 +1379,7 @@ trait Typers extends Modes with Adaptations with Tags { for (stat <- body) if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol)) unit.error(stat.pos, - if (stat.symbol hasFlag PARAMACCESSOR) "illegal parameter for value class" + if (stat.symbol != null && (stat.symbol hasFlag PARAMACCESSOR)) "illegal parameter for value class" else "this statement is not allowed in value class: " + stat) case x => unit.error(clazz.pos, "value class needs to have exactly one public val parameter") @@ -5114,7 +5113,7 @@ trait Typers extends Modes with Adaptations with Tags { case SelectFromTypeTree(qual, selector) => val qual1 = typedType(qual, mode) - if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual) + if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1) else typedSelect(qual1, selector) case CompoundTypeTree(templ) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 1b89f3db44..ad936ac39d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -23,6 +23,14 @@ trait Unapplies extends ast.TreeDSL private val unapplyParamName = nme.x_0 + + // In the typeCompleter (templateSig) of a case class (resp it's module), + // synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute + // their signatures, the corresponding ClassDef is needed. During naming (in + // `enterClassDef`), the case class ClassDef is added as an attachment to the + // moduleClass symbol of the companion module. + class ClassForCaseCompanionAttachment(val caseClass: ClassDef) + /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { assert(ufn.isMethod, ufn) diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala index 59160f87d0..8ea66979bc 100644 --- a/src/compiler/scala/tools/reflect/FastTrack.scala +++ b/src/compiler/scala/tools/reflect/FastTrack.scala @@ -15,8 +15,9 @@ trait FastTrack { import definitions._ import language.implicitConversions - private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers - private implicit def context2contextreifiers(c0: MacroContext) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers + private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers + private implicit def context2contextreifiers(c0: MacroContext): ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers + private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args) type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree] @@ -42,6 +43,7 @@ trait FastTrack { ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) } MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) } ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree } + StringContext_f bindTo { case (c, Apply(Select(Apply(_, parts), _), args)) => c.macro_StringInterpolation_f(parts, args) } registry } }
\ No newline at end of file diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala new file mode 100644 index 0000000000..a5f7928f55 --- /dev/null +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -0,0 +1,147 @@ +package scala.tools.reflect + +import scala.reflect.makro.{ReificationError, UnexpectedReificationError} +import scala.reflect.makro.runtime.Context +import scala.collection.mutable.ListBuffer +import scala.collection.mutable.Stack + +abstract class MacroImplementations { + val c: Context + + import c.universe._ + + def macro_StringInterpolation_f(parts: List[Tree], args: List[Tree]): Tree = { + // the parts all have the same position information (as the expression is generated by the compiler) + // the args have correct position information + + // the following conditions can only be violated if invoked directly + if (parts.length != args.length + 1) { + if(parts.length == 0) + c.abort(c.prefix.tree.pos, "too few parts") + else if(args.length + 1 < parts.length) + c.abort(if(args.length==0) c.enclosingPosition else args.last.pos, + "too few arguments for interpolated string") + else + c.abort(args(parts.length-1).pos, + "too many arguments for interpolated string") + } + + val stringParts = parts map { + case Literal(Constant(s: String)) => s; + case _ => throw new IllegalArgumentException("argument parts must be a list of string literals") + } + + val pi = stringParts.iterator + val bldr = new java.lang.StringBuilder + val evals = ListBuffer[ValDef]() + val ids = ListBuffer[Ident]() + val argsStack = Stack(args : _*) + + def defval(value: Tree, tpe: Type): Unit = { + val freshName = newTermName(c.fresh("arg$")) + evals += ValDef(Modifiers(), freshName, TypeTree(tpe), value) + ids += Ident(freshName) + } + + def isFlag(ch: Char): Boolean = { + ch match { + case '-' | '#' | '+' | ' ' | '0' | ',' | '(' => true + case _ => false + } + } + + def checkType(arg: Tree, variants: Type*): Option[Type] = { + variants.find(arg.tpe <:< _).orElse( + variants.find(c.inferImplicitView(arg, arg.tpe, _) != EmptyTree).orElse( + Some(variants(0)) + ) + ) + } + + def conversionType(ch: Char, arg: Tree): Option[Type] = { + ch match { + case 'b' | 'B' => + if(arg.tpe <:< NullTpe) Some(NullTpe) else Some(BooleanTpe) + case 'h' | 'H' => + Some(AnyTpe) + case 's' | 'S' => + Some(AnyTpe) + case 'c' | 'C' => + checkType(arg, CharTpe, ByteTpe, ShortTpe, IntTpe) + case 'd' | 'o' | 'x' | 'X' => + checkType(arg, IntTpe, LongTpe, ByteTpe, ShortTpe, typeOf[BigInt]) + case 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' => + checkType(arg, DoubleTpe, FloatTpe, typeOf[BigDecimal]) + case 't' | 'T' => + checkType(arg, LongTpe, typeOf[java.util.Calendar], typeOf[java.util.Date]) + case _ => None + } + } + + def copyString(first: Boolean): Unit = { + val str = StringContext.treatEscapes(pi.next()) + val strLen = str.length + val strIsEmpty = strLen == 0 + var start = 0 + var idx = 0 + + if (!first) { + val arg = argsStack.pop + if (strIsEmpty || (str charAt 0) != '%') { + bldr append "%s" + defval(arg, AnyTpe) + } else { + // PRE str is not empty and str(0) == '%' + // argument index parameter is not allowed, thus parse + // [flags][width][.precision]conversion + var pos = 1 + while(pos < strLen && isFlag(str charAt pos)) pos += 1 + while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1 + if(pos < strLen && str.charAt(pos) == '.') { pos += 1 + while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1 + } + if(pos < strLen) { + conversionType(str charAt pos, arg) match { + case Some(tpe) => defval(arg, tpe) + case None => c.error(arg.pos, "illegal conversion character") + } + } else { + // TODO: place error message on conversion string + c.error(arg.pos, "wrong conversion string") + } + } + idx = 1 + } + if (!strIsEmpty) { + val len = str.length + while (idx < len) { + if (str(idx) == '%') { + bldr append (str substring (start, idx)) append "%%" + start = idx + 1 + } + idx += 1 + } + bldr append (str substring (start, idx)) + } + } + + copyString(first = true) + while (pi.hasNext) { + copyString(first = false) + } + + val fstring = bldr.toString +// val expr = c.reify(fstring.format((ids.map(id => Expr(id).eval)) : _*)) +// https://issues.scala-lang.org/browse/SI-5824, therefore + val expr = + Apply( + Select( + Literal(Constant(fstring)), + newTermName("format")), + List(ids: _* ) + ); + + Block(evals.toList, expr) + } + +}
\ No newline at end of file diff --git a/src/library/scala/Cloneable.scala b/src/library/scala/Cloneable.scala new file mode 100644 index 0000000000..5ba76ddde5 --- /dev/null +++ b/src/library/scala/Cloneable.scala @@ -0,0 +1,14 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** + * Classes extending this trait are cloneable across platforms (Java, .NET). + */ +trait Cloneable extends java.lang.Cloneable diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index f400f18dab..f11dfb72ae 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -8,7 +8,7 @@ package scala -import collection.mutable.ArrayBuffer +import language.experimental.macros /** A class to support string interpolation. * This class supports string interpolation as outlined in Scala SIP-11. @@ -42,7 +42,7 @@ case class StringContext(parts: String*) { * @throws A `StringContext.InvalidEscapeException` if if a `parts` string contains a backslash (`\`) character * that does not start a valid escape sequence. */ - def s(args: Any*) = { + def s(args: Any*): String = { checkLengths(args: _*) val pi = parts.iterator val ai = args.iterator @@ -82,38 +82,8 @@ case class StringContext(parts: String*) { * string literally. This is achieved by replacing each such occurrence by the * format specifier `%%`. */ - def f(args: Any*) = { - checkLengths(args: _*) - val pi = parts.iterator - val bldr = new java.lang.StringBuilder - def copyString(first: Boolean): Unit = { - val str = treatEscapes(pi.next()) - val strIsEmpty = str.length == 0 - var start = 0 - var idx = 0 - if (!first) { - if (strIsEmpty || (str charAt 0) != '%') - bldr append "%s" - idx = 1 - } - if (!strIsEmpty) { - val len = str.length - while (idx < len) { - if (str(idx) == '%') { - bldr append (str substring (start, idx)) append "%%" - start = idx + 1 - } - idx += 1 - } - bldr append (str substring (start, idx)) - } - } - copyString(first = true) - while (pi.hasNext) { - copyString(first = false) - } - bldr.toString format (args: _*) - } + // The implementation is magically hardwired into `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f` + def f(args: Any*): String = macro ??? } object StringContext { diff --git a/src/library/scala/cloneable.scala b/src/library/scala/annotation/cloneable.scala index 32a1ea640d..aa45e8325f 100644 --- a/src/library/scala/cloneable.scala +++ b/src/library/scala/annotation/cloneable.scala @@ -6,11 +6,10 @@ ** |/ ** \* */ - - -package scala +package scala.annotation /** * An annotation that designates the class to which it is applied as cloneable */ +@deprecated("instead of `@cloneable class C`, use `class C extends Cloneable`", "2.10.0") class cloneable extends annotation.StaticAnnotation diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 8c603dc91b..75707b69b0 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -467,4 +467,5 @@ private[collection] trait Wrappers { } } -object Wrappers extends Wrappers +@SerialVersionUID(0 - 5857859809262781311L) +object Wrappers extends Wrappers with Serializable diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 05529761d3..2cf9985523 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -15,8 +15,7 @@ import parallel.immutable.ParHashMap /** This class implements immutable maps using a hash trie. * - * '''Note:''' the builder of a hash map returns specialized representations EmptyMap,Map1,..., Map4 - * for maps of size <= 4. + * '''Note:''' The builder of this hash map may return specialized representations for small maps. * * @tparam A the type of the keys contained in this hash map. * @tparam B the type of the values associated with the keys. diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index b956a4d838..c60fdc3bf1 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -17,8 +17,7 @@ import collection.parallel.immutable.ParHashSet /** This class implements immutable sets using a hash trie. * - * '''Note:''' the builder of a hash set returns specialized representations `EmptySet`,`Set1`,..., `Set4` - * for sets of `size <= 4`. + * '''Note:''' The builder of this hash set may return specialized representations for small sets. * * @tparam A the type of the elements contained in this hash set. * diff --git a/src/library/scala/collection/mutable/ArrayStack.scala b/src/library/scala/collection/mutable/ArrayStack.scala index 040a0e2aa7..8f834d265b 100644 --- a/src/library/scala/collection/mutable/ArrayStack.scala +++ b/src/library/scala/collection/mutable/ArrayStack.scala @@ -59,7 +59,7 @@ object ArrayStack extends SeqFactory[ArrayStack] { * @define mayNotTerminateInf * @define willNotTerminateInf */ -@cloneable @SerialVersionUID(8565219180626620510L) +@SerialVersionUID(8565219180626620510L) class ArrayStack[T] private(private var table : Array[AnyRef], private var index : Int) extends AbstractSeq[T] diff --git a/src/library/scala/collection/mutable/Buffer.scala b/src/library/scala/collection/mutable/Buffer.scala index dd225cfab9..fd5dc66292 100644 --- a/src/library/scala/collection/mutable/Buffer.scala +++ b/src/library/scala/collection/mutable/Buffer.scala @@ -28,10 +28,10 @@ import generic._ * @define Coll `Buffer` * @define coll buffer */ -@cloneable trait Buffer[A] extends Seq[A] with GenericTraversableTemplate[A, Buffer] - with BufferLike[A, Buffer[A]] { + with BufferLike[A, Buffer[A]] + with scala.Cloneable { override def companion: GenericCompanion[Buffer] = Buffer } diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala index f82a596b32..3274fe6194 100644 --- a/src/library/scala/collection/mutable/BufferLike.scala +++ b/src/library/scala/collection/mutable/BufferLike.scala @@ -58,13 +58,13 @@ import annotation.{migration, bridge} * mutates the collection in place, unlike similar but * undeprecated methods throughout the collections hierarchy. */ -@cloneable trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] extends Growable[A] with Shrinkable[A] with Scriptable[A] with Subtractable[A, This] with SeqLike[A, This] + with scala.Cloneable { self : This => // Abstract methods from Seq: diff --git a/src/library/scala/collection/mutable/Cloneable.scala b/src/library/scala/collection/mutable/Cloneable.scala index e6fbce415a..6daac3094a 100644 --- a/src/library/scala/collection/mutable/Cloneable.scala +++ b/src/library/scala/collection/mutable/Cloneable.scala @@ -17,9 +17,6 @@ package mutable * * @tparam A Type of the elements contained in the collection, covariant and with reference types as upperbound. */ -@cloneable -trait Cloneable[+A <: AnyRef] { - // !!! why doesn't this extend java.lang.Cloneable? - // because neither did @serializable, then we changed it to Serializable +trait Cloneable[+A <: AnyRef] extends scala.Cloneable { override def clone: A = super.clone().asInstanceOf[A] } diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index af55a01ed6..e37cbdc712 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -31,7 +31,6 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@cloneable class PriorityQueue[A](implicit val ord: Ordering[A]) extends AbstractIterable[A] with Iterable[A] @@ -40,6 +39,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) with Growable[A] with Builder[A, PriorityQueue[A]] with Serializable + with scala.Cloneable { import ord._ diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index 605d37aec6..2aa19d6cb0 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -30,7 +30,6 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@cloneable class Queue[A] extends MutableList[A] with GenericTraversableTemplate[A, Queue] diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index 042eac517a..db9e48d1cf 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -53,7 +53,6 @@ object Stack extends SeqFactory[Stack] { * @define mayNotTerminateInf * @define willNotTerminateInf */ -@cloneable class Stack[A] private (var elems: List[A]) extends AbstractSeq[A] with Seq[A] diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 82498f9b63..d4f1c2f39f 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -72,6 +72,10 @@ import language.implicitConversions * very fast operation which simply creates wrappers around the receiver collection. * This can be repeated recursively. * + * Tasks are scheduled for execution through a + * [[scala.collection.parallel.TaskSupport]] object, which can be changed + * through the `tasksupport` setter of the collection. + * * Method `newCombiner` produces a new combiner. Combiners are an extension of builders. * They provide a method `combine` which combines two combiners and returns a combiner * containing elements of both combiners. @@ -165,6 +169,11 @@ self: ParIterableLike[T, Repr, Sequential] => _tasksupport = defaultTaskSupport } + /** The task support object which is responsible for scheduling and + * load-balancing tasks to processors. + * + * @see [[scala.collection.parallel.TaskSupport]] + */ def tasksupport = { val ts = _tasksupport if (ts eq null) { @@ -173,6 +182,24 @@ self: ParIterableLike[T, Repr, Sequential] => } else ts } + /** Changes the task support object which is responsible for scheduling and + * load-balancing tasks to processors. + * + * A task support object can be changed in a parallel collection after it + * has been created, but only during a quiescent period, i.e. while there + * are no concurrent invocations to parallel collection methods. + * + * Here is a way to change the task support of a parallel collection: + * + * {{{ + * import scala.collection.parallel._ + * val pc = mutable.ParArray(1, 2, 3) + * pc.tasksupport = new ForkJoinTaskSupport( + * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * }}} + * + * @see [[scala.collection.parallel.TaskSupport]] + */ def tasksupport_=(ts: TaskSupport) = _tasksupport = ts def seq: Sequential diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala index 3d27f619bb..b2ff5c9e44 100644 --- a/src/library/scala/collection/parallel/TaskSupport.scala +++ b/src/library/scala/collection/parallel/TaskSupport.scala @@ -19,34 +19,71 @@ import scala.concurrent.ExecutionContext /** A trait implementing the scheduling of * a parallel collection operation. + * + * Parallel collections are modular in the way operations are scheduled. Each + * parallel collection is parametrized with a task support object which is + * responsible for scheduling and load-balancing tasks to processors. * - * Task support objects handle how a task is split and - * distributed across processors. A task support object can be - * changed in a parallel collection after it has been created, - * but only during a quiescent period, i.e. while there are no + * A task support object can be changed in a parallel collection after it has + * been created, but only during a quiescent period, i.e. while there are no * concurrent invocations to parallel collection methods. + * + * There are currently a few task support implementations available for + * parallel collections. The [[scala.collection.parallel.ForkJoinTaskSupport]] + * uses a fork-join pool + * internally and is used by default on JVM 1.6 or greater. The less efficient + * [[scala.collection.parallel.ThreadPoolTaskSupport]] is a fallback for JVM + * 1.5 and JVMs that do not support the fork join pools. The + * [[scala.collection.parallel.ExecutionContextTaskSupport]] uses the + * default execution context implementation found in scala.concurrent, and it + * reuses the thread pool used in scala.concurrent (this is either a fork join + * pool or a thread pool executor, depending on the JVM version). The + * execution context task support is set to each parallel collection by + * default, so parallel collections reuse the same fork-join pool as the + * future API. + * + * Here is a way to change the task support of a parallel collection: + * + * {{{ + * import scala.collection.parallel._ + * val pc = mutable.ParArray(1, 2, 3) + * pc.tasksupport = new ForkJoinTaskSupport( + * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * }}} + * + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/configuration.html Configuring Parallel Collections]] section + * on the parallel collection's guide for more information. */ trait TaskSupport extends Tasks -/** A task support that uses a fork join pool to schedule tasks */ +/** A task support that uses a fork join pool to schedule tasks. + * + * @see [[scala.collection.parallel.TaskSupport]] for more information. + */ class ForkJoinTaskSupport(val environment: ForkJoinPool = ForkJoinTasks.defaultForkJoinPool) extends TaskSupport with AdaptiveWorkStealingForkJoinTasks - -/** A task support that uses a thread pool executor to schedule tasks */ +/** A task support that uses a thread pool executor to schedule tasks. + * + * @see [[scala.collection.parallel.TaskSupport]] for more information. + */ class ThreadPoolTaskSupport(val environment: ThreadPoolExecutor = ThreadPoolTasks.defaultThreadPool) extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks /** A task support that uses an execution context to schedule tasks. * - * It can be used with the default execution context implementation in the `scala.concurrent` package. - * It internally forwards the call to either a forkjoin based task support or a thread pool executor one, - * depending on what the execution context uses. + * It can be used with the default execution context implementation in the + * `scala.concurrent` package. It internally forwards the call to either a + * forkjoin based task support or a thread pool executor one, depending on + * what the execution context uses. * - * By default, parallel collections are parametrized with this task support object, so parallel collections - * share the same execution context backend as the rest of the `scala.concurrent` package. + * By default, parallel collections are parametrized with this task support + * object, so parallel collections share the same execution context backend + * as the rest of the `scala.concurrent` package. + * + * @see [[scala.collection.parallel.TaskSupport]] for more information. */ class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.ExecutionContext.global) extends TaskSupport with ExecutionContextTasks diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index 5f90c32e22..a41cdedfa9 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -37,6 +37,9 @@ package object scala { @deprecated("instead of `@serializable class C`, use `class C extends Serializable`", "2.9.0") type serializable = annotation.serializable + @deprecated("instead of `@cloneable class C`, use `class C extends Cloneable`", "2.10.0") + type cloneable = annotation.cloneable + type TraversableOnce[+A] = scala.collection.TraversableOnce[A] type Traversable[+A] = scala.collection.Traversable[A] diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 0b592be454..cd243b9df0 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -368,6 +368,7 @@ trait Definitions extends api.StandardDefinitions { lazy val SerializableClass = requiredClass[scala.Serializable] lazy val JavaSerializableClass = requiredClass[java.io.Serializable] modifyInfo fixupAsAnyTrait lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait + lazy val CloneableClass = requiredClass[scala.Cloneable] lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable] lazy val JavaNumberClass = requiredClass[java.lang.Number] lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote] @@ -496,6 +497,9 @@ trait Definitions extends api.StandardDefinitions { def MacroInternal_materializeAbsTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeAbsTypeTag) def MacroInternal_materializeTypeTag = getMemberMethod(MacroInternalPackage, nme.materializeTypeTag) + lazy val StringContextClass = requiredClass[scala.StringContext] + def StringContext_f = getMemberMethod(StringContextClass, nme.f) + lazy val ScalaSignatureAnnotation = requiredClass[scala.reflect.ScalaSignature] lazy val ScalaLongSignatureAnnotation = requiredClass[scala.reflect.ScalaLongSignature] @@ -900,7 +904,7 @@ trait Definitions extends api.StandardDefinitions { lazy val BeanPropertyAttr = requiredClass[scala.beans.BeanProperty] lazy val BooleanBeanPropertyAttr = requiredClass[scala.beans.BooleanBeanProperty] - lazy val CloneableAttr = requiredClass[scala.cloneable] + lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] lazy val NativeAttr = requiredClass[scala.native] diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 37e5a23819..55fa00dd4d 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -135,7 +135,7 @@ class Flags extends ModifierFlags { final val CAPTURED = 1 << 16 // variable is accessed from nested function. Set by LambdaLift. final val LABEL = 1 << 17 // method symbol is a label. Set by TailCall final val INCONSTRUCTOR = 1 << 17 // class symbol is defined in this/superclass constructor. - final val SYNTHETIC = 1 << 21 // symbol is compiler-generated + final val SYNTHETIC = 1 << 21 // symbol is compiler-generated (compare with HIDDEN) final val STABLE = 1 << 22 // functions that are assumed to be stable // (typically, access methods for valdefs) // or classes that do not contain abstract types. @@ -165,6 +165,8 @@ class Flags extends ModifierFlags { // A Java method's type is ``cooked'' by transforming raw types to existentials final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED + final val HIDDEN = 1L << 46 // symbol should be ignored when typechecking; will be marked ACC_SYNTHETIC in bytecode + // ------- shift definitions ------------------------------------------------------- final val InitialFlags = 0x0001FFFFFFFFFFFFL // flags that are enabled from phase 1. @@ -174,6 +176,11 @@ class Flags extends ModifierFlags { final val AntiShift = 56L // Flags which sketchily share the same slot + // 16: BYNAMEPARAM/M CAPTURED COVARIANT/M + // 17: CONTRAVARIANT/M INCONSTRUCTOR LABEL + // 25: DEFAULTPARAM/M TRAIT/M + // 35: EXISTENTIAL MIXEDIN + // 37: IMPLCLASS PRESUPER/M val OverloadedFlagsMask = 0L | BYNAMEPARAM | CONTRAVARIANT | DEFAULTPARAM | EXISTENTIAL | IMPLCLASS // ------- late flags (set by a transformer phase) --------------------------------- @@ -211,7 +218,7 @@ class Flags extends ModifierFlags { /** To be a little clearer to people who aren't habitual bit twiddlers. */ final val AllFlags = -1L - + /** These flags can be set when class or module symbol is first created. * They are the only flags to survive a call to resetFlags(). */ @@ -279,6 +286,16 @@ class Flags extends ModifierFlags { /** Module flags inherited by their module-class */ final val ModuleToClassFlags = AccessFlags | TopLevelCreationFlags | CASE | SYNTHETIC + /** These flags are not pickled */ + final val FlagsNotPickled = IS_ERROR | OVERLOADED | LIFTED | TRANS_FLAG | LOCKED | TRIEDCOOKING + + // A precaution against future additions to FlagsNotPickled turning out + // to be overloaded flags thus not-pickling more than intended. + assert((OverloadedFlagsMask & FlagsNotPickled) == 0, flagsToString(OverloadedFlagsMask & FlagsNotPickled)) + + /** These flags are pickled */ + final val PickledFlags = InitialFlags & ~FlagsNotPickled + def getterFlags(fieldFlags: Long): Long = ACCESSOR + ( if ((fieldFlags & MUTABLE) != 0) fieldFlags & ~MUTABLE & ~PRESUPER else fieldFlags & ~PRESUPER | STABLE @@ -307,47 +324,45 @@ class Flags extends ModifierFlags { private final val PKL_MASK = 0x00000FFF - final val PickledFlags = 0xFFFFFFFFL - - private def rawPickledCorrespondence = Array( - (IMPLICIT, IMPLICIT_PKL), - (FINAL, FINAL_PKL), + /** Pickler correspondence, ordered roughly by frequency of occurrence */ + private def rawPickledCorrespondence = Array[(Long, Long)]( + (METHOD, METHOD_PKL), (PRIVATE, PRIVATE_PKL), + (FINAL, FINAL_PKL), (PROTECTED, PROTECTED_PKL), - (SEALED, SEALED_PKL), - (OVERRIDE, OVERRIDE_PKL), (CASE, CASE_PKL), - (ABSTRACT, ABSTRACT_PKL), (DEFERRED, DEFERRED_PKL), - (METHOD, METHOD_PKL), (MODULE, MODULE_PKL), - (INTERFACE, INTERFACE_PKL) + (OVERRIDE, OVERRIDE_PKL), + (INTERFACE, INTERFACE_PKL), + (IMPLICIT, IMPLICIT_PKL), + (SEALED, SEALED_PKL), + (ABSTRACT, ABSTRACT_PKL) ) - private val rawFlags: Array[Int] = rawPickledCorrespondence map (_._1) - private val pickledFlags: Array[Int] = rawPickledCorrespondence map (_._2) - - private def r2p(flags: Int): Int = { - var result = 0 - var i = 0 - while (i < rawFlags.length) { - if ((flags & rawFlags(i)) != 0) - result |= pickledFlags(i) - - i += 1 - } - result - } - private def p2r(flags: Int): Int = { - var result = 0 - var i = 0 - while (i < rawFlags.length) { - if ((flags & pickledFlags(i)) != 0) - result |= rawFlags(i) - - i += 1 + + private val mappedRawFlags = rawPickledCorrespondence map (_._1) + private val mappedPickledFlags = rawPickledCorrespondence map (_._2) + + private class MapFlags(from: Array[Long], to: Array[Long]) extends (Long => Long) { + val fromSet = (0L /: from) (_ | _) + + def apply(flags: Long): Long = { + var result = flags & ~fromSet + var tobeMapped = flags & fromSet + var i = 0 + while (tobeMapped != 0) { + if ((tobeMapped & from(i)) != 0) { + result |= to(i) + tobeMapped &= ~from(i) + } + i += 1 + } + result } - result } + + val rawToPickledFlags: Long => Long = new MapFlags(mappedRawFlags, mappedPickledFlags) + val pickledToRawFlags: Long => Long = new MapFlags(mappedPickledFlags, mappedRawFlags) // ------ displaying flags -------------------------------------------------------- @@ -462,18 +477,12 @@ class Flags extends ModifierFlags { } } - def rawFlagsToPickled(flags: Long): Long = - (flags & ~PKL_MASK) | r2p(flags.toInt & PKL_MASK) - - def pickledToRawFlags(pflags: Long): Long = - (pflags & ~PKL_MASK) | p2r(pflags.toInt & PKL_MASK) - // List of the raw flags, in pickled order final val MaxBitPosition = 62 final val pickledListOrder: List[Long] = { val all = 0 to MaxBitPosition map (1L << _) - val front = rawFlags map (_.toLong) + val front = mappedRawFlags map (_.toLong) front.toList ++ (all filterNot (front contains _)) } diff --git a/src/reflect/scala/reflect/internal/HasFlags.scala b/src/reflect/scala/reflect/internal/HasFlags.scala index c7c0882209..7ead9d6a1b 100644 --- a/src/reflect/scala/reflect/internal/HasFlags.scala +++ b/src/reflect/scala/reflect/internal/HasFlags.scala @@ -92,6 +92,7 @@ trait HasFlags { def isCaseAccessor = hasFlag(CASEACCESSOR) def isDeferred = hasFlag(DEFERRED) def isFinal = hasFlag(FINAL) + def isHidden = hasFlag(HIDDEN) def isImplicit = hasFlag(IMPLICIT) def isInterface = hasFlag(INTERFACE) def isJavaDefined = hasFlag(JAVA) diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 4ea9b27da9..60b3a6f436 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -4,9 +4,24 @@ package internal trait StdAttachments { self: SymbolTable => + /** + * Common code between reflect-internal Symbol and Tree related to Attachments. + */ + trait Attachable { + protected var rawatt: base.Attachments { type Pos = Position } = NoPosition + def attachments = rawatt + def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this } + def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this } + + // cannot be final due to SynchronizedSymbols + def pos: Position = rawatt.pos + def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos) + def setPos(newpos: Position): this.type = { pos = newpos; this } + } + case object BackquotedIdentifierAttachment case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree]) case class MacroExpansionAttachment(original: Tree) -}
\ No newline at end of file +} diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 72a99589d5..22b0908cab 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -662,6 +662,7 @@ trait StdNames { val eval: NameType = "eval" val ex: NameType = "ex" val experimental: NameType = "experimental" + val f: NameType = "f" val false_ : NameType = "false" val filter: NameType = "filter" val finalize_ : NameType = if (forMSIL) "Finalize" else "finalize" diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 3cb9f6ff37..04fa01c6f3 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -10,6 +10,7 @@ import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import util.Statistics import Flags._ +import base.Attachments trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ @@ -363,7 +364,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name) extends SymbolContextApiImpl with HasFlags - with Annotatable[Symbol] { + with Annotatable[Symbol] + with Attachable { type AccessBoundaryType = Symbol type AnnotationType = AnnotationInfo @@ -385,7 +387,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def rawowner = _rawowner def rawflags = _rawflags - private var rawpos = initPos + rawatt = initPos val id = nextId() // identity displayed when -uniqid //assert(id != 3390, initName) @@ -398,8 +400,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => def validTo = _validTo def validTo_=(x: Period) { _validTo = x} - def pos = rawpos - def setPos(pos: Position): this.type = { this.rawpos = pos; this } def setName(name: Name): this.type = { this.name = asNameType(name) ; this } // Update the surrounding scopes @@ -957,13 +957,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Is this symbol an accessor method for outer? */ final def isOuterAccessor = { - hasFlag(STABLE | SYNTHETIC) && + hasFlag(STABLE | HIDDEN) && originalName == nme.OUTER } /** Is this symbol an accessor method for outer? */ final def isOuterField = { - hasFlag(SYNTHETIC) && + hasFlag(HIDDEN) && originalName == nme.OUTER_LOCAL } @@ -1821,6 +1821,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => setInfo (this.info cloneInfo clone) setAnnotations this.annotations ) + this.attachments.all.foreach(clone.addAttachment) if (clone.thisSym != clone) clone.typeOfThis = (clone.typeOfThis cloneInfo clone) @@ -2238,10 +2239,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => base.info.decl(sname) filter (_.hasAccessorFlag) } - /** Return the accessor method of the first parameter of this class. + /** If this is a derived value class, return its unbox method * or NoSymbol if it does not exist. */ - def firstParamAccessor: Symbol = NoSymbol + def derivedValueClassUnbox: Symbol = NoSymbol /** The case module corresponding to this case class * @pre case class is a member of some other class or package @@ -3145,8 +3146,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => clone } - override def firstParamAccessor = - info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse NoSymbol + override def derivedValueClassUnbox = + (info.decl(nme.unbox)) orElse + (info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse + NoSymbol) private[this] var childSet: Set[Symbol] = Set() override def children = childSet diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index dd13dd4c4c..e92d644f4a 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -15,20 +15,13 @@ trait Trees extends api.Trees { self: SymbolTable => private[scala] var nodeCount = 0 - abstract class Tree extends TreeContextApiImpl with Product { + abstract class Tree extends TreeContextApiImpl with Attachable with Product { val id = nodeCount // TODO: add to attachment? nodeCount += 1 Statistics.incCounter(TreesStats.nodeByType, getClass) - @inline final def pos: Position = rawatt.pos - def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos) - def setPos(newpos: Position): this.type = { pos = newpos; this } - - private var rawatt: Attachments { type Pos = Position } = NoPosition - def attachments = rawatt - def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this } - def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this } + @inline final override def pos: Position = rawatt.pos private[this] var rawtpe: Type = _ @inline final def tpe = rawtpe diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 56cc265e48..f3dd1f03ad 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -66,7 +66,7 @@ import util.Statistics // inst is the instantiation and constr is a list of bounds. case DeBruijnIndex(level, index) // for dependent method types: a type referring to a method parameter. - case ErasedValueType(tp) + case ErasedValueType(clazz, underlying) // only used during erasure of derived value classes. */ @@ -693,20 +693,21 @@ trait Types extends api.Types { self: SymbolTable => * = Int */ def asSeenFrom(pre: Type, clazz: Symbol): Type = { - if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this - else { -// scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") { - Statistics.incCounter(asSeenFromCount) - val start = Statistics.pushTimer(typeOpsStack, asSeenFromNanos) - val m = new AsSeenFromMap(pre.normalize, clazz) - val tp = m apply this - val tp1 = existentialAbstraction(m.capturedParams, tp) - val result: Type = + TypesStats.timedTypeOp(asSeenFromNanos) { + val trivial = ( + this.isTrivial + || phase.erasedTypes && pre.typeSymbol != ArrayClass + || pre.normalize.isTrivial && !isPossiblePrefix(clazz) + ) + if (trivial) this + else { + val m = new AsSeenFromMap(pre.normalize, clazz) + val tp = m(this) + val tp1 = existentialAbstraction(m.capturedParams, tp) + if (m.capturedSkolems.isEmpty) tp1 else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1) - - Statistics.popTimer(typeOpsStack, start) - result + } } } @@ -1289,7 +1290,7 @@ trait Types extends api.Types { self: SymbolTable => /** A class for this-types of the form <sym>.this.type */ abstract case class ThisType(sym: Symbol) extends SingletonType with ThisTypeApi { - assert(sym.isClass) + assert(sym.isClass, sym) //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym) override def isTrivial: Boolean = sym.isPackageClass override def isNotNull = true @@ -2207,6 +2208,8 @@ trait Types extends api.Types { self: SymbolTable => * @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty */ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type with TypeRefApi { + override val isTrivial: Boolean = !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) + private[reflect] var parentsCache: List[Type] = _ private[reflect] var parentsPeriod = NoPeriod private[reflect] var baseTypeSeqCache: BaseTypeSeq = _ @@ -2269,9 +2272,6 @@ trait Types extends api.Types { self: SymbolTable => override def typeSymbol = sym override def typeSymbolDirect = sym - override lazy val isTrivial: Boolean = - !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) - override def isNotNull = sym.isModuleClass || sym == NothingClass || (sym isNonBottomSubClass NotNullClass) || super.isNotNull @@ -2435,11 +2435,15 @@ trait Types extends api.Types { self: SymbolTable => */ case class MethodType(override val params: List[Symbol], override val resultType: Type) extends Type with MethodTypeApi { - override def isTrivial: Boolean = isTrivial0 && (resultType eq resultType.withoutAnnotations) - private lazy val isTrivial0 = - resultType.isTrivial && params.forall{p => p.tpe.isTrivial && ( - !(params.exists(_.tpe.contains(p)) || resultType.contains(p))) - } + + override lazy val isTrivial: Boolean = + isTrivialResult && (params forall isTrivialParam) + + private def isTrivialResult = + resultType.isTrivial && (resultType eq resultType.withoutAnnotations) + + private def isTrivialParam(p: Symbol) = + p.tpe.isTrivial && !(params.exists(_.tpe contains p) || (resultType contains p)) def isImplicit = params.nonEmpty && params.head.isImplicit def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized? @@ -3211,8 +3215,7 @@ trait Types extends api.Types { self: SymbolTable => override protected def rewrap(tp: Type) = copy(underlying = tp) - override def isTrivial: Boolean = isTrivial0 - private lazy val isTrivial0 = underlying.isTrivial && annotations.forall(_.isTrivial) + override def isTrivial: Boolean = underlying.isTrivial && annotations.forall(_.isTrivial) override def safeToString = annotations.mkString(underlying + " @", " @", "") @@ -3305,16 +3308,21 @@ trait Types extends api.Types { self: SymbolTable => } } - abstract case class ErasedValueType(sym: Symbol) extends Type { - override def safeToString = sym.name+"$unboxed" + /** A temporary type representing the reasure of a user-defined value type. + * Created during phase reasure, elimintaed again in posterasure. + * @param sym The value class symbol + * @param underlying The underlying type before erasure + */ + abstract case class ErasedValueType(original: TypeRef) extends Type { + override def safeToString = "ErasedValueType("+original+")" } - final class UniqueErasedValueType(sym: Symbol) extends ErasedValueType(sym) with UniqueType + final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original) with UniqueType object ErasedValueType { - def apply(sym: Symbol): Type = { - assert(sym ne NoSymbol, "ErasedValueType cannot be NoSymbol") - unique(new UniqueErasedValueType(sym)) + def apply(original: TypeRef): Type = { + assert(original.sym ne NoSymbol, "ErasedValueType over NoSymbol") + unique(new UniqueErasedValueType(original)) } } @@ -4250,55 +4258,58 @@ trait Types extends api.Types { self: SymbolTable => def singletonBounds(hi: Type) = TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe))) + /** Might the given symbol be important when calculating the prefix + * of a type? When tp.asSeenFrom(pre, clazz) is called on `tp`, + * the result will be `tp` unchanged if `pre` is trivial and `clazz` + * is a symbol such that isPossiblePrefix(clazz) == false. + */ + def isPossiblePrefix(clazz: Symbol) = clazz.isClass && !clazz.isPackageClass + /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints { var capturedSkolems: List[Symbol] = List() var capturedParams: List[Symbol] = List() - var capturedPre = emptySymMap + @inline private def skipPrefixOf(pre: Type, clazz: Symbol) = ( + (pre eq NoType) || (pre eq NoPrefix) || !isPossiblePrefix(clazz) + ) override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object annotationArgRewriter extends TypeMapTransformer { + private def canRewriteThis(sym: Symbol) = ( + (sym isNonBottomSubClass clazz) + && (pre.widen.typeSymbol isNonBottomSubClass sym) + && (pre.isStable || giveup()) + ) + // what symbol should really be used? + private def newTermSym() = { + val p = pre.typeSymbol + p.owner.newValue(p.name.toTermName, p.pos) setInfo pre + } /** Rewrite `This` trees in annotation argument trees */ - def rewriteThis(tree: Tree): Tree = - tree match { - case This(_) - if (tree.symbol isNonBottomSubClass clazz) && - (pre.widen.typeSymbol isNonBottomSubClass tree.symbol) => - if (pre.isStable) { // XXX why is this in this method? pull it out and guard the call `annotationArgRewriter.transform(tree)`? - val termSym = ( - pre.typeSymbol.owner.newValue(pre.typeSymbol.name.toTermName, pre.typeSymbol.pos) // what symbol should really be used? - setInfo pre - ) - gen.mkAttributedQualifier(pre, termSym) - } else - giveup() - - case tree => tree - } - - override def transform(tree: Tree): Tree = { - val tree1 = rewriteThis(super.transform(tree)) - tree1 + override def transform(tree: Tree): Tree = super.transform(tree) match { + case This(_) if canRewriteThis(tree.symbol) => gen.mkAttributedQualifier(pre, newTermSym()) + case tree => tree } } - annotationArgRewriter.transform(tree) } - def stabilize(pre: Type, clazz: Symbol): Type = - capturedPre.getOrElse(clazz, { - val qvar = clazz freshExistential ".type" setInfo singletonBounds(pre) - capturedPre += (clazz -> qvar) - capturedParams = qvar :: capturedParams - qvar - }).tpe + def stabilize(pre: Type, clazz: Symbol): Type = { + capturedParams find (_.owner == clazz) match { + case Some(qvar) => qvar.tpe + case _ => + val qvar = clazz freshExistential nme.SINGLETON_SUFFIX setInfo singletonBounds(pre) + capturedParams ::= qvar + qvar.tpe + } + } def apply(tp: Type): Type = - if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp + if (skipPrefixOf(pre, clazz)) tp else tp match { case ThisType(sym) => def toPrefix(pre: Type, clazz: Symbol): Type = - if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp + if (skipPrefixOf(pre, clazz)) tp else if ((sym isNonBottomSubClass clazz) && (pre.widen.typeSymbol isNonBottomSubClass sym)) { val pre1 = pre match { @@ -4334,7 +4345,7 @@ trait Types extends api.Types { self: SymbolTable => // (skolems also aren't affected: they are ruled out by the isTypeParameter check) case TypeRef(prefix, sym, args) if (sym.isTypeParameter && sym.owner.isClass) => def toInstance(pre: Type, clazz: Symbol): Type = - if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) mapOver(tp) + if (skipPrefixOf(pre, clazz)) mapOver(tp) //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary else { def throwError = abort("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen) @@ -4604,7 +4615,7 @@ trait Types extends api.Types { self: SymbolTable => if (existentials(pid) eq null) { val param = params(pid) existentials(pid) = ( - param.owner.newExistential(newTypeName(param.name + ".type"), param.pos, param.flags) + param.owner.newExistential(param.name.toTypeName append nme.SINGLETON_SUFFIX, param.pos, param.flags) setInfo singletonBounds(actuals(pid)) ) } @@ -6910,4 +6921,10 @@ object TypesStats { val typerefBaseTypeSeqCount = Statistics.newSubCounter(" of which for typerefs", baseTypeSeqCount) val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount) val typeOpsStack = Statistics.newTimerStack() + + @inline final def timedTypeOp[T](c: Statistics.StackableTimer)(op: => T): T = { + val start = Statistics.pushTimer(typeOpsStack, c) + try op + finally Statistics.popTimer(typeOpsStack, start) + } } diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 4d8e932862..4411b79b97 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -373,12 +373,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { NullaryMethodType(restpe) case EXISTENTIALtpe => val restpe = readTypeRef() - // @PP: Where is the flag setting supposed to happen? I infer - // from the lack of flag setting in the rest of the unpickler - // that it isn't right here. See #4757 for the immediate - // motivation to fix it. - val tparams = until(end, readSymbolRef) map (_ setFlag EXISTENTIAL) - newExistentialType(tparams, restpe) + newExistentialType(until(end, readSymbolRef), restpe) case ANNOTATEDtpe => var typeRef = readNat() diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index 5beec70d62..368d55a59c 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -2,7 +2,7 @@ package scala.reflect package internal package transform -import Flags.PARAMACCESSOR +import Flags.{PARAMACCESSOR, METHOD} trait Erasure { @@ -72,8 +72,37 @@ trait Erasure { if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? } + def unboxDerivedValueClassMethod(clazz: Symbol): Symbol = + (clazz.info.decl(nme.unbox)) orElse + (clazz.info.decls.find(_ hasAllFlags PARAMACCESSOR | METHOD) getOrElse + NoSymbol) + def underlyingOfValueClass(clazz: Symbol): Type = - clazz.firstParamAccessor.tpe.resultType + clazz.derivedValueClassUnbox.tpe.resultType + + /** The type of the argument of a value class reference after erasure + * This method needs to be called at a phase no later than erasurephase + */ + def erasedValueClassArg(tref: TypeRef): Type = { + assert(!phase.erasedTypes) + val clazz = tref.sym + if (valueClassIsParametric(clazz)) { + val underlying = tref.memberType(clazz.derivedValueClassUnbox).resultType + boxingErasure(underlying) + } else { + scalaErasure(underlyingOfValueClass(clazz)) + } + } + + /** Does this vakue class have an underlying type that's a type parameter of + * the class itself? + * This method needs to be called at a phase no later than erasurephase + */ + def valueClassIsParametric(clazz: Symbol): Boolean = { + assert(!phase.erasedTypes) + clazz.typeParams contains + clazz.derivedValueClassUnbox.tpe.resultType.normalize.typeSymbol + } abstract class ErasureMap extends TypeMap { private lazy val ObjectArray = arrayType(ObjectClass.tpe) @@ -84,15 +113,14 @@ trait Erasure { def eraseNormalClassRef(pre: Type, clazz: Symbol): Type = typeRef(apply(rebindInnerClass(pre, clazz)), clazz, List()) // #2585 - protected def eraseDerivedValueClassRef(clazz: Symbol): Type = - scalaErasure(underlyingOfValueClass(clazz)) + protected def eraseDerivedValueClassRef(tref: TypeRef): Type = erasedValueClassArg(tref) def apply(tp: Type): Type = tp match { case ConstantType(_) => tp case st: SubType => apply(st.supertype) - case TypeRef(pre, sym, args) => + case tref @ TypeRef(pre, sym, args) => if (sym == ArrayClass) if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe else if (args.head.typeSymbol.isBottomClass) ObjectArray @@ -100,7 +128,7 @@ trait Erasure { else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) ErasedObject else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) else if (sym.isRefinementClass) apply(mergeParents(tp.parents)) - else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(sym) + else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref) else if (sym.isClass) eraseNormalClassRef(pre, sym) else apply(sym.info) // alias type or abstract type case PolyType(tparams, restpe) => @@ -236,7 +264,8 @@ trait Erasure { * are then later converted to the underlying parameter type in phase posterasure. */ object specialScalaErasure extends ScalaErasureMap { - override def eraseDerivedValueClassRef(clazz: Symbol): Type = ErasedValueType(clazz) + override def eraseDerivedValueClassRef(tref: TypeRef): Type = + ErasedValueType(tref) } object javaErasure extends JavaErasureMap @@ -251,6 +280,14 @@ trait Erasure { } } + object boxingErasure extends ScalaErasureMap { + override def eraseNormalClassRef(pre: Type, clazz: Symbol) = + if (isPrimitiveValueClass(clazz)) boxedClass(clazz).tpe + else super.eraseNormalClassRef(pre, clazz) + override def eraseDerivedValueClassRef(tref: TypeRef) = + super.eraseNormalClassRef(tref.pre, tref.sym) + } + /** The intersection dominator (SLS 3.7) of a list of types is computed as follows. * * - If the list contains one or more occurrences of scala.Array with diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index 3a31c2858b..e503d812e6 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -169,7 +169,7 @@ quant) nanos = nanos0 + System.nanoTime() - start timings += 1 } - protected def show(ns: Long) = s"${ns/1000}ms" + protected def show(ns: Long) = s"${ns/1000000}ms" override def toString = s"$timings spans, ${show(nanos)}" } diff --git a/src/reflect/scala/reflect/makro/Universe.scala b/src/reflect/scala/reflect/makro/Universe.scala index 98046be555..a676f7f1de 100644 --- a/src/reflect/scala/reflect/makro/Universe.scala +++ b/src/reflect/scala/reflect/makro/Universe.scala @@ -5,13 +5,24 @@ abstract class Universe extends scala.reflect.api.Universe { val treeBuild: TreeBuilder { val global: Universe.this.type } + trait AttachableApi { + /** ... */ + def attachments: base.Attachments { type Pos = Position } + + /** ... */ + def addAttachment(attachment: Any): AttachableApi.this.type + + /** ... */ + def removeAttachment[T: ClassTag]: AttachableApi.this.type + } + // Symbol extensions --------------------------------------------------------------- override type Symbol >: Null <: SymbolContextApi /** The extended API of symbols that's supported in macro context universes */ - trait SymbolContextApi extends SymbolApi { this: Symbol => + trait SymbolContextApi extends SymbolApi with AttachableApi { this: Symbol => // [Eugene++ to Martin] should we also add mutability methods here (similarly to what's done below for trees)? // I'm talking about `setAnnotations` and friends @@ -23,7 +34,7 @@ abstract class Universe extends scala.reflect.api.Universe { /** The extended API of trees that's supported in macro context universes */ - trait TreeContextApi extends TreeApi { this: Tree => + trait TreeContextApi extends TreeApi with AttachableApi { this: Tree => /** ... */ def pos_=(pos: Position): Unit @@ -62,15 +73,6 @@ abstract class Universe extends scala.reflect.api.Universe { /** ... */ def setSymbol(sym: Symbol): this.type - - /** ... */ - def attachments: base.Attachments { type Pos = Position } - - /** ... */ - def addAttachment(attachment: Any): this.type - - /** ... */ - def removeAttachment[T: ClassTag]: this.type } override type SymTree >: Null <: Tree with SymTreeContextApi diff --git a/test/files/buildmanager/t2651_3/t2651_3.check b/test/files/buildmanager/t2651_3/t2651_3.check index d4bac196e9..2a60e3d806 100644 --- a/test/files/buildmanager/t2651_3/t2651_3.check +++ b/test/files/buildmanager/t2651_3/t2651_3.check @@ -3,4 +3,4 @@ compiling Set(A.scala) Changes: Map() builder > A.scala compiling Set(A.scala) -Changes: Map(trait A -> List(Changed(Definition(A.x))[method x changed from ()T to ()S flags: <deferred> <method>])) +Changes: Map(trait A -> List(Changed(Definition(A.x))[method x changed from ()T to ()S flags: <method> <deferred>])) diff --git a/test/files/buildmanager/t2651_4/t2651_4.check b/test/files/buildmanager/t2651_4/t2651_4.check index b182f31c09..74e5d8f99b 100644 --- a/test/files/buildmanager/t2651_4/t2651_4.check +++ b/test/files/buildmanager/t2651_4/t2651_4.check @@ -3,8 +3,8 @@ compiling Set(A.scala, B.scala) Changes: Map() builder > A.scala compiling Set(A.scala) -Changes: Map(trait A -> List(Changed(Definition(A.x))[method x changed from ()T to ()T flags: <deferred> <method> <triedcooking>], Changed(Definition(A.y))[method y changed from (a: T)Unit to (a: T)Unit flags: <deferred> <method>], Changed(Definition(A.z))[method z changed from [B <: T]()Unit to [B <: T]()Unit flags: <deferred> <method>])) -invalidate B.scala because inherited method changed [Changed(Definition(A.x))[method x changed from ()T to ()T flags: <deferred> <method> <triedcooking>]] +Changes: Map(trait A -> List(Changed(Definition(A.x))[method x changed from ()T to ()T flags: <method> <deferred> <triedcooking>], Changed(Definition(A.y))[method y changed from (a: T)Unit to (a: T)Unit flags: <method> <deferred>], Changed(Definition(A.z))[method z changed from [B <: T]()Unit to [B <: T]()Unit flags: <method> <deferred>])) +invalidate B.scala because inherited method changed [Changed(Definition(A.x))[method x changed from ()T to ()T flags: <method> <deferred> <triedcooking>]] compiling Set(B.scala) B.scala:2: error: type mismatch; found : Int(3) diff --git a/test/files/buildmanager/t2657/t2657.check b/test/files/buildmanager/t2657/t2657.check index cd0357599c..0d6709e58b 100644 --- a/test/files/buildmanager/t2657/t2657.check +++ b/test/files/buildmanager/t2657/t2657.check @@ -4,8 +4,8 @@ warning: there were 1 feature warnings; re-run with -feature for details Changes: Map() builder > A.scala compiling Set(A.scala) -Changes: Map(class A -> List(Changed(Definition(A.y))[method y changed from (i: Int)String to (i: Int)String flags: implicit <method> <triedcooking>])) -invalidate B.scala because inherited method changed [Changed(Definition(A.y))[method y changed from (i: Int)String to (i: Int)String flags: implicit <method> <triedcooking>]] +Changes: Map(class A -> List(Changed(Definition(A.y))[method y changed from (i: Int)String to (i: Int)String flags: <method> implicit <triedcooking>])) +invalidate B.scala because inherited method changed [Changed(Definition(A.y))[method y changed from (i: Int)String to (i: Int)String flags: <method> implicit <triedcooking>]] compiling Set(B.scala) B.scala:2: error: type mismatch; found : Int(3) diff --git a/test/files/buildmanager/t2789/t2789.check b/test/files/buildmanager/t2789/t2789.check index a7c767cc45..066561ac44 100644 --- a/test/files/buildmanager/t2789/t2789.check +++ b/test/files/buildmanager/t2789/t2789.check @@ -3,8 +3,8 @@ compiling Set(A.scala, B.scala) Changes: Map() builder > A.scala compiling Set(A.scala) -Changes: Map(class A -> List(Changed(Definition(A.e))[method e changed from ()E to ()E flags: implicit <method> <triedcooking>]), class E -> List()) -invalidate B.scala because inherited method changed [Changed(Definition(A.e))[method e changed from ()E to ()E flags: implicit <method> <triedcooking>]] +Changes: Map(class A -> List(Changed(Definition(A.e))[method e changed from ()E to ()E flags: <method> implicit <triedcooking>]), class E -> List()) +invalidate B.scala because inherited method changed [Changed(Definition(A.e))[method e changed from ()E to ()E flags: <method> implicit <triedcooking>]] compiling Set(B.scala) B.scala:2: error: could not find implicit value for parameter y: E val y = x(3) diff --git a/test/files/codelib/code.jar.desired.sha1 b/test/files/codelib/code.jar.desired.sha1 index d2b8d9add9..c4cc74c244 100644 --- a/test/files/codelib/code.jar.desired.sha1 +++ b/test/files/codelib/code.jar.desired.sha1 @@ -1 +1 @@ -e737b123d31eede5594ceda07caafed1673ec472 ?code.jar +e737b123d31eede5594ceda07caafed1673ec472 *code.jar diff --git a/test/files/lib/annotations.jar.desired.sha1 b/test/files/lib/annotations.jar.desired.sha1 index 2b4292d796..ff7bc9425e 100644 --- a/test/files/lib/annotations.jar.desired.sha1 +++ b/test/files/lib/annotations.jar.desired.sha1 @@ -1 +1 @@ -02fe2ed93766323a13f22c7a7e2ecdcd84259b6c ?annotations.jar +02fe2ed93766323a13f22c7a7e2ecdcd84259b6c *annotations.jar diff --git a/test/files/lib/enums.jar.desired.sha1 b/test/files/lib/enums.jar.desired.sha1 index 46cd8e92cf..040dff4487 100644 --- a/test/files/lib/enums.jar.desired.sha1 +++ b/test/files/lib/enums.jar.desired.sha1 @@ -1 +1 @@ -981392dbd1f727b152cd1c908c5fce60ad9d07f7 ?enums.jar +981392dbd1f727b152cd1c908c5fce60ad9d07f7 *enums.jar diff --git a/test/files/lib/genericNest.jar.desired.sha1 b/test/files/lib/genericNest.jar.desired.sha1 index e9321262f2..77e4fec408 100644 --- a/test/files/lib/genericNest.jar.desired.sha1 +++ b/test/files/lib/genericNest.jar.desired.sha1 @@ -1 +1 @@ -b1ec8a095cec4902b3609d74d274c04365c59c04 ?genericNest.jar +b1ec8a095cec4902b3609d74d274c04365c59c04 *genericNest.jar diff --git a/test/files/lib/methvsfield.jar.desired.sha1 b/test/files/lib/methvsfield.jar.desired.sha1 index 8c01532b88..6655f45ddb 100644 --- a/test/files/lib/methvsfield.jar.desired.sha1 +++ b/test/files/lib/methvsfield.jar.desired.sha1 @@ -1 +1 @@ -be8454d5e7751b063ade201c225dcedefd252775 ?methvsfield.jar +be8454d5e7751b063ade201c225dcedefd252775 *methvsfield.jar diff --git a/test/files/lib/nest.jar.desired.sha1 b/test/files/lib/nest.jar.desired.sha1 index 674ca79a5b..056e7ada90 100644 --- a/test/files/lib/nest.jar.desired.sha1 +++ b/test/files/lib/nest.jar.desired.sha1 @@ -1 +1 @@ -cd33e0a0ea249eb42363a2f8ba531186345ff68c ?nest.jar +cd33e0a0ea249eb42363a2f8ba531186345ff68c *nest.jar diff --git a/test/files/lib/scalacheck.jar.desired.sha1 b/test/files/lib/scalacheck.jar.desired.sha1 index e6ed543d73..2f15402d18 100644 --- a/test/files/lib/scalacheck.jar.desired.sha1 +++ b/test/files/lib/scalacheck.jar.desired.sha1 @@ -1 +1 @@ -b6f4dbb29f0c2ec1eba682414f60d52fea84f703 ?scalacheck.jar +b6f4dbb29f0c2ec1eba682414f60d52fea84f703 *scalacheck.jar diff --git a/test/files/neg/stringinterpolation_macro-neg.check b/test/files/neg/stringinterpolation_macro-neg.check new file mode 100644 index 0000000000..8986b899a3 --- /dev/null +++ b/test/files/neg/stringinterpolation_macro-neg.check @@ -0,0 +1,70 @@ +stringinterpolation_macro-neg.scala:8: error: too few parts + new StringContext().f() + ^ +stringinterpolation_macro-neg.scala:9: error: too few arguments for interpolated string + new StringContext("", " is ", "%2d years old").f(s) + ^ +stringinterpolation_macro-neg.scala:10: error: too many arguments for interpolated string + new StringContext("", " is ", "%2d years old").f(s, d, d) + ^ +stringinterpolation_macro-neg.scala:11: error: too few arguments for interpolated string + new StringContext("", "").f() + ^ +stringinterpolation_macro-neg.scala:14: error: type mismatch; + found : String + required: Boolean + f"$s%b" + ^ +stringinterpolation_macro-neg.scala:15: error: type mismatch; + found : String + required: Char + f"$s%c" + ^ +stringinterpolation_macro-neg.scala:16: error: type mismatch; + found : Double + required: Char + f"$f%c" + ^ +stringinterpolation_macro-neg.scala:17: error: type mismatch; + found : String + required: Int + f"$s%x" + ^ +stringinterpolation_macro-neg.scala:18: error: type mismatch; + found : Boolean + required: Int + f"$b%d" + ^ +stringinterpolation_macro-neg.scala:19: error: type mismatch; + found : String + required: Int + f"$s%d" + ^ +stringinterpolation_macro-neg.scala:20: error: type mismatch; + found : Double + required: Int + f"$f%o" + ^ +stringinterpolation_macro-neg.scala:21: error: type mismatch; + found : String + required: Double + f"$s%e" + ^ +stringinterpolation_macro-neg.scala:22: error: type mismatch; + found : Boolean + required: Double + f"$b%f" + ^ +stringinterpolation_macro-neg.scala:27: error: type mismatch; + found : String + required: Int +Note that implicit conversions are not applicable because they are ambiguous: + both value strToInt2 of type String => Int + and value strToInt1 of type String => Int + are possible conversion functions from String to Int + f"$s%d" + ^ +stringinterpolation_macro-neg.scala:30: error: illegal conversion character + f"$s%i" + ^ +15 errors found diff --git a/test/files/neg/stringinterpolation_macro-neg.scala b/test/files/neg/stringinterpolation_macro-neg.scala new file mode 100644 index 0000000000..ac9d97d678 --- /dev/null +++ b/test/files/neg/stringinterpolation_macro-neg.scala @@ -0,0 +1,31 @@ +object Test extends App { + val s = "Scala" + val d = 8 + val b = false + val f = 3.14159 + + // 1) number of arguments + new StringContext().f() + new StringContext("", " is ", "%2d years old").f(s) + new StringContext("", " is ", "%2d years old").f(s, d, d) + new StringContext("", "").f() + + // 2) Interpolation mismatches + f"$s%b" + f"$s%c" + f"$f%c" + f"$s%x" + f"$b%d" + f"$s%d" + f"$f%o" + f"$s%e" + f"$b%f" + + { + implicit val strToInt1 = (s: String) => 1 + implicit val strToInt2 = (s: String) => 2 + f"$s%d" + } + + f"$s%i" +} diff --git a/test/files/neg/t5504.check b/test/files/neg/t5504.check deleted file mode 100644 index 2827c02d10..0000000000 --- a/test/files/neg/t5504.check +++ /dev/null @@ -1,4 +0,0 @@ -error: type _$1 is defined twice - conflicting symbols both originated in file 't5504/s_1.scala' - Note: this may be due to a bug in the compiler involving wildcards in package objects -one error found diff --git a/test/files/neg/t6042.check b/test/files/neg/t6042.check new file mode 100644 index 0000000000..221f06e2c5 --- /dev/null +++ b/test/files/neg/t6042.check @@ -0,0 +1,4 @@ +t6042.scala:7: error: illegal type selection from volatile type a.OpSemExp (with upper bound LazyExp[a.OpSemExp] with _$1) + def foo[AA <: LazyExp[_]](a: AA): a.OpSemExp#Val = ??? // a.OpSemExp is volatile, because of `with This` + ^ +one error found diff --git a/test/files/neg/t6042.scala b/test/files/neg/t6042.scala new file mode 100644 index 0000000000..5a123d17ca --- /dev/null +++ b/test/files/neg/t6042.scala @@ -0,0 +1,8 @@ +trait LazyExp[+This <: LazyExp[This]] { this: This => + type OpSemExp <: LazyExp[OpSemExp] with This + type Val +} + +object Test { + def foo[AA <: LazyExp[_]](a: AA): a.OpSemExp#Val = ??? // a.OpSemExp is volatile, because of `with This` +} diff --git a/test/files/neg/t5504/s_1.scala b/test/files/pos/t5504/s_1.scala index 35cb2c8bae..35cb2c8bae 100644 --- a/test/files/neg/t5504/s_1.scala +++ b/test/files/pos/t5504/s_1.scala diff --git a/test/files/neg/t5504/s_2.scala b/test/files/pos/t5504/s_2.scala index 03eecf6e19..03eecf6e19 100644 --- a/test/files/neg/t5504/s_2.scala +++ b/test/files/pos/t5504/s_2.scala diff --git a/test/files/pos/t5957/T_1.scala b/test/files/pos/t5957/T_1.scala new file mode 100644 index 0000000000..1db5a3891f --- /dev/null +++ b/test/files/pos/t5957/T_1.scala @@ -0,0 +1,6 @@ +abstract class T { + def t1: Test$Bar + def t2: Test#Bar + def t3: Test$Baz + def t4: Test.Baz +} diff --git a/test/files/pos/t5957/Test.java b/test/files/pos/t5957/Test.java new file mode 100644 index 0000000000..4fbd257d95 --- /dev/null +++ b/test/files/pos/t5957/Test.java @@ -0,0 +1,11 @@ +public class Test { + public class Bar { + public Bar(int i) { + } + } + + public static class Baz { + public Baz(int i) { + } + } +} diff --git a/test/files/pos/t6022.flags b/test/files/pos/t6022.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/pos/t6022.flags @@ -0,0 +1 @@ +-Xfatal-warnings
\ No newline at end of file diff --git a/test/files/pos/t6022.scala b/test/files/pos/t6022.scala new file mode 100644 index 0000000000..522c3352c7 --- /dev/null +++ b/test/files/pos/t6022.scala @@ -0,0 +1,7 @@ +class Test { + (null: Any) match { + case x: AnyRef if false => + case list: Option[_] => + case product: Product => // change Product to String and it's all good + } +}
\ No newline at end of file diff --git a/test/files/presentation/hyperlinks.flags b/test/files/presentation/hyperlinks.flags deleted file mode 100644 index dc13682c5e..0000000000 --- a/test/files/presentation/hyperlinks.flags +++ /dev/null @@ -1,2 +0,0 @@ -# This test will fail in the new pattern matcher because -# it generates trees whose positions are not transparent diff --git a/test/files/presentation/hyperlinks/Runner.scala b/test/files/presentation/hyperlinks/Runner.scala index 3d19f2d948..61da49a3d7 100644 --- a/test/files/presentation/hyperlinks/Runner.scala +++ b/test/files/presentation/hyperlinks/Runner.scala @@ -1,11 +1,11 @@ import scala.tools.nsc.interactive.tests.InteractiveTest object Test extends InteractiveTest { - override def runTests() { + override def runDefaultTests() { // make sure typer is done.. the virtual pattern matcher might translate // some trees and mess up positions. But we'll catch it red handed! sourceFiles foreach (src => askLoadedTyped(src).get) - super.runTests() + super.runDefaultTests() } }
\ No newline at end of file diff --git a/test/files/presentation/ide-bug-1000469/Runner.scala b/test/files/presentation/ide-bug-1000469/Runner.scala index c53533fddd..1ef3cf9025 100644 --- a/test/files/presentation/ide-bug-1000469/Runner.scala +++ b/test/files/presentation/ide-bug-1000469/Runner.scala @@ -1,5 +1,3 @@ import scala.tools.nsc.interactive.tests._ -object Test extends InteractiveTest { - override val runRandomTests = false -} +object Test extends InteractiveTest
\ No newline at end of file diff --git a/test/files/presentation/ide-bug-1000531.flags b/test/files/presentation/ide-bug-1000531.flags deleted file mode 100644 index 56d026a62d..0000000000 --- a/test/files/presentation/ide-bug-1000531.flags +++ /dev/null @@ -1,18 +0,0 @@ -# This file contains command line options that are passed to the presentation compiler -# Lines starting with # are stripped, and you can split arguments on several lines. - -# The -bootclasspath option is treated specially by the test framework: if it's not specified -# in this file, the presentation compiler will pick up the scala-library/compiler that's on the -# java classpath used to run this test (usually build/pack) - -# Any option can be passed this way, like presentation debug -# -Ypresentation-debug -Ypresentation-verbose - -# the classpath is relative to the current working directory. That means it depends where you're -# running partest from. Run it from the root scala checkout for these files to resolve correctly -# (by default when running 'ant test', or 'test/partest'). Paths use Unix separators, the test -# framework translates them to the platform dependent representation. -# -bootclasspath lib/scala-compiler.jar:lib/scala-library.jar:lib/fjbg.jar - -# the following line would test using the quick compiler -# -bootclasspath build/quick/classes/compiler:build/quick/classes/library:lib/fjbg.jar diff --git a/test/files/presentation/ide-t1000976.check b/test/files/presentation/ide-t1000976.check new file mode 100644 index 0000000000..d58f86d6c6 --- /dev/null +++ b/test/files/presentation/ide-t1000976.check @@ -0,0 +1 @@ +Test OK
\ No newline at end of file diff --git a/test/files/presentation/ide-t1000976.flags b/test/files/presentation/ide-t1000976.flags new file mode 100644 index 0000000000..9a1a05a4f6 --- /dev/null +++ b/test/files/presentation/ide-t1000976.flags @@ -0,0 +1 @@ +-sourcepath src
\ No newline at end of file diff --git a/test/files/presentation/ide-t1000976/Test.scala b/test/files/presentation/ide-t1000976/Test.scala new file mode 100644 index 0000000000..722259d3a1 --- /dev/null +++ b/test/files/presentation/ide-t1000976/Test.scala @@ -0,0 +1,30 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest +import scala.reflect.internal.util.SourceFile +import scala.tools.nsc.interactive.Response + +object Test extends InteractiveTest { + override def execute(): Unit = { + loadSourceAndWaitUntilTypechecked("A.scala") + val sourceB = loadSourceAndWaitUntilTypechecked("B.scala") + checkErrors(sourceB) + } + + private def loadSourceAndWaitUntilTypechecked(sourceName: String): SourceFile = { + val sourceFile = sourceFiles.find(_.file.name == sourceName).head + compiler.askToDoFirst(sourceFile) + val res = new Response[Unit] + compiler.askReload(List(sourceFile), res) + res.get + askLoadedTyped(sourceFile).get + sourceFile + } + + private def checkErrors(source: SourceFile): Unit = compiler.getUnitOf(source) match { + case Some(unit) => + val problems = unit.problems.toList + if(problems.isEmpty) reporter.println("Test OK") + else problems.foreach(problem => reporter.println(problem.msg)) + + case None => reporter.println("No compilation unit found for " + source.file.name) + } +} diff --git a/test/files/presentation/ide-t1000976/src/a/A.scala b/test/files/presentation/ide-t1000976/src/a/A.scala new file mode 100644 index 0000000000..fcfef8b525 --- /dev/null +++ b/test/files/presentation/ide-t1000976/src/a/A.scala @@ -0,0 +1,7 @@ +package a + +import d.D._ + +object A { + Seq.empty[Byte].toArray.toSeq +} diff --git a/test/files/presentation/ide-t1000976/src/b/B.scala b/test/files/presentation/ide-t1000976/src/b/B.scala new file mode 100644 index 0000000000..628348cac1 --- /dev/null +++ b/test/files/presentation/ide-t1000976/src/b/B.scala @@ -0,0 +1,7 @@ +package b + +import c.C + +class B { + new C("") +} diff --git a/test/files/presentation/ide-t1000976/src/c/C.scala b/test/files/presentation/ide-t1000976/src/c/C.scala new file mode 100644 index 0000000000..cc23e3eef1 --- /dev/null +++ b/test/files/presentation/ide-t1000976/src/c/C.scala @@ -0,0 +1,3 @@ +package c + +class C(key: String = "", componentStates: String = "") diff --git a/test/files/presentation/ide-t1000976/src/d/D.scala b/test/files/presentation/ide-t1000976/src/d/D.scala new file mode 100644 index 0000000000..d7a48f98d5 --- /dev/null +++ b/test/files/presentation/ide-t1000976/src/d/D.scala @@ -0,0 +1,7 @@ +package d + +import c.C + +object D { + implicit def c2s(c: C): String = "" +} diff --git a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala index 857beac7df..a5533a623a 100644 --- a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala +++ b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala @@ -24,10 +24,7 @@ import scala.tools.nsc.io._ object Test extends InteractiveTest { final val mega = 1024 * 1024 - override def main(args: Array[String]) { - memoryConsumptionTest() - compiler.askShutdown() - } + override def execute(): Unit = memoryConsumptionTest() def batchSource(name: String) = new BatchSourceFile(AbstractFile.getFile(name)) diff --git a/test/files/presentation/t5708/Test.scala b/test/files/presentation/t5708/Test.scala index 96e758d974..bec1131c4c 100644 --- a/test/files/presentation/t5708/Test.scala +++ b/test/files/presentation/t5708/Test.scala @@ -1,5 +1,3 @@ import scala.tools.nsc.interactive.tests.InteractiveTest -object Test extends InteractiveTest { - -}
\ No newline at end of file +object Test extends InteractiveTest
\ No newline at end of file diff --git a/test/files/presentation/visibility/Test.scala b/test/files/presentation/visibility/Test.scala index 96e758d974..bec1131c4c 100644 --- a/test/files/presentation/visibility/Test.scala +++ b/test/files/presentation/visibility/Test.scala @@ -1,5 +1,3 @@ import scala.tools.nsc.interactive.tests.InteractiveTest -object Test extends InteractiveTest { - -}
\ No newline at end of file +object Test extends InteractiveTest
\ No newline at end of file diff --git a/test/files/run/stringinterpolation_macro-run.check b/test/files/run/stringinterpolation_macro-run.check new file mode 100644 index 0000000000..be62c5780b --- /dev/null +++ b/test/files/run/stringinterpolation_macro-run.check @@ -0,0 +1,62 @@ +false +false +true +false +true +FALSE +FALSE +TRUE +FALSE +TRUE +true +false +null +0 +80000000 +4c01926 +NULL +4C01926 +null +NULL +Scala +SCALA +5 +x +x +x +x +x +x +x +x +x +x +x +x +S +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +42 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.000000e+00 +3.000000e+00 +05/26/12 +05/26/12 +05/26/12 +05/26/12 diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala new file mode 100644 index 0000000000..9c59c334f8 --- /dev/null +++ b/test/files/run/stringinterpolation_macro-run.scala @@ -0,0 +1,103 @@ +object Test extends App { + +// 'b' / 'B' (category: general) +// ----------------------------- +println(f"${null}%b") +println(f"${false}%b") +println(f"${true}%b") +println(f"${new java.lang.Boolean(false)}%b") +println(f"${new java.lang.Boolean(true)}%b") + +println(f"${null}%B") +println(f"${false}%B") +println(f"${true}%B") +println(f"${new java.lang.Boolean(false)}%B") +println(f"${new java.lang.Boolean(true)}%B") + +implicit val stringToBoolean = java.lang.Boolean.parseBoolean(_: String) +println(f"${"true"}%b") +println(f"${"false"}%b") + +// 'h' | 'H' (category: general) +// ----------------------------- +println(f"${null}%h") +println(f"${0.0}%h") +println(f"${-0.0}%h") +println(f"${"Scala"}%h") + +println(f"${null}%H") +println(f"${"Scala"}%H") + +// 's' | 'S' (category: general) +// ----------------------------- +println(f"${null}%s") +println(f"${null}%S") +println(f"${"Scala"}%s") +println(f"${"Scala"}%S") +println(f"${5}") + +// 'c' | 'C' (category: character) +// ------------------------------- +println(f"${120:Char}%c") +println(f"${120:Byte}%c") +println(f"${120:Short}%c") +println(f"${120:Int}%c") +println(f"${new java.lang.Character('x')}%c") +println(f"${new java.lang.Byte(120:Byte)}%c") +println(f"${new java.lang.Short(120:Short)}%c") +println(f"${new java.lang.Integer(120)}%c") + +println(f"${'x' : java.lang.Character}%c") +println(f"${(120:Byte) : java.lang.Byte}%c") +println(f"${(120:Short) : java.lang.Short}%c") +println(f"${120 : java.lang.Integer}%c") + +implicit val stringToChar = (x: String) => x(0) +println(f"${"Scala"}%c") + +// 'd' | 'o' | 'x' | 'X' (category: integral) +// ------------------------------------------ +println(f"${120:Byte}%d") +println(f"${120:Short}%d") +println(f"${120:Int}%d") +println(f"${120:Long}%d") +println(f"${new java.lang.Byte(120:Byte)}%d") +println(f"${new java.lang.Short(120:Short)}%d") +println(f"${new java.lang.Integer(120)}%d") +println(f"${new java.lang.Long(120)}%d") +println(f"${120 : java.lang.Integer}%d") +println(f"${120 : java.lang.Long}%d") +println(f"${BigInt(120)}%d") +println(f"${new java.math.BigInteger("120")}%d") + +{ + implicit val strToShort = (s: String) => java.lang.Short.parseShort(s) + println(f"${"120"}%d") + implicit val strToInt = (s: String) => 42 + println(f"${"120"}%d") +} + +// 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' (category: floating point) +// ------------------------------------------------------------------ +println(f"${3.4f}%e") +println(f"${3.4}%e") +println(f"${3.4f : java.lang.Float}%e") +println(f"${3.4 : java.lang.Double}%e") +println(f"${BigDecimal(3.4)}%e") +println(f"${new java.math.BigDecimal(3.4)}%e") +println(f"${3}%e") +println(f"${3L}%e") + +// 't' | 'T' (category: date/time) +// ------------------------------- +import java.util.Calendar +import java.util.Locale +val c = Calendar.getInstance(Locale.US) +c.set(2012, Calendar.MAY, 26) +println(f"${c}%TD") +println(f"${c.getTime}%TD") +println(f"${c.getTime.getTime}%TD") + +implicit val strToDate = (x: String) => c +println(f"""${"1234"}%TD""") +} diff --git a/test/files/run/t5974.check b/test/files/run/t5974.check new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/test/files/run/t5974.check @@ -0,0 +1 @@ +ok diff --git a/test/files/run/t5974.scala b/test/files/run/t5974.scala new file mode 100644 index 0000000000..5b99e9f721 --- /dev/null +++ b/test/files/run/t5974.scala @@ -0,0 +1,10 @@ +object Test extends App { + import scala.collection.JavaConverters._ + + def ser(a: AnyRef) = + (new java.io.ObjectOutputStream(new java.io.ByteArrayOutputStream())).writeObject(a) + + val l = java.util.Arrays.asList("pigdog").asScala + ser(l) + println("ok") +} diff --git a/test/files/speclib/instrumented.jar.desired.sha1 b/test/files/speclib/instrumented.jar.desired.sha1 index 24856fe19a..0b8ee593da 100644 --- a/test/files/speclib/instrumented.jar.desired.sha1 +++ b/test/files/speclib/instrumented.jar.desired.sha1 @@ -1 +1 @@ -474d8c20ab31438d5d4a2ba6bc07ebdcdb530b50 ?instrumented.jar +474d8c20ab31438d5d4a2ba6bc07ebdcdb530b50 *instrumented.jar diff --git a/tools/new-starr b/tools/new-starr new file mode 100755 index 0000000000..5f00cc758e --- /dev/null +++ b/tools/new-starr @@ -0,0 +1,6 @@ +#!/bin/bash + +ant -Dscalac.args.optimise="-optimise" locker.done +cp -R src/starr/* src/ +ant build-opt +ant starr.done |