summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml26
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala83
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala12
-rw-r--r--src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala149
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala60
-rw-r--r--src/library/scala/annotation/static.scala20
-rw-r--r--src/library/scala/concurrent/package.scala78
-rw-r--r--src/partest/scala/tools/partest/DirectTest.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1
-rw-r--r--src/reflect/scala/reflect/internal/util/SourceFile.scala24
-rw-r--r--src/reflect/scala/tools/nsc/io/VirtualFile.scala2
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala11
-rw-r--r--test/files/neg/static-annot.check19
-rw-r--r--test/files/neg/static-annot.scala47
-rw-r--r--test/files/neg/t4069.check2
-rw-r--r--test/files/neg/t4584.check7
-rw-r--r--test/files/neg/unicode-unterminated-quote.check5
-rw-r--r--test/files/pos/t5957/T_1.scala6
-rw-r--r--test/files/run/outertest.scala26
-rw-r--r--test/files/run/static-annot/field.scala243
-rw-r--r--test/files/run/t5385.check8
-rw-r--r--test/files/run/t5385.scala16
-rw-r--r--test/files/run/t6104.check1
-rw-r--r--test/files/run/t6104.scala8
32 files changed, 764 insertions, 126 deletions
diff --git a/build.xml b/build.xml
index 1fba806071..a4feada3c7 100644
--- a/build.xml
+++ b/build.xml
@@ -499,7 +499,7 @@ LOCAL DEPENDENCY (Adapted ASM)
destdir="${build-asm.dir}/classes"
classpath="${build-asm.dir}/classes"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
</javac>
<touch file="${build-asm.dir}/asm.complete" verbose="no"/>
@@ -540,7 +540,7 @@ LOCAL DEPENDENCY (FORKJOIN)
classpath="${build-libs.dir}/classes/forkjoin"
includes="**/*.java"
debug="true"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
</javac>
<touch file="${build-libs.dir}/forkjoin.complete" verbose="no"/>
@@ -587,7 +587,7 @@ LOCAL DEPENDENCY (FJBG)
classpath="${build-libs.dir}/classes/fjbg"
includes="**/*.java"
debug="true"
- target="1.5" source="1.4">
+ target="1.6" source="1.4">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
</javac>
<touch file="${build-libs.dir}/fjbg.complete" verbose="no"/>
@@ -635,7 +635,7 @@ LOCAL REFERENCE BUILD (LOCKER)
srcdir="${src.dir}/library"
destdir="${build-locker.dir}/classes/library"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
<classpath>
<path refid="forkjoin.classpath"/>
@@ -749,7 +749,7 @@ LOCAL REFERENCE BUILD (LOCKER)
includes="**/*.java"
excludes="**/tests/**"
debug="true"
- target="1.5" source="1.4">
+ target="1.6" source="1.4">
<compilerarg line="${javac.args}"/>
</javac>
<scalacfork
@@ -1009,7 +1009,7 @@ QUICK BUILD (QUICK)
srcdir="${src.dir}/library"
destdir="${build-quick.dir}/classes/library"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
<classpath>
<path refid="forkjoin.classpath"/>
@@ -1020,7 +1020,7 @@ QUICK BUILD (QUICK)
srcdir="${src.dir}/actors"
destdir="${build-quick.dir}/classes/library"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args}"/>
<classpath>
<path refid="forkjoin.classpath"/>
@@ -1145,7 +1145,7 @@ QUICK BUILD (QUICK)
includes="**/*.java"
excludes="**/tests/**"
debug="true"
- target="1.5" source="1.4">
+ target="1.6" source="1.4">
<compilerarg line="${javac.args}"/>
</javac>
<scalacfork
@@ -1349,7 +1349,7 @@ QUICK BUILD (QUICK)
<javac
srcdir="${src.dir}/partest"
destdir="${build-quick.dir}/classes/partest"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<classpath>
<pathelement location="${build-quick.dir}/classes/library"/>
<pathelement location="${build-quick.dir}/classes/reflect"/>
@@ -1691,7 +1691,7 @@ BOOTSTRAPPING BUILD (STRAP)
srcdir="${src.dir}/library"
destdir="${build-strap.dir}/classes/library"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args} -XDignore.symbol.file"/>
<classpath>
<path refid="forkjoin.classpath"/>
@@ -1702,7 +1702,7 @@ BOOTSTRAPPING BUILD (STRAP)
srcdir="${src.dir}/actors"
destdir="${build-strap.dir}/classes/library"
includes="**/*.java"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<compilerarg line="${javac.args}"/>
<classpath>
<path refid="forkjoin.classpath"/>
@@ -1826,7 +1826,7 @@ BOOTSTRAPPING BUILD (STRAP)
includes="**/*.java"
excludes="**/tests/**"
debug="true"
- target="1.5" source="1.4">
+ target="1.6" source="1.4">
<compilerarg line="${javac.args}"/>
</javac>
<scalacfork
@@ -1994,7 +1994,7 @@ BOOTSTRAPPING BUILD (STRAP)
<javac
srcdir="${src.dir}/partest"
destdir="${build-strap.dir}/classes/partest"
- target="1.5" source="1.5">
+ target="1.6" source="1.5">
<classpath>
<pathelement location="${build-strap.dir}/classes/library"/>
<pathelement location="${build-strap.dir}/classes/reflect"/>
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index e70716885e..c6809fb48e 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -99,7 +99,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {
/** Defines valid values for the `target` property. */
object Target extends PermissibleValue {
- val values = List("jvm-1.5", "jvm-1.6", "jvm-1.7", "msil")
+ val values = List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil")
}
/** Defines valid values for the `deprecation` and `unchecked` properties. */
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index e378d71944..83335c4f62 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1447,6 +1447,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
settings.userSetSettings filter (_.isDeprecated) foreach { s =>
unit.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get)
}
+ if (settings.target.value.contains("jvm-1.5"))
+ unit.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.")
}
/* An iterator returning all the units being compiled in this run */
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index b638745327..982267097b 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -113,26 +113,42 @@ abstract class GenICode extends SubComponent {
m.native = m.symbol.hasAnnotation(definitions.NativeAttr)
if (!m.isAbstractMethod && !m.native) {
- ctx1 = genLoad(rhs, ctx1, m.returnType);
-
- // reverse the order of the local variables, to match the source-order
- m.locals = m.locals.reverse
-
- rhs match {
- case Block(_, Return(_)) => ()
- case Return(_) => ()
- case EmptyTree =>
- globalError("Concrete method has no definition: " + tree + (
- if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")"
- else "")
- )
- case _ => if (ctx1.bb.isEmpty)
- ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos)
- else
+ if (m.symbol.isAccessor && m.symbol.accessed.hasStaticAnnotation) {
+ // in companion object accessors to @static fields, we access the static field directly
+ val hostClass = m.symbol.owner.companionClass
+ val staticfield = hostClass.info.findMember(m.symbol.accessed.name, NoFlags, NoFlags, false)
+
+ if (m.symbol.isGetter) {
+ ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos)
ctx1.bb.closeWith(RETURN(m.returnType))
+ } else if (m.symbol.isSetter) {
+ ctx1.bb.emit(LOAD_LOCAL(m.locals.head), tree.pos)
+ ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos)
+ ctx1.bb.closeWith(RETURN(m.returnType))
+ } else assert(false, "unreachable")
+ } else {
+ ctx1 = genLoad(rhs, ctx1, m.returnType);
+
+ // reverse the order of the local variables, to match the source-order
+ m.locals = m.locals.reverse
+
+ rhs match {
+ case Block(_, Return(_)) => ()
+ case Return(_) => ()
+ case EmptyTree =>
+ globalError("Concrete method has no definition: " + tree + (
+ if (settings.debug.value) "(found: " + m.symbol.owner.info.decls.toList.mkString(", ") + ")"
+ else "")
+ )
+ case _ =>
+ if (ctx1.bb.isEmpty)
+ ctx1.bb.closeWith(RETURN(m.returnType), rhs.pos)
+ else
+ ctx1.bb.closeWith(RETURN(m.returnType))
+ }
+ if (!ctx1.bb.closed) ctx1.bb.close
+ prune(ctx1.method)
}
- if (!ctx1.bb.closed) ctx1.bb.close
- prune(ctx1.method)
} else
ctx1.method.setCode(NoCode)
ctx1
@@ -854,9 +870,32 @@ abstract class GenICode extends SubComponent {
generatedType = toTypeKind(fun.symbol.tpe.resultType)
ctx1
+ case app @ Apply(fun @ Select(qual, _), args)
+ if !ctx.method.symbol.isStaticConstructor
+ && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation =>
+ // bypass the accessor to the companion object and load the static field directly
+ // the only place were this bypass is not done, is the static intializer for the static field itself
+ val sym = fun.symbol
+ generatedType = toTypeKind(sym.accessed.info)
+ val hostClass = qual.tpe.typeSymbol.orElse(sym.owner).companionClass
+ val staticfield = hostClass.info.findMember(sym.accessed.name, NoFlags, NoFlags, false)
+
+ if (sym.isGetter) {
+ ctx.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos)
+ ctx
+ } else if (sym.isSetter) {
+ val ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx)
+ ctx1.bb.emit(STORE_FIELD(staticfield, true), tree.pos)
+ ctx1.bb.emit(CONSTANT(Constant(false)), tree.pos)
+ ctx1
+ } else {
+ assert(false, "supposedly unreachable")
+ ctx
+ }
+
case app @ Apply(fun, args) =>
val sym = fun.symbol
-
+
if (sym.isLabel) { // jump to a label
val label = ctx.labels.getOrElse(sym, {
// it is a forward jump, scan for labels
@@ -1623,8 +1662,12 @@ abstract class GenICode extends SubComponent {
* backend emits them as static).
* No code is needed for this module symbol.
*/
- for (f <- cls.info.decls ; if !f.isMethod && f.isTerm && !f.isModule)
+ for (
+ f <- cls.info.decls;
+ if !f.isMethod && f.isTerm && !f.isModule && !(f.owner.isModuleClass && f.hasStaticAnnotation)
+ ) {
ctx.clazz addField new IField(f)
+ }
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index e3d1f61535..025046f19e 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -598,7 +598,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
reverseJavaName.put(internalName, trackedSym)
case Some(oldsym) =>
assert((oldsym == trackedSym) || (oldsym == RuntimeNothingClass) || (oldsym == RuntimeNullClass), // In contrast, neither NothingClass nor NullClass show up bytecode-level.
- "how can getCommonSuperclass() do its job if different class symbols get the same bytecode-level internal name.")
+ "how can getCommonSuperclass() do its job if different class symbols get the same bytecode-level internal name: " + internalName)
}
}
@@ -1170,7 +1170,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name))
else {
log("Adding static forwarder for '%s' from %s to '%s'".format(m, jclassName, moduleClass))
- addForwarder(isRemoteClass, jclass, moduleClass, m)
+ if (m.isAccessor && m.accessed.hasStaticAnnotation) {
+ log("@static: accessor " + m + ", accessed: " + m.accessed)
+ } else addForwarder(isRemoteClass, jclass, moduleClass, m)
}
}
}
@@ -1675,6 +1677,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
jmethod = clinitMethod
jMethodName = CLASS_CONSTRUCTOR_NAME
jmethod.visitCode()
+ computeLocalVarsIndex(m)
genCode(m, false, true)
jmethod.visitMaxs(0, 0) // just to follow protocol, dummy arguments
jmethod.visitEnd()
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 912a5b0e90..0ae2adac84 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -1021,6 +1021,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
method = m
jmethod = clinitMethod
+
+ computeLocalVarsIndex(m)
genCode(m)
case None =>
legacyStaticInitializer(cls, clinit)
@@ -1114,7 +1116,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
linkedClass.info.members collect { case sym if sym.name.isTermName => sym.name } toSet
}
debuglog("Potentially conflicting names for forwarders: " + conflictingNames)
-
+
for (m <- moduleClass.info.membersBasedOnFlags(ExcludedForwarderFlags, Flags.METHOD)) {
if (m.isType || m.isDeferred || (m.owner eq ObjectClass) || m.isConstructor)
debuglog("No forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
@@ -1122,7 +1124,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name))
else {
log("Adding static forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
- addForwarder(jclass, moduleClass, m)
+ if (m.isAccessor && m.accessed.hasStaticAnnotation) {
+ log("@static: accessor " + m + ", accessed: " + m.accessed)
+ } else addForwarder(jclass, moduleClass, m)
}
}
}
@@ -1304,7 +1308,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
jclass.getType())
}
}
-
+
style match {
case Static(true) => dbg("invokespecial"); jcode.emitINVOKESPECIAL(jowner, jname, jtype)
case Static(false) => dbg("invokestatic"); jcode.emitINVOKESTATIC(jowner, jname, jtype)
@@ -1885,7 +1889,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
*/
def computeLocalVarsIndex(m: IMethod) {
var idx = if (m.symbol.isStaticMember) 0 else 1;
-
+
for (l <- m.params) {
debuglog("Index value for " + l + "{" + l.## + "}: " + idx)
l.index = idx
diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
index f0ee8b11f3..0991577829 100644
--- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
@@ -40,9 +40,9 @@ trait StandardScalaSettings {
val nowarn = BooleanSetting ("-nowarn", "Generate no warnings.")
val optimise: BooleanSetting // depends on post hook which mutates other settings
val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.")
- val target = ChoiceSetting ("-target", "target", "Target platform for object files.",
+ val target = ChoiceSetting ("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.",
List("jvm-1.5", "jvm-1.5-fjbg", "jvm-1.5-asm", "jvm-1.6", "jvm-1.7", "msil"),
- "jvm-1.5-asm")
+ "jvm-1.6")
val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked (erasure) warnings.")
val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.")
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index bbdf10a021..e672f1914a 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -23,9 +23,12 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
new CleanUpTransformer(unit)
class CleanUpTransformer(unit: CompilationUnit) extends Transformer {
- private val newStaticMembers = mutable.Buffer.empty[Tree]
- private val newStaticInits = mutable.Buffer.empty[Tree]
- private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
+ private val newStaticMembers = mutable.Buffer.empty[Tree]
+ private val newStaticInits = mutable.Buffer.empty[Tree]
+ private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
+ private val staticBodies = mutable.Map.empty[(Symbol, Symbol), Tree]
+ private val syntheticClasses = mutable.Map.empty[Symbol, mutable.Set[Tree]] // package and trees
+ private val classNames = mutable.Map.empty[Symbol, Set[Name]]
private def clearStatics() {
newStaticMembers.clear()
newStaticInits.clear()
@@ -45,15 +48,16 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
result
}
private def transformTemplate(tree: Tree) = {
- val Template(parents, self, body) = tree
+ val t @ Template(parents, self, body) = tree
clearStatics()
+
val newBody = transformTrees(body)
val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody)
try addStaticInits(templ) // postprocess to include static ctors
finally clearStatics()
}
private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix)
-
+
/** Kludge to provide a safe fix for #4560:
* If we generate a reference in an implementation class, we
* watch out for embedded This(..) nodes that point to the interface.
@@ -555,7 +559,73 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
else tree
}
-
+
+ case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation =>
+ log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner)
+ val sym = tree.symbol
+ val owner = sym.owner
+
+ val staticBeforeLifting = atPhase(currentRun.erasurePhase) { owner.isStatic }
+ val isPrivate = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PRIVATE) }
+ val isProtected = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PROTECTED) }
+ val isLazy = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(LAZY) }
+ if (!owner.isModuleClass || !staticBeforeLifting) {
+ if (!sym.isSynthetic) {
+ reporter.error(tree.pos, "Only members of top-level objects and their nested objects can be annotated with @static.")
+ tree.symbol.removeAnnotation(StaticClass)
+ }
+ super.transform(tree)
+ } else if (isPrivate || isProtected) {
+ reporter.error(tree.pos, "The @static annotation is only allowed on public members.")
+ tree.symbol.removeAnnotation(StaticClass)
+ super.transform(tree)
+ } else if (isLazy) {
+ reporter.error(tree.pos, "The @static annotation is not allowed on lazy members.")
+ tree.symbol.removeAnnotation(StaticClass)
+ super.transform(tree)
+ } else if (owner.isModuleClass) {
+ val linkedClass = owner.companionClass match {
+ case NoSymbol =>
+ // create the companion class if it does not exist
+ val enclosing = owner.owner
+ val compclass = enclosing.newClass(newTypeName(owner.name.toString))
+ compclass setInfo ClassInfoType(List(ObjectClass.tpe), newScope, compclass)
+ enclosing.info.decls enter compclass
+
+ val compclstree = ClassDef(compclass, NoMods, List(List()), List(List()), List(), tree.pos)
+
+ syntheticClasses.getOrElseUpdate(enclosing, mutable.Set()) += compclstree
+
+ compclass
+ case comp => comp
+ }
+
+ // create a static field in the companion class for this @static field
+ val stfieldSym = linkedClass.newVariable(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe
+ stfieldSym.addAnnotation(StaticClass)
+
+ val names = classNames.getOrElseUpdate(linkedClass, linkedClass.info.decls.collect {
+ case sym if sym.name.isTermName => sym.name
+ } toSet)
+ if (names(stfieldSym.name)) {
+ reporter.error(
+ tree.pos,
+ "@static annotated field " + tree.symbol.name + " has the same name as a member of class " + linkedClass.name
+ )
+ } else {
+ linkedClass.info.decls enter stfieldSym
+
+ val initializerBody = rhs
+
+ // static field was previously initialized in the companion object itself, like this:
+ // staticBodies((linkedClass, stfieldSym)) = Select(This(owner), sym.getter(owner))
+ // instead, we move the initializer to the static ctor of the companion class
+ // we save the entire ValDef/DefDef to extract the rhs later
+ staticBodies((linkedClass, stfieldSym)) = tree
+ }
+ }
+ super.transform(tree)
+
/* MSIL requires that the stack is empty at the end of a try-block.
* Hence, we here rewrite all try blocks with a result != {Unit, All} such that they
* store their result in a local variable. The catch blocks are adjusted as well.
@@ -665,6 +735,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
if (newStaticInits.isEmpty)
template
else {
+ val ctorBody = newStaticInits.toList flatMap {
+ case Block(stats, expr) => stats :+ expr
+ case t => List(t)
+ }
+
val newCtor = findStaticCtor(template) match {
// in case there already were static ctors - augment existing ones
// currently, however, static ctors aren't being generated anywhere else
@@ -673,22 +748,76 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
deriveDefDef(ctor) {
case block @ Block(stats, expr) =>
// need to add inits to existing block
- treeCopy.Block(block, newStaticInits.toList ::: stats, expr)
+ treeCopy.Block(block, ctorBody ::: stats, expr)
case term: TermTree =>
// need to create a new block with inits and the old term
- treeCopy.Block(term, newStaticInits.toList, term)
+ treeCopy.Block(term, ctorBody, term)
}
case _ =>
// create new static ctor
val staticCtorSym = currentClass.newStaticConstructor(template.pos)
- val rhs = Block(newStaticInits.toList, Literal(Constant(())))
+ val rhs = Block(ctorBody, Literal(Constant(())))
localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs))
}
deriveTemplate(template)(newCtor :: _)
}
}
-
+
+ private def addStaticDeclarations(tree: Template, clazz: Symbol) {
+ // add static field initializer statements for each static field in clazz
+ if (!clazz.isModuleClass) for {
+ staticSym <- clazz.info.decls
+ if staticSym.hasStaticAnnotation
+ } staticSym match {
+ case stfieldSym if stfieldSym.isVariable =>
+ val valdef = staticBodies((clazz, stfieldSym))
+ val ValDef(_, _, _, rhs) = valdef
+ val fixedrhs = rhs.changeOwner((valdef.symbol, clazz.info.decl(nme.CONSTRUCTOR)))
+
+ val stfieldDef = localTyper.typedPos(tree.pos)(VAL(stfieldSym) === EmptyTree)
+ val flattenedInit = fixedrhs match {
+ case Block(stats, expr) => Block(stats, safeREF(stfieldSym) === expr)
+ case rhs => safeREF(stfieldSym) === rhs
+ }
+ val stfieldInit = localTyper.typedPos(tree.pos)(flattenedInit)
+
+ // add field definition to new defs
+ newStaticMembers append stfieldDef
+ newStaticInits append stfieldInit
+ }
+ }
+
+
+
+ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
+ super.transformStats(stats, exprOwner) ++ {
+ // flush pending synthetic classes created in this owner
+ val synthclassdefs = syntheticClasses.get(exprOwner).toList.flatten
+ syntheticClasses -= exprOwner
+ synthclassdefs map {
+ cdef => localTyper.typedPos(cdef.pos)(cdef)
+ }
+ } map {
+ case clsdef @ ClassDef(mods, name, tparams, t @ Template(parent, self, body)) =>
+ // process all classes in the package again to add static initializers
+ clearStatics()
+
+ addStaticDeclarations(t, clsdef.symbol)
+
+ val templ = deriveTemplate(t)(_ => transformTrees(newStaticMembers.toList) ::: body)
+ val ntempl =
+ try addStaticInits(templ)
+ finally clearStatics()
+
+ val derived = deriveClassDef(clsdef)(_ => ntempl)
+ classNames.remove(clsdef.symbol)
+ derived
+
+ case stat => stat
+ }
+ }
+
} // CleanUpTransformer
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index e5119eac71..70bd0bd21b 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -186,12 +186,15 @@ abstract class Constructors extends Transform with ast.TreeDSL {
// before the superclass constructor call, otherwise it goes after.
// Lazy vals don't get the assignment in the constructor.
if (!stat.symbol.tpe.isInstanceOf[ConstantType]) {
- if (rhs != EmptyTree && !stat.symbol.isLazy) {
+ if (stat.symbol.hasStaticAnnotation) {
+ debuglog("@static annotated field initialization skipped.")
+ defBuf += deriveValDef(stat)(tree => tree)
+ } else if (rhs != EmptyTree && !stat.symbol.isLazy) {
val rhs1 = intoConstructor(stat.symbol, rhs);
(if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign(
stat.symbol, rhs1)
+ defBuf += deriveValDef(stat)(_ => EmptyTree)
}
- defBuf += deriveValDef(stat)(_ => EmptyTree)
}
case ClassDef(_, _, _, _) =>
// classes are treated recursively, and left in the template
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index ab7bbc591b..afbe528b1f 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -46,10 +46,13 @@ abstract class ExplicitOuter extends InfoTransform
private def haveSameOuter(parent: Type, clazz: Symbol) = parent match {
case TypeRef(pre, sym, _) =>
val owner = clazz.owner
+
+ //println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre")
sym.isClass && owner.isClass &&
- owner == sym.owner &&
+ (owner isSubClass sym.owner) &&
owner.thisType =:= pre
+
case _ => false
}
@@ -480,7 +483,7 @@ abstract class ExplicitOuter extends InfoTransform
val vparamss1 =
if (isInner(clazz)) { // (4)
val outerParam =
- sym.newValueParameter(nme.OUTER, sym.pos) setInfo outerField(clazz).info
+ sym.newValueParameter(nme.OUTER, sym.pos) setInfo clazz.outerClass.thisType
((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail
} else vparamss
super.transform(copyDefDef(tree)(vparamss = vparamss1))
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index b54f127417..43edad3576 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -54,6 +54,25 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
import debugging.patmatDebug
+ // to govern how much time we spend analyzing matches for unreachability/exhaustivity
+ object AnalysisBudget {
+ import scala.tools.cmd.FromString.IntFromString
+ val max = sys.props.get("scalac.patmat.analysisBudget").collect(IntFromString.orElse{case "off" => Integer.MAX_VALUE}).getOrElse(256)
+
+ abstract class Exception extends RuntimeException("CNF budget exceeded") {
+ val advice: String
+ def warn(pos: Position, kind: String) = currentUnit.uncheckedWarning(pos, s"Cannot check match for $kind.\n$advice")
+ }
+
+ object exceeded extends Exception {
+ val advice = s"(The analysis required more space than allowed. Please try with scalac -Dscalac.patmat.analysisBudget=${AnalysisBudget.max*2} or -Dscalac.patmat.analysisBudget=off.)"
+ }
+
+ object stackOverflow extends Exception {
+ val advice = "(There was a stack overflow. Please try increasing the stack available to the compiler using e.g., -Xss2m.)"
+ }
+ }
+
def newTransformer(unit: CompilationUnit): Transformer =
if (opt.virtPatmat) new MatchTransformer(unit)
else noopTransformer
@@ -422,7 +441,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
The pattern matches any value v such that r == v (ยง12.1).
The type of r must conform to the expected type of the pattern.
**/
- case Literal(Constant(_)) | Ident(_) | Select(_, _) =>
+ case Literal(Constant(_)) | Ident(_) | Select(_, _) | This(_) =>
noFurtherSubPats(EqualityTestTreeMaker(patBinder, patTree, pos))
case Alternative(alts) =>
@@ -439,7 +458,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("WARNING: Bind tree with unbound symbol "+ patTree)
noFurtherSubPats() // there's no symbol -- something's wrong... don't fail here though (or should we?)
- // case Star(_) | ArrayValue | This => error("stone age pattern relics encountered!")
+ // case Star(_) | ArrayValue => error("stone age pattern relics encountered!")
case _ =>
error("unsupported pattern: "+ patTree +"(a "+ patTree.getClass +")")
@@ -1946,14 +1965,14 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
type Formula
def andFormula(a: Formula, b: Formula): Formula
- class CNFBudgetExceeded extends RuntimeException("CNF budget exceeded")
- // may throw an CNFBudgetExceeded
- def propToSolvable(p: Prop) = {
+ // may throw an AnalysisBudget.Exception
+ def propToSolvable(p: Prop): Formula = {
val (eqAxioms, pure :: Nil) = removeVarEq(List(p), modelNull = false)
eqFreePropToSolvable(And(eqAxioms, pure))
}
+ // may throw an AnalysisBudget.Exception
def eqFreePropToSolvable(p: Prop): Formula
def cnfString(f: Formula): String
@@ -1979,7 +1998,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
type Lit
def Lit(sym: Sym, pos: Boolean = true): Lit
- // throws an CNFBudgetExceeded when the prop results in a CNF that's too big
+ // throws an AnalysisBudget.Exception when the prop results in a CNF that's too big
def eqFreePropToSolvable(p: Prop): Formula = {
// TODO: for now, reusing the normalization from DPLL
def negationNormalForm(p: Prop): Prop = p match {
@@ -2001,9 +2020,9 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
def lit(s: Sym) = formula(clause(Lit(s)))
def negLit(s: Sym) = formula(clause(Lit(s, false)))
- def conjunctiveNormalForm(p: Prop, budget: Int = 256): Formula = {
+ def conjunctiveNormalForm(p: Prop, budget: Int = AnalysisBudget.max): Formula = {
def distribute(a: Formula, b: Formula, budget: Int): Formula =
- if (budget <= 0) throw new CNFBudgetExceeded
+ if (budget <= 0) throw AnalysisBudget.exceeded
else
(a, b) match {
// true \/ _ = true
@@ -2018,7 +2037,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
big flatMap (c => distribute(formula(c), small, budget - (big.size*small.size)))
}
- if (budget <= 0) throw new CNFBudgetExceeded
+ if (budget <= 0) throw AnalysisBudget.exceeded
p match {
case True => TrueF
@@ -2037,9 +2056,17 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
val start = Statistics.startTimer(patmatCNF)
- val res = conjunctiveNormalForm(negationNormalForm(p))
+ val res =
+ try {
+ conjunctiveNormalForm(negationNormalForm(p))
+ } catch { case ex : StackOverflowError =>
+ throw AnalysisBudget.stackOverflow
+ }
+
Statistics.stopTimer(patmatCNF, start)
- patmatCNFSizes(res.size).value += 1
+
+ //
+ if (Statistics.enabled) patmatCNFSizes(res.size).value += 1
// patmatDebug("cnf for\n"+ p +"\nis:\n"+cnfString(res))
res
@@ -2440,6 +2467,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// right now hackily implement this by pruning counter-examples
// unreachability would also benefit from a more faithful representation
+
// reachability (dead code)
// computes the first 0-based case index that is unreachable (if any)
@@ -2508,9 +2536,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
if (reachable) None else Some(caseIndex)
} catch {
- case e : CNFBudgetExceeded =>
-// debugWarn(util.Position.formatMessage(prevBinder.pos, "Cannot check match for reachability", false))
-// e.printStackTrace()
+ case ex: AnalysisBudget.Exception =>
+ ex.warn(prevBinder.pos, "unreachability")
None // CNF budget exceeded
}
}
@@ -2651,9 +2678,8 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
Statistics.stopTimer(patmatAnaExhaust, start)
pruned
} catch {
- case e : CNFBudgetExceeded =>
- patmatDebug(util.Position.formatMessage(prevBinder.pos, "Cannot check match for exhaustivity", false))
- // e.printStackTrace()
+ case ex : AnalysisBudget.Exception =>
+ ex.warn(prevBinder.pos, "exhaustivity")
Nil // CNF budget exceeded
}
}
diff --git a/src/library/scala/annotation/static.scala b/src/library/scala/annotation/static.scala
new file mode 100644
index 0000000000..f2955c756c
--- /dev/null
+++ b/src/library/scala/annotation/static.scala
@@ -0,0 +1,20 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.annotation
+
+/**
+ * An annotation that marks a member in the companion object as static
+ * and ensures that the compiler generates static fields/methods for it.
+ * This is important for Java interoperability and performance reasons.
+ *
+ * @since 2.10
+ */
+final class static extends StaticAnnotation {
+ // TODO document exact semantics above!
+}
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index a6488b602f..a2ef42fac8 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -18,41 +18,6 @@ package object concurrent {
type CancellationException = java.util.concurrent.CancellationException
type TimeoutException = java.util.concurrent.TimeoutException
- @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
- sealed trait CanAwait
- private implicit object AwaitPermission extends CanAwait
-
- /**
- * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances.
- */
- object Await {
- /**
- * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * ready() blocks until the awaitable has completed or the timeout expires.
- *
- * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`.
- * @param awaitable the `Awaitable` on which `ready` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.ready` which is defined to be the awaitable itself.
- */
- @throws(classOf[TimeoutException])
- def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type =
- blocking(awaitable.ready(atMost))
-
- /**
- * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
- * result() blocks until the awaitable has completed or the timeout expires.
- *
- * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`.
- * @param awaitable the `Awaitable` on which `result` is to be called
- * @param atMost the maximum timeout for which to wait
- * @return the result of `awaitable.result`
- */
- @throws(classOf[Exception])
- def result[T](awaitable: Awaitable[T], atMost: Duration): T =
- blocking(awaitable.result(atMost))
- }
-
/** Starts an asynchronous computation and returns a `Future` object with the result of that computation.
*
* The result becomes available once the asynchronous computation is completed.
@@ -85,5 +50,46 @@ package object concurrent {
* - TimeoutException - in the case that the blockable object timed out
*/
@throws(classOf[Exception])
- def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)
+ def blocking[T](body: =>T): T = BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission)
+}
+
+package concurrent {
+ @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
+ sealed trait CanAwait
+
+ /**
+ * Internal usage only, implementation detail.
+ */
+ private[concurrent] object AwaitPermission extends CanAwait
+
+ /**
+ * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances.
+ */
+ object Await {
+ /**
+ * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
+ * ready() blocks until the awaitable has completed or the timeout expires.
+ *
+ * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`.
+ * @param awaitable the `Awaitable` on which `ready` is to be called
+ * @param atMost the maximum timeout for which to wait
+ * @return the result of `awaitable.ready` which is defined to be the awaitable itself.
+ */
+ @throws(classOf[TimeoutException])
+ def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type =
+ blocking(awaitable.ready(atMost)(AwaitPermission))
+
+ /**
+ * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`.
+ * result() blocks until the awaitable has completed or the timeout expires.
+ *
+ * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`.
+ * @param awaitable the `Awaitable` on which `result` is to be called
+ * @param atMost the maximum timeout for which to wait
+ * @return the result of `awaitable.result`
+ */
+ @throws(classOf[Exception])
+ def result[T](awaitable: Awaitable[T], atMost: Duration): T =
+ blocking(awaitable.result(atMost)(AwaitPermission))
+ }
}
diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala
index 4e7f36bdc9..5b4e1b4b25 100644
--- a/src/partest/scala/tools/partest/DirectTest.scala
+++ b/src/partest/scala/tools/partest/DirectTest.scala
@@ -38,7 +38,8 @@ abstract class DirectTest extends App {
// new compiler
def newCompiler(args: String*): Global = {
val settings = newSettings((CommandLineParser tokenize extraSettings) ++ args.toList)
- new Global(settings)
+ if (settings.Yrangepos.value) new Global(settings) with interactive.RangePositions
+ else new Global(settings)
}
def newSources(sourceCodes: String*) = sourceCodes.toList.zipWithIndex map {
case (src, idx) => new BatchSourceFile("newSource" + (idx + 1), src)
@@ -69,7 +70,7 @@ abstract class DirectTest extends App {
/** Constructor/main body **/
try show()
- catch { case t => println(t) ; t.printStackTrace ; sys.exit(1) }
+ catch { case t => println(t.getMessage) ; t.printStackTrace ; sys.exit(1) }
/** Debugger interest only below this line **/
protected def isDebug = (sys.props contains "partest.debug") || (sys.env contains "PARTEST_DEBUG")
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7284a199b7..d9b63529eb 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -898,6 +898,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val SwitchClass = requiredClass[scala.annotation.switch]
lazy val TailrecClass = requiredClass[scala.annotation.tailrec]
lazy val VarargsClass = requiredClass[scala.annotation.varargs]
+ lazy val StaticClass = requiredClass[scala.annotation.static]
lazy val uncheckedStableClass = requiredClass[scala.annotation.unchecked.uncheckedStable]
lazy val uncheckedVarianceClass = requiredClass[scala.annotation.unchecked.uncheckedVariance]
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index e5d0e96d9c..75962ff9d0 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -246,6 +246,7 @@ trait StdNames {
final val BeanPropertyAnnot: NameType = "BeanProperty"
final val BooleanBeanPropertyAnnot: NameType = "BooleanBeanProperty"
final val bridgeAnnot: NameType = "bridge"
+ final val staticAnnot: NameType = "static"
// Classfile Attributes
final val AnnotationDefaultATTR: NameType = "AnnotationDefault"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d484617767..10d02376b1 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -933,6 +933,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
|| hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated
)
def hasBridgeAnnotation = hasAnnotation(BridgeClass)
+ def hasStaticAnnotation = hasAnnotation(StaticClass)
def isDeprecated = hasAnnotation(DeprecatedAttr)
def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0)
def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1)
diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala
index 7c80ddd37d..df4a3336c3 100644
--- a/src/reflect/scala/reflect/internal/util/SourceFile.scala
+++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala
@@ -102,17 +102,21 @@ class ScriptSourceFile(underlying: BatchSourceFile, content: Array[Char], overri
}
/** a file whose contents do not change over time */
-class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends SourceFile {
-
+class BatchSourceFile(val file : AbstractFile, val content0: Array[Char]) extends SourceFile {
def this(_file: AbstractFile) = this(_file, _file.toCharArray)
def this(sourceName: String, cs: Seq[Char]) = this(new VirtualFile(sourceName), cs.toArray)
def this(file: AbstractFile, cs: Seq[Char]) = this(file, cs.toArray)
- override def equals(that : Any) = that match {
- case that : BatchSourceFile => file.path == that.file.path && start == that.start
- case _ => false
- }
- override def hashCode = file.path.## + start.##
+ // If non-whitespace tokens run all the way up to EOF,
+ // positions go wrong because the correct end of the last
+ // token cannot be used as an index into the char array.
+ // The least painful way to address this was to add a
+ // newline to the array.
+ val content = (
+ if (content0.length == 0 || !content0.last.isWhitespace)
+ content0 :+ '\n'
+ else content0
+ )
val length = content.length
def start = 0
def isSelfContained = true
@@ -158,4 +162,10 @@ class BatchSourceFile(val file : AbstractFile, val content: Array[Char]) extends
lastLine = findLine(0, lines.length, lastLine)
lastLine
}
+
+ override def equals(that : Any) = that match {
+ case that : BatchSourceFile => file.path == that.file.path && start == that.start
+ case _ => false
+ }
+ override def hashCode = file.path.## + start.##
}
diff --git a/src/reflect/scala/tools/nsc/io/VirtualFile.scala b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
index b9a946598c..805bc04165 100644
--- a/src/reflect/scala/tools/nsc/io/VirtualFile.scala
+++ b/src/reflect/scala/tools/nsc/io/VirtualFile.scala
@@ -55,7 +55,7 @@ class VirtualFile(val name: String, override val path: String) extends AbstractF
}
}
- def container: AbstractFile = unsupported
+ def container: AbstractFile = NoAbstractFile
/** Is this abstract file a directory? */
def isDirectory: Boolean = false
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index 1209b710b0..43d4c9dc71 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -700,9 +700,18 @@ trait Blocking extends TestBase {
}
}
+ def testFQCNForAwaitAPI(): Unit = once {
+ done =>
+
+ assert(classOf[CanAwait].getName == "scala.concurrent.CanAwait")
+ assert(Await.getClass.getName == "scala.concurrent.Await")
+
+ done()
+ }
+
testAwaitSuccess()
testAwaitFailure()
-
+ testFQCNForAwaitAPI()
}
trait BlockContexts extends TestBase {
diff --git a/test/files/neg/static-annot.check b/test/files/neg/static-annot.check
new file mode 100644
index 0000000000..66efebdcee
--- /dev/null
+++ b/test/files/neg/static-annot.check
@@ -0,0 +1,19 @@
+static-annot.scala:8: error: Only members of top-level objects and their nested objects can be annotated with @static.
+ @static val bar = 1
+ ^
+static-annot.scala:27: error: @static annotated field bar has the same name as a member of class Conflicting
+ @static val bar = 1
+ ^
+static-annot.scala:37: error: The @static annotation is only allowed on public members.
+ @static private val bar = 1
+ ^
+static-annot.scala:38: error: The @static annotation is only allowed on public members.
+ @static private val baz = 2
+ ^
+static-annot.scala:39: error: The @static annotation is not allowed on lazy members.
+ @static lazy val bam = 3
+ ^
+static-annot.scala:14: error: Only members of top-level objects and their nested objects can be annotated with @static.
+ @static val blah = 2
+ ^
+6 errors found \ No newline at end of file
diff --git a/test/files/neg/static-annot.scala b/test/files/neg/static-annot.scala
new file mode 100644
index 0000000000..c6c626d42b
--- /dev/null
+++ b/test/files/neg/static-annot.scala
@@ -0,0 +1,47 @@
+
+
+import annotation.static
+
+
+
+class StaticInClass {
+ @static val bar = 1
+}
+
+
+class NestedObjectInClass {
+ object Nested {
+ @static val blah = 2
+ }
+}
+
+
+object NestedObjectInObject {
+ object Nested {
+ @static val succeed = 3
+ }
+}
+
+
+object Conflicting {
+ @static val bar = 1
+}
+
+
+class Conflicting {
+ val bar = 45
+}
+
+
+object PrivateProtectedLazy {
+ @static private val bar = 1
+ @static private val baz = 2
+ @static lazy val bam = 3
+}
+
+
+class PrivateProtectedLazy {
+ println(PrivateProtectedLazy.bar)
+ println(PrivateProtectedLazy.baz)
+ println(PrivateProtectedLazy.bam)
+}
diff --git a/test/files/neg/t4069.check b/test/files/neg/t4069.check
index 91bf882cec..08e937bdfe 100644
--- a/test/files/neg/t4069.check
+++ b/test/files/neg/t4069.check
@@ -12,5 +12,5 @@ t4069.scala:4: error: I encountered a '}' where I didn't expect one, maybe this
^
t4069.scala:10: error: '}' expected but eof found.
}
-^
+ ^
5 errors found
diff --git a/test/files/neg/t4584.check b/test/files/neg/t4584.check
index 060160d76a..419f5704b1 100644
--- a/test/files/neg/t4584.check
+++ b/test/files/neg/t4584.check
@@ -1,4 +1,7 @@
-t4584.scala:1: error: incomplete unicode escape
+t4584.scala:1: error: error in unicode escape
+class A { val /u2
+ ^
+t4584.scala:1: error: illegal character '/uffff'
class A { val /u2
^
-one error found
+two errors found
diff --git a/test/files/neg/unicode-unterminated-quote.check b/test/files/neg/unicode-unterminated-quote.check
index fc5caa6d7e..5085505fb4 100644
--- a/test/files/neg/unicode-unterminated-quote.check
+++ b/test/files/neg/unicode-unterminated-quote.check
@@ -1,4 +1,7 @@
unicode-unterminated-quote.scala:2: error: unclosed string literal
val x = /u0022
^
-one error found
+unicode-unterminated-quote.scala:2: error: '}' expected but eof found.
+ val x = /u0022
+ ^
+two errors found
diff --git a/test/files/pos/t5957/T_1.scala b/test/files/pos/t5957/T_1.scala
index 1db5a3891f..339dcbf0f0 100644
--- a/test/files/pos/t5957/T_1.scala
+++ b/test/files/pos/t5957/T_1.scala
@@ -1,6 +1,8 @@
abstract class T {
- def t1: Test$Bar
+ // see: SI-6109
+ // def t1: Test$Bar
def t2: Test#Bar
- def t3: Test$Baz
+ // see: SI-6109
+ // def t3: Test$Baz
def t4: Test.Baz
}
diff --git a/test/files/run/outertest.scala b/test/files/run/outertest.scala
new file mode 100644
index 0000000000..3cc96afa5b
--- /dev/null
+++ b/test/files/run/outertest.scala
@@ -0,0 +1,26 @@
+// A test for the case where the outer field of class B#J should be eliminated.
+// You can verify this by running a javap on B.J
+abstract class A {
+
+ abstract class I {
+
+ }
+
+ val foo = "foo"
+
+}
+
+class B extends A {
+
+ class J extends I {
+ val bar = foo
+ }
+
+}
+
+object Test extends App {
+
+ val b = new B
+ assert((new b.J).bar == b.foo)
+
+}
diff --git a/test/files/run/static-annot/field.scala b/test/files/run/static-annot/field.scala
new file mode 100644
index 0000000000..a7d8158321
--- /dev/null
+++ b/test/files/run/static-annot/field.scala
@@ -0,0 +1,243 @@
+
+
+
+import java.lang.reflect.Modifier
+import annotation.static
+import reflect._
+
+
+
+/* TEST 1 */
+
+/* A @static-annotated field in the companion object should yield
+ * a static field in its companion class.
+ */
+object Foo {
+ @static val bar = 17
+}
+
+
+class Foo
+
+
+trait Check {
+ def checkStatic(cls: Class[_]) {
+ cls.getDeclaredFields.find(_.getName == "bar") match {
+ case Some(f) => assert(Modifier.isStatic(f.getModifiers), "no static modifier")
+ case None => assert(false, "no static field bar in class")
+ }
+ }
+
+ def test(): Unit
+}
+
+
+object Test1 extends Check {
+ def test() {
+ checkStatic(classOf[Foo])
+ assert(Foo.bar == 17, "Companion object field should be 17.")
+ }
+}
+
+
+/* TEST 2 */
+
+class Foo2
+
+
+/** The order of declaring the class and its companion is inverted now. */
+object Foo2 {
+ @static val bar = 199
+}
+
+
+object Test2 extends Check {
+ def test() {
+ checkStatic(Class.forName("Foo3"))
+ assert(Foo3.bar == 1984, "Companion object field should be 1984.")
+ }
+}
+
+
+/* TEST 3 */
+
+/** The case where there is no explicit companion class */
+object Foo3 {
+ @static val bar = 1984
+}
+
+
+object Test3 extends Check {
+ def test() {
+ checkStatic(Class.forName("Foo3"))
+ assert(Foo3.bar == 1984, "Companion object field should be 1984.")
+ }
+}
+
+
+/* TEST 4 */
+
+/** We want to be able to generate atomic reference field updaters on the companion object
+ * so that they are created only once per class declaration, but we want them to actually
+ * be initialize __in the static initializer of the class itself__.
+ * This is extremely important, because otherwise the creation of the ARFU fails, since it uses
+ * trickery to detect the caller and compare it to the owner of the field being modified.
+ * Previously, this used to be circumvented through the use of Java base classes. A pain.
+ */
+class ArfuTarget {
+ @volatile var strfield = ArfuTarget.STR
+
+ def CAS(ov: String, nv: String): Boolean = {
+ ArfuTarget.arfu.compareAndSet(this, ov, nv)
+ }
+}
+
+
+object ArfuTarget {
+ @static val arfu = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(classOf[ArfuTarget], classOf[String], "strfield")
+ val STR = "Some string"
+}
+
+
+object Test4 extends Check {
+ def checkArfu() {
+ val at = new ArfuTarget
+ assert(at.strfield == ArfuTarget.STR)
+ at.CAS(ArfuTarget.STR, null)
+ assert(at.strfield == null)
+ }
+
+ def test() {
+ checkArfu()
+ }
+}
+
+
+/* TEST 5 */
+
+/** Although our main use-case is to use final static fields, we should be able to use non-final too.
+ * Here we set the static field of the class by using the setters in the companion object.
+ * It is legal to do so using the reference to `Foo` directly (in which case the callsites
+ * are rewritten to access the static field directly), or through an interface `Var` (in
+ * which case the getter and the setter for `field` access the static field in `Var`).
+ */
+trait Var {
+ var field: Int
+}
+
+object VarHolder extends Var {
+ @static var field = 1
+}
+
+
+object Test5 extends Check {
+ def test() {
+ assert(VarHolder.field == 1)
+ VarHolder.field = 2
+ assert(VarHolder.field == 2)
+ val vh: Var = VarHolder
+ vh.field = 3
+ assert(vh.field == 3)
+ }
+}
+
+
+/* TEST 6 */
+
+/** Here we test flattening the static ctor body and changing the owners of local definitions. */
+object Foo6 {
+ var companionField = 101
+ @static val staticField = {
+ val intermediate = companionField + 1
+ intermediate * 2
+ }
+}
+
+
+object Test6 extends Check {
+ def test() {
+ assert(Foo6.staticField == 204)
+ }
+}
+
+
+
+/* TEST 7 */
+
+/** Here we test objects nested in top-level objects */
+object Foo7 {
+ object AndHisFriend {
+ @static val bar = "string"
+ }
+ class AndHisFriend
+}
+
+
+object Test7 extends Check {
+ def test() {
+ checkStatic(classOf[Foo7.AndHisFriend])
+ assert(Foo7.AndHisFriend.bar == "string")
+ }
+}
+
+
+
+/* TEST 8 */
+
+object Foo8 {
+ @static val field = 7
+
+ val function: () => Int = () => {
+ field + 1
+ }
+
+ val anon = new Runnable {
+ def run() {
+ assert(field == 7, "runnable asserting field is 7")
+ }
+ }
+
+ @static var mutable = 10
+
+ val mutation: () => Unit = () => {
+ mutable += 1
+ }
+}
+
+object Test8 {
+ def test() {
+ assert(Foo8.function() == 8, "function must return 8")
+ Foo8.anon.run()
+ assert(Foo8.mutable == 10, "mutable is 10")
+ Foo8.mutation()
+ assert(Foo8.mutable == 11, "mutable is 11")
+ Foo8.mutation()
+ assert(Foo8.mutable == 12, "mutable is 12")
+ }
+}
+
+
+
+
+/* main */
+
+object Test {
+
+ def main(args: Array[String]) {
+ Test1.test()
+ Test2.test()
+ Test3.test()
+ Test4.test()
+ Test5.test()
+ Test6.test()
+ Test7.test()
+ Test8.test()
+ }
+
+}
+
+
+
+
+
+
diff --git a/test/files/run/t5385.check b/test/files/run/t5385.check
new file mode 100644
index 0000000000..1df74fcfb5
--- /dev/null
+++ b/test/files/run/t5385.check
@@ -0,0 +1,8 @@
+[0:9] class Azz
+[0:9] class Bzz
+[0:9] class Czz
+[0:9] class Dzz
+[0:11] class Ezz
+[0:11] class Fzz
+[0:13] class Gzz
+[0:13] class Hzz
diff --git a/test/files/run/t5385.scala b/test/files/run/t5385.scala
new file mode 100644
index 0000000000..b803897e71
--- /dev/null
+++ b/test/files/run/t5385.scala
@@ -0,0 +1,16 @@
+import scala.tools.partest._
+
+object Test extends CompilerTest {
+ import global._
+ override def extraSettings = super.extraSettings + " -Yrangepos"
+ override def sources = List(
+ "class Azz", "class Bzz ", "class Czz ", "class Dzz\n",
+ "class Ezz{}", "class Fzz{} ", "class Gzz { }", "class Hzz { } "
+ )
+ def check(source: String, unit: CompilationUnit) {
+ unit.body foreach {
+ case cdef: ClassDef => println("%-15s class %s".format(cdef.pos.show, cdef.name))
+ case _ =>
+ }
+ }
+}
diff --git a/test/files/run/t6104.check b/test/files/run/t6104.check
new file mode 100644
index 0000000000..9766475a41
--- /dev/null
+++ b/test/files/run/t6104.check
@@ -0,0 +1 @@
+ok
diff --git a/test/files/run/t6104.scala b/test/files/run/t6104.scala
new file mode 100644
index 0000000000..8ab12c7752
--- /dev/null
+++ b/test/files/run/t6104.scala
@@ -0,0 +1,8 @@
+class A { Self =>
+ val ok = "ok"
+ this match {
+ case me@Self => println(me.ok)
+ }
+}
+
+object Test extends A with App \ No newline at end of file