From aa43994c9648183a81cba2557dc3188ef6ca341e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Aug 2008 14:53:44 +0000 Subject: corrected several problems with error reporting... corrected several problems with error reporting: positions checked twice, warnings masking errors. Refined solution of forward implicits without5 result type. --- src/compiler/scala/tools/nsc/CompilationUnits.scala | 18 +++--------------- src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 2 +- .../scala/tools/nsc/reporters/AbstractReporter.scala | 14 +++++++------- src/compiler/scala/tools/nsc/typechecker/Infer.scala | 13 ++++++++++++- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 19 ++++++++++++++----- 5 files changed, 37 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index f536a16a62..bf02e114ab 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -44,19 +44,11 @@ trait CompilationUnits { self: Global => */ val icode: HashSet[icodes.IClass] = new HashSet - val errorPositions = new HashSet[Position] - def error(pos: Position, msg: String) = - if (inIDE || !(errorPositions contains pos)) { - if (!inIDE) errorPositions += pos - reporter.error((pos), msg) - } + reporter.error(pos, msg) def warning(pos: Position, msg: String) = - if (inIDE || !(errorPositions contains pos)) { - if (!inIDE) errorPositions += pos - reporter.warning((pos), msg) - } + reporter.warning(pos, msg) def deprecationWarning(pos: Position, msg: String) = if (settings.deprecation.value) warning(pos, msg) @@ -67,10 +59,7 @@ trait CompilationUnits { self: Global => else currentRun.uncheckedWarnings = true def incompleteInputError(pos: Position, msg:String) = - if (inIDE || !(errorPositions contains pos)) { - if (!inIDE) errorPositions += pos - reporter.incompleteInputError((pos), msg) - } + reporter.incompleteInputError(pos, msg) /** Is this about a .java source file? */ lazy val isJava = source.file.name.endsWith(".java") @@ -81,7 +70,6 @@ trait CompilationUnits { self: Global => fresh = null body = null depends.clear - errorPositions.clear defined.clear } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 52c1cacb29..f38f0cde1e 100755 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -32,7 +32,7 @@ trait JavaParsers extends JavaScanners { abstract class JavaParser { val in: JavaScanner - protected def posToReport: Int = in.p2g(in.currentPos) + protected def posToReport: Int = in.currentPos protected def freshName(pos : Position, prefix : String): Name protected implicit def i2p(offset : Int) : Position private implicit def p2i(pos : Position): Int = pos.offset.getOrElse(-1) diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index 53cbbddcc7..a4f682a715 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -6,7 +6,7 @@ package scala.tools.nsc.reporters -import scala.collection.mutable.HashSet +import scala.collection.mutable.HashMap import scala.tools.nsc.Settings import scala.tools.nsc.util.Position @@ -14,7 +14,7 @@ import scala.tools.nsc.util.Position * This reporter implements filtering. */ abstract class AbstractReporter extends Reporter { - private val positions = new HashSet[Position]() + private val positions = new HashMap[Position, Severity] override def reset = { super.reset @@ -31,13 +31,13 @@ abstract class AbstractReporter extends Reporter { case INFO => if (force || settings.verbose.value) display(pos, msg, severity) case WARNING => - val hidden = testAndLog(pos) + val hidden = testAndLog(pos, severity) if (!settings.nowarnings.value) { if (!hidden || settings.prompt.value) display(pos, msg, severity) if (settings.prompt.value) displayPrompt } case ERROR => - val hidden = testAndLog(pos) + val hidden = testAndLog(pos, severity) if (!hidden || settings.prompt.value) display(pos, msg, severity) if (settings.prompt.value) displayPrompt } @@ -48,11 +48,11 @@ abstract class AbstractReporter extends Reporter { * @param pos ... * @return true if pos was already logged. */ - private def testAndLog(pos: Position): Boolean = { + private def testAndLog(pos: Position, severity: Severity): Boolean = { if (pos eq null) return false if (pos.offset.isEmpty) return false - if (positions contains pos) return true - positions += pos + if ((positions contains pos) && positions(pos) >= severity) return true + positions += (pos -> severity) false } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 51288bab2e..567ff3479e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -197,6 +197,14 @@ trait Infer { /* -- Error Messages --------------------------------------------------- */ + private var addendumPos: Position = NoPosition + private var addendum: () => String = _ + + def setAddendum(pos: Position, msg: () => String) = { + addendumPos = pos + addendum = msg + } + def setError[T <: Tree](tree: T): T = { if (tree.hasSymbol) if (context.reportGeneralErrors) { @@ -265,7 +273,10 @@ trait Infer { def typeError(pos: Position, found: Type, req: Type) { if (!found.isErroneous && !req.isErroneous) { - error(pos, typeErrorMsg(found, req)) + error(pos, + typeErrorMsg(found, req)+ + (if (pos != NoPosition && pos == addendumPos) addendum() + else "")) if (settings.explaintypes.value) explainTypes(found, req) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 4d57d8bc33..138d2f469d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3648,6 +3648,7 @@ trait Typers { self: Analyzer => def comesBefore(sym: Symbol, owner: Symbol) = sym.pos.offset.getOrElse(0) < owner.pos.offset.getOrElse(Integer.MAX_VALUE) && !(owner.ownerChain contains sym) + /** Should implicit definition symbol `sym' be considered for applicability testing? * This is the case if one of the following holds: * - the symbol's type is initialized @@ -3666,19 +3667,27 @@ trait Typers { self: Analyzer => hasExplicitResultType(sym) || comesBefore(sym, context.owner) } + val lateImpls = new ListBuffer[Symbol] def isApplicable(info: ImplicitInfo): Boolean = - (true /* for now */ || isValid(info.sym)) && !containsError(info.tpe) && !(isLocal && shadowed.contains(info.name)) && (!isView || info.sym != Predef_identity) && tc.typedImplicit(pos, info, pt0, pt, isLocal) != EmptyTree - def applicableInfos(is: List[ImplicitInfo]) = { - val result = is filter isApplicable + def applicableInfos(is: List[ImplicitInfo]): List[ImplicitInfo] = { + val applicable = new ListBuffer[ImplicitInfo] + for (i <- is) + if (!isValid(i.sym)) lateImpls += i.sym + else if (isApplicable(i)) applicable += i if (isLocal) for (i <- is) shadowed addEntry i.name - result + applicable.toList + } + val applicable = implicitInfoss flatMap applicableInfos + if (applicable.isEmpty && !lateImpls.isEmpty) { + infer.setAddendum(pos, () => + "\n Note: implicit "+lateImpls.first+" is not applicable here"+ + "\n because it comes after the application point and it lacks an explicit result type") } - val applicable = List.flatten(implicitInfoss map applicableInfos) val best = (NoImplicitInfo /: applicable) ((best, alt) => if (improves(alt, best)) alt else best) if (best == NoImplicitInfo) EmptyTree else { -- cgit v1.2.3