summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-01-25 16:39:39 -0800
committerPaul Phillips <paulp@improving.org>2013-01-25 18:16:40 -0800
commitcc067e6508546d3b830422d57034210489a54151 (patch)
treeb5dd29c21822f4dd6d3064dc1a734a45ca3a712c /src
parent5abf901ea347fc0319c6a191454211f704d04961 (diff)
parent2fa859e1b3eb2ac57058feaba87d96adfbac9209 (diff)
downloadscala-cc067e6508546d3b830422d57034210489a54151.tar.gz
scala-cc067e6508546d3b830422d57034210489a54151.tar.bz2
scala-cc067e6508546d3b830422d57034210489a54151.zip
Merge remote-tracking branch 'origin/2.10.x' into pr/merge-2.10
* origin/2.10.x: SI-6969, mishandling of SoftReferences in method cache. SI-7011 Fix finding constructor type in captured var definitions SI-6987 Tests fsc verbose output SI-6987 Fixes fsc compile server verbose output SI-6231 Report unsupported free var capture by a trait. SI-6666 Restrict hidden `this` access in self/super calls. SI-6902 Check unreachability under @unchecked SI-6976 Fix value class separate compilation crasher. Closes SI-6952: add correct error positions for Dynamic feature check. Conflicts: src/compiler/scala/tools/nsc/CompileServer.scala src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala40
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala26
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala12
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala45
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala19
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala6
-rw-r--r--src/compiler/scala/tools/util/SocketServer.scala4
8 files changed, 119 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index e4c250a3d9..72e8cc69c7 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -87,10 +87,11 @@ class StandardCompileServer extends SocketServer {
val args = input.split("\0", -1).toList
val newSettings = new FscSettings(fscError)
- this.verbose = newSettings.verbose.value
val command = new OfflineCompilerCommand(args, newSettings)
+ this.verbose = newSettings.verbose.value
info("Settings after normalizing paths: " + newSettings)
+ if (!command.files.isEmpty) info("Input files after normalizing paths: " + (command.files mkString ","))
printMemoryStats()
// Update the idle timeout if given
@@ -168,11 +169,22 @@ object CompileServer extends StandardCompileServer {
/** A directory holding redirected output */
private lazy val redirectDir = (compileSocket.tmpDir / "output-redirects").createDirectory()
- private def redirect(setter: PrintStream => Unit, filename: String) {
- setter(new PrintStream((redirectDir / filename).createFile().bufferedOutput()))
- }
+ private def createRedirect(filename: String) =
+ new PrintStream((redirectDir / filename).createFile().bufferedOutput())
+
+ def main(args: Array[String]) =
+ execute(() => (), args)
- def main(args: Array[String]) {
+ /**
+ * Used for internal testing. The callback is called upon
+ * server start, notifying the caller that the server is
+ * ready to run. WARNING: the callback runs in the
+ * server's thread, blocking the server from doing any work
+ * until the callback is finished. Callbacks should be kept
+ * simple and clients should not try to interact with the
+ * server while the callback is processing.
+ */
+ def execute(startupCallback : () => Unit, args: Array[String]) {
val debug = args contains "-v"
if (debug) {
@@ -180,14 +192,16 @@ object CompileServer extends StandardCompileServer {
echo("Redirect dir is " + redirectDir)
}
- redirect(System.setOut, "scala-compile-server-out.log")
- redirect(System.setErr, "scala-compile-server-err.log")
- System.err.println("...starting server on socket "+port+"...")
- System.err.flush()
- compileSocket setPort port
- run()
+ Console.withErr(createRedirect("scala-compile-server-err.log")) {
+ Console.withOut(createRedirect("scala-compile-server-out.log")) {
+ Console.err.println("...starting server on socket "+port+"...")
+ Console.err.flush()
+ compileSocket setPort port
+ startupCallback()
+ run()
- compileSocket deletePort port
- sys exit 0
+ compileSocket deletePort port
+ }
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 39460ef004..f5c8907991 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -201,12 +201,17 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
var reflPoly$Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache())
def reflMethod$Method(forReceiver: JClass[_]): JMethod = {
- var method: JMethod = reflPoly$Cache.find(forReceiver)
- if (method != null)
+ var methodCache: MethodCache = reflPoly$Cache.find(forReceiver)
+ if (methodCache eq null) {
+ methodCache = new EmptyMethodCache
+ reflPoly$Cache = new SoftReference(methodCache)
+ }
+ var method: JMethod = methodCache.find(forReceiver)
+ if (method ne null)
return method
else {
method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache))
- reflPoly$Cache = new SoftReference(reflPoly$Cache.get.add(forReceiver, method))
+ reflPoly$Cache = new SoftReference(methodCache.add(forReceiver, method))
return method
}
}
@@ -223,16 +228,22 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def getPolyCache = gen.mkCast(fn(REF(reflPolyCacheSym), nme.get), MethodCacheClass.tpe)
addStaticMethodToClass((reflMethodSym, forReceiverSym) => {
+ val methodCache = reflMethodSym.newVariable(mkTerm("methodCache"), ad.pos) setInfo MethodCacheClass.tpe
val methodSym = reflMethodSym.newVariable(mkTerm("method"), ad.pos) setInfo MethodClass.tpe
BLOCK(
- IF (getPolyCache OBJ_EQ NULL) THEN (REF(reflPolyCacheSym) === mkNewPolyCache) ENDIF,
- VAL(methodSym) === ((getPolyCache DOT methodCache_find)(REF(forReceiverSym))) ,
- IF (REF(methodSym) OBJ_!= NULL) .
+ VAL(methodCache) === getPolyCache,
+ IF (REF(methodCache) OBJ_EQ NULL) THEN BLOCK(
+ REF(methodCache) === NEW(TypeTree(EmptyMethodCacheClass.tpe)),
+ REF(reflPolyCacheSym) === gen.mkSoftRef(REF(methodCache))
+ ) ENDIF,
+
+ VAL(methodSym) === (REF(methodCache) DOT methodCache_find)(REF(forReceiverSym)),
+ IF (REF(methodSym) OBJ_NE NULL) .
THEN (Return(REF(methodSym)))
ELSE {
def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym)))
- def cacheRHS = ((getPolyCache DOT methodCache_add)(REF(forReceiverSym), REF(methodSym)))
+ def cacheRHS = ((REF(methodCache) DOT methodCache_add)(REF(forReceiverSym), REF(methodSym)))
BLOCK(
REF(methodSym) === (REF(ensureAccessibleMethod) APPLY (methodSymRHS)),
REF(reflPolyCacheSym) === gen.mkSoftRef(cacheRHS),
@@ -241,6 +252,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
)
})
+
}
/* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */
diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
index 77e7e013ab..12933af138 100644
--- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala
@@ -60,14 +60,18 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
}
}
- /** Return the extension method that corresponds to given instance method `meth`.
- */
+ private def companionModuleForce(sym: Symbol) = {
+ sym.andAlso(_.owner.initialize) // See SI-6976. `companionModule` only calls `rawInfo`. (Why?)
+ sym.companionModule
+ }
+
+ /** Return the extension method that corresponds to given instance method `meth`. */
def extensionMethod(imeth: Symbol): Symbol = enteringPhase(currentRun.refchecksPhase) {
- val companionInfo = imeth.owner.companionModule.info
+ val companionInfo = companionModuleForce(imeth.owner).info
val candidates = extensionNames(imeth) map (companionInfo.decl(_)) filter (_.exists)
val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe)
assert(matching.nonEmpty,
- s"no extension method found for $imeth:${imeth.tpe} among ${candidates map (c => c.name+":"+c.tpe)} / ${extensionNames(imeth)}")
+ s"no extension method found for $imeth:${imeth.tpe} among ${candidates.map(c => c.name+":"+c.tpe).toList} / ${extensionNames(imeth).toList}")
matching.head
}
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index b081fb7e3f..f8172743b5 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -320,12 +320,24 @@ abstract class LambdaLift extends InfoTransform {
private def memberRef(sym: Symbol) = {
val clazz = sym.owner.enclClass
//Console.println("memberRef from "+currentClass+" to "+sym+" in "+clazz)
- val qual = if (clazz == currentClass) gen.mkAttributedThis(clazz)
- else {
- sym resetFlag(LOCAL | PRIVATE)
- if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
- else outerPath(outerValue, currentClass.outerClass, clazz)
- }
+ def prematureSelfReference() {
+ val what =
+ if (clazz.isStaticOwner) clazz.fullLocationString
+ else s"the unconstructed `this` of ${clazz.fullLocationString}"
+ val msg = s"Implementation restriction: access of ${sym.fullLocationString} from ${currentClass.fullLocationString}, would require illegal premature access to $what"
+ currentUnit.error(curTree.pos, msg)
+ }
+ val qual =
+ if (clazz == currentClass) gen.mkAttributedThis(clazz)
+ else {
+ sym resetFlag (LOCAL | PRIVATE)
+ if (selfOrSuperCalls exists (_.owner == clazz)) {
+ prematureSelfReference()
+ EmptyTree
+ }
+ else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
+ else outerPath(outerValue, currentClass.outerClass, clazz)
+ }
Select(qual, sym) setType sym.tpe
}
@@ -352,6 +364,7 @@ abstract class LambdaLift extends InfoTransform {
copyDefDef(tree)(vparamss = List(vparams ++ freeParams))
case ClassDef(_, _, _, _) =>
+ // SI-6231
// Disabled attempt to to add getters to freeParams
// this does not work yet. Problem is that local symbols need local names
// and references to local symbols need to be transformed into
@@ -369,7 +382,7 @@ abstract class LambdaLift extends InfoTransform {
tree
}
-/* Something like this will be necessary to eliminate the implementation
+/* SI-6231: Something like this will be necessary to eliminate the implementation
* restiction from paramGetter above:
* We need to pass getters to the interface of an implementation class.
private def fixTraitGetters(lifted: List[Tree]): List[Tree] =
@@ -430,10 +443,10 @@ abstract class LambdaLift extends InfoTransform {
/* Creating a constructor argument if one isn't present. */
val constructorArg = rhs match {
case EmptyTree =>
- sym.primaryConstructor.info.paramTypes match {
+ sym.tpe.typeSymbol.primaryConstructor.info.paramTypes match {
case List(tp) => gen.mkZero(tp)
case _ =>
- log("Couldn't determine how to properly construct " + sym)
+ debugwarn("Couldn't determine how to properly construct " + sym)
rhs
}
case arg => arg
@@ -495,13 +508,25 @@ abstract class LambdaLift extends InfoTransform {
private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe)
+ /** The stack of constructor symbols in which a call to this() or to the super
+ * constructor is active.
+ */
+ private val selfOrSuperCalls = mutable.Stack[Symbol]()
+ @inline private def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = try {
+ selfOrSuperCalls push sym
+ a
+ } finally selfOrSuperCalls.pop()
+
override def transform(tree: Tree): Tree = tree match {
case Select(ReferenceToBoxed(idt), elem) if elem == nme.elem =>
postTransform(preTransform(idt), isBoxedRef = false)
case ReferenceToBoxed(idt) =>
postTransform(preTransform(idt), isBoxedRef = true)
case _ =>
- postTransform(preTransform(tree))
+ def transformTree = postTransform(preTransform(tree))
+ if (treeInfo isSelfOrSuperConstrCall tree)
+ inSelfOrSuperCall(currentOwner)(transformTree)
+ else transformTree
}
/** Transform statements and add lifted definitions to them. */
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 6a253a98b1..3e5ac6922e 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -1214,9 +1214,24 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// refer to fields in some implementation class via an abstract
// getter in the interface.
val iface = toInterface(sym.owner.tpe).typeSymbol
- val getter = sym getter iface orElse abort("No getter for " + sym + " in " + iface)
+ val ifaceGetter = sym getter iface
+
+ def si6231Restriction() {
+ // See SI-6231 comments in LamdaLift for ideas on how to lift the restriction.
+ val msg = sm"""Implementation restriction: local ${iface.fullLocationString} is unable to automatically capture the
+ |free variable ${sym} on behalf of ${currentClass}. You can manually assign it to a val inside the trait,
+ |and refer that that val in ${currentClass}. For more details, see SI-6231."""
+ reporter.error(tree.pos, msg)
+ }
- typedPos(tree.pos)((qual DOT getter)())
+ if (ifaceGetter == NoSymbol) {
+ if (sym.isParamAccessor) {
+ si6231Restriction()
+ EmptyTree
+ }
+ else abort("No getter for " + sym + " in " + iface)
+ }
+ else typedPos(tree.pos)((qual DOT ifaceGetter)())
case Assign(Apply(lhs @ Select(qual, _), List()), rhs) =>
// assign to fields in some implementation class via an abstract
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index ec6a33519a..27bdad3066 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -3237,6 +3237,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// TODO: make more fine-grained, as we don't always need to jump
def canJump: Boolean
+ /** Should exhaustivity analysis be skipped? */
def unchecked: Boolean
@@ -3470,12 +3471,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
case Some(cds) => cds
}
- val allReachable = unchecked || {
- // a switch with duplicate cases yields a verify error,
- // and a switch with duplicate cases and guards cannot soundly be rewritten to an unguarded switch
- // (even though the verify error would disappear, the behaviour would change)
- unreachableCase(caseDefsWithGuards) map (cd => reportUnreachable(cd.body.pos)) isEmpty
- }
+ // a switch with duplicate cases yields a verify error,
+ // and a switch with duplicate cases and guards cannot soundly be rewritten to an unguarded switch
+ // (even though the verify error would disappear, the behaviour would change)
+ val allReachable = unreachableCase(caseDefsWithGuards) map (cd => reportUnreachable(cd.body.pos)) isEmpty
if (!allReachable) Nil
else if (noGuards(caseDefsWithGuards)) {
@@ -3718,10 +3717,10 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
with SymbolicMatchAnalysis
with DPLLSolver { self: TreeMakers =>
override def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): (List[List[TreeMaker]], List[Tree]) = {
+ unreachableCase(prevBinder, cases, pt) foreach { caseIndex =>
+ reportUnreachable(cases(caseIndex).last.pos)
+ }
if (!unchecked) {
- unreachableCase(prevBinder, cases, pt) foreach { caseIndex =>
- reportUnreachable(cases(caseIndex).last.pos)
- }
val counterExamples = exhaustive(prevBinder, cases, pt)
if (counterExamples.nonEmpty)
reportMissingCases(prevBinder.pos, counterExamples)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 8d028857d4..f2f8f47bf2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1698,8 +1698,8 @@ trait Typers extends Adaptations with Tags {
*/
def validateParentClasses(parents: List[Tree], selfType: Type) {
val pending = ListBuffer[AbsTypeError]()
- def validateDynamicParent(parent: Symbol) =
- if (parent == DynamicClass) checkFeature(parent.pos, DynamicsFeature)
+ def validateDynamicParent(parent: Symbol, parentPos: Position) =
+ if (parent == DynamicClass) checkFeature(parentPos, DynamicsFeature)
def validateParentClass(parent: Tree, superclazz: Symbol) =
if (!parent.isErrorTyped) {
@@ -1746,7 +1746,7 @@ trait Typers extends Adaptations with Tags {
if (parents exists (p => p != parent && p.tpe.typeSymbol == psym && !psym.isError))
pending += ParentInheritedTwiceError(parent, psym)
- validateDynamicParent(psym)
+ validateDynamicParent(psym, parent.pos)
}
if (!parents.isEmpty && parents.forall(!_.isErrorTyped)) {
diff --git a/src/compiler/scala/tools/util/SocketServer.scala b/src/compiler/scala/tools/util/SocketServer.scala
index d29a370c28..1b06ce2ff2 100644
--- a/src/compiler/scala/tools/util/SocketServer.scala
+++ b/src/compiler/scala/tools/util/SocketServer.scala
@@ -16,8 +16,8 @@ trait CompileOutputCommon {
def verbose: Boolean
def info(msg: String) = if (verbose) echo(msg)
- def echo(msg: String) = Console println msg
- def warn(msg: String) = System.err println msg
+ def echo(msg: String) = {Console println msg; Console.flush}
+ def warn(msg: String) = {Console.err println msg; Console.flush}
def fatal(msg: String) = { warn(msg) ; sys.exit(1) }
}