summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-11-10 15:31:43 +0100
committerJason Zaugg <jzaugg@gmail.com>2012-11-10 23:41:39 +0100
commit0b59b4627a76d99531a51c7f17bbfa8b9c8c4bd8 (patch)
treecbcb514f01d80d2dee906df9d137b8e6ae98b3aa
parent8b598436f64ca4e980c8a38f642085b4d23e2327 (diff)
downloadscala-0b59b4627a76d99531a51c7f17bbfa8b9c8c4bd8.tar.gz
scala-0b59b4627a76d99531a51c7f17bbfa8b9c8c4bd8.tar.bz2
scala-0b59b4627a76d99531a51c7f17bbfa8b9c8c4bd8.zip
SI-6640 Better reporting of deficient classpaths.
In a55788e, StubSymbols were introduced to fail-slow when the classpath was deficient. This allowed compilation to succeed in cases when one didn't actually use the part of class A which referred to some missing class B. But a few problems were introduced. Firstly, when the deferred error eventually happened, it was signalled with abort(msg), rather than through a thrown MissingRequirementError. The latter is desirable, as it doesn't lead to printing a stack trace. Second, the actual error message changed, and no longer included the name of the class file that refers to the missing class. Finally, it seems that we can end up with a stub term symbol in a situation where a class symbol is desired. An assertion in the constructor of ThisType throws trips when calling .isClass, before the useful error message from StubSymbol can be emitted. This commit addresses these points, and rewords the error a little to be more accessible. The last point is the most fragile in this arrangement, there might be some whack-a-mole required to find other places that also need this. I don't see a clean solution for this, but am open to suggestions. We should really build a facility in partest to delete specified classfiles between groups in separate compilation tests, in order to have tests for this. I'll work on that as a followup. For now, here's the result of my manual testing: [info] Set current project to default-821d14 (in build file:/Users/jason/code/scratch1/) > compile [info] Compiling 1 Scala source to /Users/jason/code/scratch1/target/scala-2.10/classes... [error] [error] while compiling: /Users/jason/code/scratch1/test.scala [error] during phase: typer [error] library version: version 2.10.0-RC2 [error] compiler version: version 2.10.0-RC2 ... [error] last tree to typer: Ident(SwingWorker) [error] symbol: <none> (flags: ) [error] symbol definition: <none> [error] symbol owners: [error] context owners: object Test -> package <empty> ... [error] uncaught exception during compilation: java.lang.AssertionError [trace] Stack trace suppressed: run last compile:compile for the full output. [error] (compile:compile) java.lang.AssertionError: assertion failed: value actors [error] Total time: 2 s, completed Nov 10, 2012 3:18:34 PM > > set scalaHome := Some(file("/Users/jason/code/scala/build/pack")) [info] Defining *:scala-home [info] The new value will be used by no settings or tasks. [info] Reapplying settings... [info] Set current project to default-821d14 (in build file:/Users/jason/code/scratch1/) ^[compile [info] Compiling 1 Scala source to /Users/jason/code/scratch1/target/scala-2.10/classes... [error] /Users/jason/code/scratch1/test.scala:4: A signature in SwingWorker.class refers to term actors in package scala which is missing from the classpath. [error] object Test extends SwingWorker [error] ^ [error] one error found [error] (compile:compile) Compilation failed [error] Total time: 2 s, completed Nov 10, 2012 3:18:45 PM
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala21
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala2
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala8
3 files changed, 11 insertions, 20 deletions
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 7cb9a0e105..33d99b35d8 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -423,9 +423,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* failure to the point when that name is used for something, which is
* often to the point of never.
*/
- def newStubSymbol(name: Name): Symbol = name match {
- case n: TypeName => new StubClassSymbol(this, n)
- case _ => new StubTermSymbol(this, name.toTermName)
+ def newStubSymbol(name: Name, missingMessage: String): Symbol = name match {
+ case n: TypeName => new StubClassSymbol(this, n, missingMessage)
+ case _ => new StubTermSymbol(this, name.toTermName, missingMessage)
}
@deprecated("Use the other signature", "2.10.0")
@@ -3100,14 +3100,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
}
trait StubSymbol extends Symbol {
- protected def stubWarning = {
- val from = if (associatedFile == null) "" else s" - referenced from ${associatedFile.canonicalPath}"
- s"$kindString $nameString$locationString$from (a classfile may be missing)"
- }
+ protected def missingMessage: String
private def fail[T](alt: T): T = {
// Avoid issuing lots of redundant errors
if (!hasFlag(IS_ERROR)) {
- globalError(s"bad symbolic reference to " + stubWarning)
+ MissingRequirementError.signal(missingMessage)
if (settings.debug.value)
(new Throwable).printStackTrace
@@ -3124,12 +3121,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def rawInfo = fail(NoType)
override def companionSymbol = fail(NoSymbol)
- locally {
- debugwarn("creating stub symbol for " + stubWarning)
- }
+ debugwarn("creating stub symbol to defer error: " + missingMessage)
}
- class StubClassSymbol(owner0: Symbol, name0: TypeName) extends ClassSymbol(owner0, owner0.pos, name0) with StubSymbol
- class StubTermSymbol(owner0: Symbol, name0: TermName) extends TermSymbol(owner0, owner0.pos, name0) with StubSymbol
+ class StubClassSymbol(owner0: Symbol, name0: TypeName, protected val missingMessage: String) extends ClassSymbol(owner0, owner0.pos, name0) with StubSymbol
+ class StubTermSymbol(owner0: Symbol, name0: TermName, protected val missingMessage: String) extends TermSymbol(owner0, owner0.pos, name0) with StubSymbol
trait FreeSymbol extends Symbol {
def origin: String
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index e8054fcdf5..86d03d7450 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1385,7 +1385,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, sym)
+ assert(sym.isClass, {sym.info; sym}) // call .info to allow StubSymbols to reveal what's missing from the classpath
//assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym)
override def isTrivial: Boolean = sym.isPackageClass
override def isNotNull = true
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 43b982a8a4..15465f919a 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -233,7 +233,8 @@ abstract class UnPickler /*extends scala.reflect.generic.UnPickler*/ {
// (4) Call the mirror's "missing" hook.
adjust(mirrorThatLoaded(owner).missingHook(owner, name)) orElse {
// (5) Create a stub symbol to defer hard failure a little longer.
- owner.newStubSymbol(name)
+ val missingMessage = s"A signature in $filename refers to ${name.longString} in ${owner.fullLocationString} which is missing from the classpath."
+ owner.newStubSymbol(name, missingMessage)
}
}
}
@@ -827,11 +828,6 @@ abstract class UnPickler /*extends scala.reflect.generic.UnPickler*/ {
protected def errorBadSignature(msg: String) =
throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg)
- protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol =
- mirrorThatLoaded(owner).missingHook(owner, name) orElse MissingRequirementError.signal(
- s"bad reference while unpickling $filename: ${name.longString} not found in ${owner.tpe.widen}"
- )
-
def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) {} // can't do it; need a compiler for that.
def newLazyTypeRef(i: Int): LazyType = new LazyTypeRef(i)