diff options
9 files changed, 55 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index aba17ca290..f5e32fbb09 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -5,12 +5,20 @@ package scala.tools.nsc -import util.{ FreshNameCreator,Position,NoPosition,SourceFile } +import util.{ FreshNameCreator, Position, NoPosition, SourceFile, NoSourceFile } import scala.collection.mutable import scala.collection.mutable.{ LinkedHashSet, ListBuffer } trait CompilationUnits { self: Global => + /** An object representing a missing compilation unit. + */ + object NoCompilationUnit extends CompilationUnit(NoSourceFile) { + override lazy val isJava = false + override def exists = false + override def toString() = "NoCompilationUnit" + } + /** One unit of compilation that has been submitted to the compiler. * It typically corresponds to a single file of source code. It includes * error-reporting hooks. */ @@ -25,6 +33,8 @@ trait CompilationUnits { self: Global => /** the content of the compilation unit in tree form */ var body: Tree = EmptyTree + def exists = source != NoSourceFile && source != null + // def parseSettings() = { // val argsmarker = "SCALAC_ARGS" // if(comments nonEmpty) { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 76af2a7a03..75019f7624 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -48,7 +48,7 @@ abstract class GenICode extends SubComponent { override def description = "Generate ICode from the AST" - var unit: CompilationUnit = _ + var unit: CompilationUnit = NoCompilationUnit override def run() { scalaPrimitives.init @@ -61,7 +61,7 @@ abstract class GenICode extends SubComponent { unit.icode.clear informProgress("Generating icode for " + unit) gen(unit.body) - this.unit = null + this.unit = NoCompilationUnit } def gen(tree: Tree): Context = gen(tree, new Context()) diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index fc53a34c45..3d7d14627c 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -205,7 +205,7 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "") */ override def signalDone(context: Context, old: Tree, result: Tree) { if (interruptsEnabled && analyzer.lockedCount == 0) { - if (context.unit != null && + if (context.unit.exists && result.pos.isOpaqueRange && (result.pos includes context.unit.targetPos)) { var located = new TypedLocator(context.unit.targetPos) locateIn result diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 96b27b58ae..44c28cf2f5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -21,6 +21,7 @@ trait Contexts { self: Analyzer => val NoContext = new Context { override def implicitss: List[List[ImplicitInfo]] = List() outer = this + override def toString = "NoContext" } NoContext.enclClass = NoContext NoContext.enclMethod = NoContext @@ -89,7 +90,7 @@ trait Contexts { self: Analyzer => } class Context private[typechecker] { - var unit: CompilationUnit = _ + var unit: CompilationUnit = NoCompilationUnit var tree: Tree = _ // Tree associated with this context var owner: Symbol = NoSymbol // The current owner var scope: Scope = _ // The current scope @@ -164,12 +165,11 @@ trait Contexts { self: Analyzer => */ def make(unit: CompilationUnit, tree: Tree, owner: Symbol, scope: Scope, imports: List[ImportInfo]): Context = { - val c = new Context - c.unit = unit - c.tree = tree + val c = new Context + c.unit = unit + c.tree = tree c.owner = owner c.scope = scope - c.outer = this tree match { @@ -203,6 +203,7 @@ trait Contexts { self: Analyzer => c.retyping = this.retyping c.openImplicits = this.openImplicits registerContext(c.asInstanceOf[analyzer.Context]) + debuglog("Created context: " + this + " ==> " + c) c } @@ -364,11 +365,9 @@ trait Contexts { self: Analyzer => def nextEnclosing(p: Context => Boolean): Context = if (this == NoContext || p(this)) this else outer.nextEnclosing(p) - override def toString = ( - if (this == NoContext) "NoContext" - else "Context(%s@%s scope=%s)".format(owner.fullName, tree.getClass.getName split "[.$]" last, scope.##) + override def toString = "Context(%s@%s unit=%s scope=%s)".format( + owner.fullName, tree.shortClass, unit, scope.## ) - /** Is `sub` a subclass of `base` or a companion object of such a subclass? */ def isSubClassOrCompanion(sub: Symbol, base: Symbol) = diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 2a6fc122e2..7305cef34f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -249,7 +249,7 @@ trait Infer { tree setSymbol sym setType ErrorType } else { val topClass = context.owner.toplevelClass - if (context.unit != null) + if (context.unit.exists) context.unit.depends += sym.toplevelClass var sym1 = sym filter (alt => context.isAccessible(alt, pre, site.isInstanceOf[Super])) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 513522e017..2c424d17d7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -414,7 +414,7 @@ trait TypeDiagnostics { // Error suppression will squash some of these warnings unless we circumvent it. // It is presumed if you are using a -Y option you would really like to hear // the warnings you've requested. - if (settings.warnDeadCode.value && context.unit != null && treeOK(tree) && exprOK) { + if (settings.warnDeadCode.value && context.unit.exists && treeOK(tree) && exprOK) { val saved = context.reportGeneralErrors try { context.reportGeneralErrors = true diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d8c09cc685..f305644837 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2101,7 +2101,7 @@ trait Typers extends Modes with Adaptations { def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { val inBlock = exprOwner == context.owner def includesTargetPos(tree: Tree) = - tree.pos.isRange && context.unit != null && (tree.pos includes context.unit.targetPos) + tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos) val localTarget = stats exists includesTargetPos def typedStat(stat: Tree): Tree = { if (context.owner.isRefinementClass && !treeInfo.isDeclarationOrTypeDef(stat)) @@ -3779,7 +3779,7 @@ trait Typers extends Modes with Adaptations { // compilation units. Defined symbols take precedence over erroneous imports. if (defSym.definedInPackage && (!currentRun.compiles(defSym) || - (context.unit ne null) && defSym.sourceFile != context.unit.source.file)) + context.unit.exists && defSym.sourceFile != context.unit.source.file)) defSym = NoSymbol else if (impSym.isError || impSym.name == nme.CONSTRUCTOR) impSym = NoSymbol @@ -4328,8 +4328,7 @@ trait Typers extends Modes with Adaptations { case ex: Exception => if (settings.debug.value) // @M causes cyclic reference error Console.println("exception when typing "+tree+", pt = "+pt) - if ((context ne null) && (context.unit ne null) && - (context.unit.source ne null) && (tree ne null)) + if (context != null && context.unit.exists && tree != null) logError("AT: " + (tree.pos).dbgString, ex) throw ex } diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index 44e06441ce..42489c5aaf 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -51,6 +51,19 @@ abstract class SourceFile { def identifier(pos: Position): Option[String] = None } +/** An object representing a missing source file. + */ +object NoSourceFile extends SourceFile { + def content = Array() + def file = null // TODO: push NPE-defense out another level or two + def isLineBreak(idx: Int) = false + def isSelfContained = true + def length = -1 + def offsetToLine(offset: Int) = -1 + def lineToOffset(index : Int) = -1 + override def toString = "NoSourceFile" +} + object ScriptSourceFile { /** Length of the script header from the given content, if there is one. * The header begins with "#!" or "::#!" and ends with a line starting diff --git a/test/pending/pos/bug4859.scala b/test/pending/pos/bug4859.scala new file mode 100644 index 0000000000..ec5abd966d --- /dev/null +++ b/test/pending/pos/bug4859.scala @@ -0,0 +1,15 @@ +object O { + C().CC() + D().DD() +} + +case class C() { + case class CC() +} + +case class D() { + class DD() + object DD { + def apply() = new DD() + } +} |