summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-10-31 08:26:18 -0700
committerPaul Phillips <paulp@improving.org>2012-10-31 08:49:56 -0700
commit1e1199d8abbd81ab2fa3b9cbab0290d6793e0945 (patch)
treebde1e98d0f4a060d14e6ce681366d82f533d0ceb /src
parentb480d991072e6e68ed46574d87e4483da778ff0e (diff)
downloadscala-1e1199d8abbd81ab2fa3b9cbab0290d6793e0945.tar.gz
scala-1e1199d8abbd81ab2fa3b9cbab0290d6793e0945.tar.bz2
scala-1e1199d8abbd81ab2fa3b9cbab0290d6793e0945.zip
Fix for -Xcheckinit failures.
The GenASM phase had an eager val which required loading a bunch of symbols, which meant an earlier call to isPastTyper could lead to a cycle of the form: new Run new GenASM rootMirror.getRequiredClass findMember defineBaseClassesOfCompoundType isPastTyper currentRun.typerPhase and the opening "new Run" hasn't yet caught up to where currentRun.typerPhase is set. This was remedied by making the eager val lazy, and substantially hardened against recurrence via a method on global "isGlobalInitialized" which verifies that both the definitions object and the root mirror have completed their init methods.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala10
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Mirrors.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala2
4 files changed, 16 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 40a14aec6f..5b5cffa885 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1046,9 +1046,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit
def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile
+ def isGlobalInitialized = (
+ definitions.isDefinitionsInitialized
+ && rootMirror.isMirrorInitialized
+ )
override def isPastTyper = (
(curRun ne null)
- && (currentRun.typerPhase ne null)
+ && isGlobalInitialized // defense against init order issues
&& (globalPhase.id > currentRun.typerPhase.id)
)
@@ -1525,9 +1529,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def compileUnits(units: List[CompilationUnit], fromPhase: Phase) {
try compileUnitsInternal(units, fromPhase)
catch { case ex: Throwable =>
- val shown = if (settings.verbose.value)
+ val shown = if (settings.verbose.value)
stackTraceString(ex)
- else
+ else
ex.getClass.getName
// ex.printStackTrace(Console.out) // DEBUG for fsc, note that error stacktraces do not print in fsc
globalError(supplementErrorMessage("uncaught exception during compilation: " + shown))
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 34d46e27fe..f4921e79e5 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -53,7 +53,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
override def erasedTypes = true
def apply(cls: IClass) = sys.error("no implementation")
- val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo")
+ // Lazy val; can't have eager vals in Phase constructors which may
+ // cause cycles before Global has finished initialization.
+ lazy val BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo")
def isJavaEntryPoint(icls: IClass) = {
val sym = icls.symbol
diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala
index 019cf7f908..d16374476a 100644
--- a/src/reflect/scala/reflect/internal/Mirrors.scala
+++ b/src/reflect/scala/reflect/internal/Mirrors.scala
@@ -20,6 +20,8 @@ trait Mirrors extends api.Mirrors {
trait RootSymbol extends Symbol { def mirror: Mirror }
abstract class RootsBase(rootOwner: Symbol) extends scala.reflect.api.Mirror[Mirrors.this.type] { thisMirror =>
+ private[this] var initialized = false
+ def isMirrorInitialized = initialized
protected[scala] def rootLoader: LazyType
@@ -229,6 +231,7 @@ trait Mirrors extends api.Mirrors {
// }
def init() {
+ if (initialized) return
// Still fiddling with whether it's cleaner to do some of this setup here
// or from constructors. The latter approach tends to invite init order issues.
@@ -240,6 +243,8 @@ trait Mirrors extends api.Mirrors {
RootClass.info.decls enter EmptyPackage
RootClass.info.decls enter RootPackage
+
+ initialized = true
}
}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 92db92d5f3..b6c67ad63e 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1728,7 +1728,7 @@ trait Types extends api.Types { self: SymbolTable =>
protected def defineBaseClassesOfCompoundType(tpe: CompoundType) {
def define = defineBaseClassesOfCompoundType(tpe, force = false)
- if (isPastTyper || !breakCycles) define
+ if (!breakCycles || isPastTyper) define
else tpe match {
// non-empty parents helpfully excludes all package classes
case tpe @ ClassInfoType(_ :: _, _, clazz) if !clazz.isAnonOrRefinementClass =>