summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-08-26 13:43:35 +0200
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-08-26 13:43:35 +0200
commit63a087609855c46c8f376bd2271b8a50583d5c62 (patch)
tree8d578cada1e80ec1c196431f6b953cac1287cd30 /src/compiler/scala/tools/nsc/typechecker
parent6ec0d70da83255ec4f9d1b81902ee60b0f5c6332 (diff)
parentca9f64dfa20fb8d5a4c022f6b9fd2f18a8ea1028 (diff)
downloadscala-63a087609855c46c8f376bd2271b8a50583d5c62.tar.gz
scala-63a087609855c46c8f376bd2271b8a50583d5c62.tar.bz2
scala-63a087609855c46c8f376bd2271b8a50583d5c62.zip
Merge pull request #3886 from adriaanm/report-filter
part 2 of the big error reporting refactoring
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala112
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala429
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala130
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala142
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala82
10 files changed, 483 insertions, 433 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 9715fdaf00..20e462bbce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -27,6 +27,16 @@ trait ContextErrors {
override def toString() = "[Type error at:" + errPos + "] " + errMsg
}
+ abstract class AbsAmbiguousTypeError extends AbsTypeError
+
+ case class AmbiguousTypeError(errPos: Position, errMsg: String)
+ extends AbsAmbiguousTypeError
+
+ case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
+ extends AbsAmbiguousTypeError {
+ def errPos = underlyingTree.pos
+ }
+
sealed abstract class TreeTypeError extends AbsTypeError {
def underlyingTree: Tree
def errPos = underlyingTree.pos
@@ -38,9 +48,6 @@ trait ContextErrors {
case class AccessTypeError(underlyingTree: Tree, errMsg: String)
extends TreeTypeError
- case class AmbiguousTypeError(errPos: Position, errMsg: String)
- extends AbsTypeError
-
case class SymbolTypeError(underlyingSym: Symbol, errMsg: String)
extends AbsTypeError {
@@ -75,8 +82,6 @@ trait ContextErrors {
s"diverging implicit expansion for type ${pt}\nstarting with ${sym.fullLocationString}"
}
- case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
- extends TreeTypeError
case class PosAndMsgTypeError(errPos: Position, errMsg: String)
extends AbsTypeError
@@ -90,10 +95,6 @@ trait ContextErrors {
issueTypeError(SymbolTypeError(sym, msg))
}
- def issueAmbiguousTypeError(pre: Type, sym1: Symbol, sym2: Symbol, err: AmbiguousTypeError)(implicit context: Context) {
- context.issueAmbiguousError(pre, sym1, sym2, err)
- }
-
def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) }
def typeErrorMsg(found: Type, req: Type) = "type mismatch" + foundReqMsg(found, req)
@@ -123,6 +124,36 @@ trait ContextErrors {
import ErrorUtils._
+ private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
+ def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
+ val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
+ // TODO: clean this up! (This is a more explicit version of what the code use to do, to reveal the issue.)
+ throw new TypeError(analyzer.lastTreeToTyper.pos, message)
+ }
+
+ def MacroCantExpand210xMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
+
+ def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
+
+ def NoImplicitFoundError(tree: Tree, param: Symbol)(implicit context: Context): Unit = {
+ def errMsg = {
+ val paramName = param.name
+ val paramTp = param.tpe
+ def evOrParam = (
+ if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
+ "evidence parameter of type"
+ else
+ s"parameter $paramName:")
+ paramTp.typeSymbolDirect match {
+ case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
+ case _ => s"could not find implicit value for $evOrParam $paramTp"
+ }
+ }
+ issueNormalTypeError(tree, errMsg)
+ }
+
trait TyperContextErrors {
self: Typer =>
@@ -141,24 +172,6 @@ trait ContextErrors {
setError(tree)
}
- def NoImplicitFoundError(tree: Tree, param: Symbol) = {
- def errMsg = {
- val paramName = param.name
- val paramTp = param.tpe
- def evOrParam = (
- if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
- "evidence parameter of type"
- else
- s"parameter $paramName:"
- )
- paramTp.typeSymbolDirect match {
- case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
- case _ => s"could not find implicit value for $evOrParam $paramTp"
- }
- }
- issueNormalTypeError(tree, errMsg)
- }
-
def AdaptTypeError(tree: Tree, found: Type, req: Type) = {
// SI-3971 unwrapping to the outermost Apply helps prevent confusion with the
// error message point.
@@ -733,17 +746,6 @@ trait ContextErrors {
NormalTypeError(expandee, "too many argument lists for " + fun)
}
- private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
- def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
- val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
- issueNormalTypeError(lastTreeToTyper, message)
- }
-
- def MacroCantExpand210xMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
-
- def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable
@@ -883,19 +885,21 @@ trait ContextErrors {
val WrongNumber, NoParams, ArgsDoNotConform = Value
}
- private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) =
- if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
- val methodName = nme.defaultGetterToMethod(sym1.name)
- (sym1.enclClass.pos,
- "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
- " define default arguments")
- } else {
- (pos,
- ("ambiguous reference to overloaded definition,\n" +
- "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
- "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
- "\nmatch " + rest)
- )
+ private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit =
+ if (!(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)) {
+ if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
+ val methodName = nme.defaultGetterToMethod(sym1.name)
+ context.issueAmbiguousError(AmbiguousTypeError(sym1.enclClass.pos,
+ "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
+ " define default arguments"))
+ } else {
+ context.issueAmbiguousError(AmbiguousTypeError(pos,
+ ("ambiguous reference to overloaded definition,\n" +
+ "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
+ "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
+ "\nmatch " + rest)
+ ))
+ }
}
def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError =
@@ -952,8 +956,7 @@ trait ContextErrors {
val msg0 =
"argument types " + argtpes.mkString("(", ",", ")") +
(if (pt == WildcardType) "" else " and expected result type " + pt)
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, msg0)
setErrorOnLastTry(lastTry, tree)
} else setError(tree) // do not even try further attempts because they should all fail
// even if this is not the last attempt (because of the SO's possibility on the horizon)
@@ -966,8 +969,7 @@ trait ContextErrors {
}
def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type, lastTry: Boolean) = {
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, "expected type " + pt)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, "expected type " + pt)
setErrorOnLastTry(lastTry, tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 72ca9b879a..a79f162140 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -9,6 +9,7 @@ package typechecker
import scala.collection.{ immutable, mutable }
import scala.annotation.tailrec
import scala.reflect.internal.util.shortClassOfInstance
+import scala.tools.nsc.reporters.Reporter
/**
* @author Martin Odersky
@@ -98,7 +99,7 @@ trait Contexts { self: Analyzer =>
}
- def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, erasedTypes: Boolean = false): Context = {
+ def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, throwing: Boolean = false, checking: Boolean = false): Context = {
val rootImportsContext = (startContext /: rootImports(unit))((c, sym) => c.make(gen.mkWildcardImport(sym)))
// there must be a scala.xml package when xml literals were parsed in this unit
@@ -113,18 +114,21 @@ trait Contexts { self: Analyzer =>
else rootImportsContext.make(gen.mkImport(ScalaXmlPackage, nme.TopScope, nme.dollarScope))
val c = contextWithXML.make(tree, unit = unit)
- if (erasedTypes) c.setThrowErrors() else c.setReportErrors()
- c(EnrichmentEnabled | ImplicitsEnabled) = !erasedTypes
+
+ c.initRootContext(throwing, checking)
c
}
+ def rootContextPostTyper(unit: CompilationUnit, tree: Tree = EmptyTree): Context =
+ rootContext(unit, tree, throwing = true)
+
def resetContexts() {
startContext.enclosingContextChain foreach { context =>
context.tree match {
case Import(qual, _) => qual setType singleType(qual.symbol.owner.thisType, qual.symbol)
case _ =>
}
- context.reportBuffer.clearAll()
+ context.reporter.clearAll()
}
}
@@ -178,7 +182,8 @@ trait Contexts { self: Analyzer =>
* @param _outer The next outer context.
*/
class Context private[typechecker](val tree: Tree, val owner: Symbol, val scope: Scope,
- val unit: CompilationUnit, _outer: Context) {
+ val unit: CompilationUnit, _outer: Context,
+ private[this] var _reporter: ContextReporter = new ThrowingReporter) {
private def outerIsNoContext = _outer eq null
final def outer: Context = if (outerIsNoContext) NoContext else _outer
@@ -254,8 +259,6 @@ trait Contexts { self: Analyzer =>
def macrosEnabled = this(MacrosEnabled)
def enrichmentEnabled_=(value: Boolean) = this(EnrichmentEnabled) = value
def enrichmentEnabled = this(EnrichmentEnabled)
- def checking_=(value: Boolean) = this(Checking) = value
- def checking = this(Checking)
def retyping_=(value: Boolean) = this(ReTyping) = value
def retyping = this(ReTyping)
def inSecondTry = this(SecondTry)
@@ -265,8 +268,9 @@ trait Contexts { self: Analyzer =>
def defaultModeForTyped: Mode = if (inTypeConstructorAllowed) Mode.NOmode else Mode.EXPRmode
- /** These messages are printed when issuing an error */
- var diagnostic: List[String] = Nil
+ /** To enrich error messages involving default arguments.
+ When extending the notion, group diagnostics in an object. */
+ var diagUsedDefaults: Boolean = false
/** Saved type bounds for type parameters which are narrowed in a GADT. */
var savedTypeBounds: List[(Symbol, Type)] = List()
@@ -310,7 +314,7 @@ trait Contexts { self: Analyzer =>
*/
def savingUndeterminedTypeParams[A](reportAmbiguous: Boolean = ambiguousErrors)(body: => A): A = {
withMode() {
- this(AmbiguousErrors) = reportAmbiguous
+ setAmbiguousErrors(reportAmbiguous)
val saved = extractUndetparams()
try body
finally undetparams = saved
@@ -321,54 +325,59 @@ trait Contexts { self: Analyzer =>
// Error reporting policies and buffer.
//
- private var _reportBuffer: ReportBuffer = new ReportBuffer
- /** A buffer for errors and warnings, used with `this.bufferErrors == true` */
- def reportBuffer = _reportBuffer
- /** Discard the current report buffer, and replace with an empty one */
- def useFreshReportBuffer() = _reportBuffer = new ReportBuffer
- /** Discard the current report buffer, and replace with `other` */
- def restoreReportBuffer(other: ReportBuffer) = _reportBuffer = other
-
- /** The first error, if any, in the report buffer */
- def firstError: Option[AbsTypeError] = reportBuffer.firstError
- def errors: Seq[AbsTypeError] = reportBuffer.errors
- /** Does the report buffer contain any errors? */
- def hasErrors = reportBuffer.hasErrors
-
- def reportErrors = this(ReportErrors)
- def bufferErrors = this(BufferErrors)
+ // the reporter for this context
+ def reporter: ContextReporter = _reporter
+
+ // if set, errors will not be reporter/thrown
+ def bufferErrors = reporter.isBuffering
+ def reportErrors = !bufferErrors
+
+ // whether to *report* (which is separate from buffering/throwing) ambiguity errors
def ambiguousErrors = this(AmbiguousErrors)
- def throwErrors = contextMode.inNone(ReportErrors | BufferErrors)
-
- def setReportErrors(): Unit = set(enable = ReportErrors | AmbiguousErrors, disable = BufferErrors)
- def setBufferErrors(): Unit = set(enable = BufferErrors, disable = ReportErrors | AmbiguousErrors)
- def setThrowErrors(): Unit = this(ReportErrors | AmbiguousErrors | BufferErrors) = false
- def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
-
- /** Append the given errors to the report buffer */
- def updateBuffer(errors: Traversable[AbsTypeError]) = reportBuffer ++= errors
- /** Clear all errors from the report buffer */
- def flushBuffer() { reportBuffer.clearAllErrors() }
- /** Return and clear all errors from the report buffer */
- def flushAndReturnBuffer(): immutable.Seq[AbsTypeError] = {
- val current = reportBuffer.errors
- reportBuffer.clearAllErrors()
- current
- }
- /** Issue and clear all warnings from the report buffer */
- def flushAndIssueWarnings() {
- reportBuffer.warnings foreach {
- case (pos, msg) => reporter.warning(pos, msg)
+ private def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
+
+ /**
+ * Try inference twice: once without views and once with views,
+ * unless views are already disabled.
+ */
+ abstract class TryTwice {
+ def tryOnce(isLastTry: Boolean): Unit
+
+ final def apply(): Unit = {
+ val doLastTry =
+ // do first try if implicits are enabled
+ if (implicitsEnabled) {
+ // We create a new BufferingReporter to
+ // distinguish errors that occurred before entering tryTwice
+ // and our first attempt in 'withImplicitsDisabled'. If the
+ // first attempt fails, we try with implicits on
+ // and the original reporter.
+ // immediate reporting of ambiguous errors is suppressed, so that they are buffered
+ inSilentMode {
+ try {
+ set(disable = ImplicitsEnabled | EnrichmentEnabled) // restored by inSilentMode
+ tryOnce(false)
+ reporter.hasErrors
+ } catch {
+ case ex: CyclicReference => throw ex
+ case ex: TypeError => true // recoverable cyclic references?
+ }
+ }
+ } else true
+
+ // do last try if try with implicits enabled failed
+ // (or if it was not attempted because they were disabled)
+ if (doLastTry)
+ tryOnce(true)
}
- reportBuffer.clearAllWarnings()
}
//
// Temporary mode adjustment
//
- @inline def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
+ @inline final def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
val saved = contextMode
set(enabled, disabled)
try op
@@ -402,12 +411,18 @@ trait Contexts { self: Analyzer =>
// See comment on FormerNonStickyModes.
@inline final def withOnlyStickyModes[T](op: => T): T = withMode(disabled = FormerNonStickyModes)(op)
- /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */
+ // inliner note: this has to be a simple method for inlining to work -- moved the `&& !reporter.hasErrors` out
@inline final def inSilentMode(expr: => Boolean): Boolean = {
- withMode() { // withMode with no arguments to restore the mode mutated by `setBufferErrors`.
- setBufferErrors()
- try expr && !hasErrors
- finally reportBuffer.clearAll()
+ val savedContextMode = contextMode
+ val savedReporter = reporter
+
+ setAmbiguousErrors(false)
+ _reporter = new BufferingReporter
+
+ try expr
+ finally {
+ contextMode = savedContextMode
+ _reporter = savedReporter
}
}
@@ -423,7 +438,8 @@ trait Contexts { self: Analyzer =>
* `Context#imports`.
*/
def make(tree: Tree = tree, owner: Symbol = owner,
- scope: Scope = scope, unit: CompilationUnit = unit): Context = {
+ scope: Scope = scope, unit: CompilationUnit = unit,
+ reporter: ContextReporter = this.reporter): Context = {
val isTemplateOrPackage = tree match {
case _: Template | _: PackageDef => true
case _ => false
@@ -446,16 +462,15 @@ trait Contexts { self: Analyzer =>
// The blank canvas
val c = if (isImport)
- new Context(tree, owner, scope, unit, this) with ImportContext
+ new Context(tree, owner, scope, unit, this, reporter) with ImportContext
else
- new Context(tree, owner, scope, unit, this)
+ new Context(tree, owner, scope, unit, this, reporter)
// Fields that are directly propagated
c.variance = variance
- c.diagnostic = diagnostic
+ c.diagUsedDefaults = diagUsedDefaults
c.openImplicits = openImplicits
c.contextMode = contextMode // note: ConstructorSuffix, a bit within `mode`, is conditionally overwritten below.
- c._reportBuffer = reportBuffer
// Fields that may take on a different value in the child
c.prefix = prefixInChild
@@ -470,22 +485,38 @@ trait Contexts { self: Analyzer =>
c
}
+ /** Use reporter (possibly buffered) for errors/warnings and enable implicit conversion **/
+ def initRootContext(throwing: Boolean = false, checking: Boolean = false): Unit = {
+ _reporter =
+ if (checking) new CheckingReporter
+ else if (throwing) new ThrowingReporter
+ else new ImmediateReporter
+
+ setAmbiguousErrors(!throwing)
+ this(EnrichmentEnabled | ImplicitsEnabled) = !throwing
+ }
+
def make(tree: Tree, owner: Symbol, scope: Scope): Context =
// TODO SI-7345 Moving this optimization into the main overload of `make` causes all tests to fail.
- // even if it is extened to check that `unit == this.unit`. Why is this?
+ // even if it is extended to check that `unit == this.unit`. Why is this?
if (tree == this.tree && owner == this.owner && scope == this.scope) this
else make(tree, owner, scope, unit)
/** Make a child context that represents a new nested scope */
- def makeNewScope(tree: Tree, owner: Symbol): Context =
- make(tree, owner, newNestedScope(scope))
+ def makeNewScope(tree: Tree, owner: Symbol, reporter: ContextReporter = this.reporter): Context =
+ make(tree, owner, newNestedScope(scope), reporter = reporter)
/** Make a child context that buffers errors and warnings into a fresh report buffer. */
def makeSilent(reportAmbiguousErrors: Boolean = ambiguousErrors, newtree: Tree = tree): Context = {
- val c = make(newtree)
- c.setBufferErrors()
+ // A fresh buffer so as not to leak errors/warnings into `this`.
+ val c = make(newtree, reporter = new BufferingReporter)
c.setAmbiguousErrors(reportAmbiguousErrors)
- c._reportBuffer = new ReportBuffer // A fresh buffer so as not to leak errors/warnings into `this`.
+ c
+ }
+
+ def makeNonSilent(newtree: Tree): Context = {
+ val c = make(newtree, reporter = reporter.makeImmediate)
+ c.setAmbiguousErrors(true)
c
}
@@ -508,7 +539,9 @@ trait Contexts { self: Analyzer =>
*/
def makeConstructorContext = {
val baseContext = enclClass.outer.nextEnclosing(!_.tree.isInstanceOf[Template])
- val argContext = baseContext.makeNewScope(tree, owner)
+ // must propagate reporter!
+ // (caught by neg/t3649 when refactoring reporting to be specified only by this.reporter and not also by this.contextMode)
+ val argContext = baseContext.makeNewScope(tree, owner, reporter = this.reporter)
argContext.contextMode = contextMode
argContext.inSelfSuperCall = true
def enterElems(c: Context) {
@@ -533,65 +566,16 @@ trait Contexts { self: Analyzer =>
// Error and warning issuance
//
- private def addDiagString(msg: String) = {
- val ds =
- if (diagnostic.isEmpty) ""
- else diagnostic.mkString("\n","\n", "")
- if (msg endsWith ds) msg else msg + ds
- }
-
- private def unitError(pos: Position, msg: String): Unit =
- if (checking) onTreeCheckerError(pos, msg) else reporter.error(pos, msg)
-
- @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) {
- // TODO: are errors allowed to have pos == NoPosition??
- // if not, Jason suggests doing: val pos = err.errPos.orElse( { devWarning("Que?"); context.tree.pos })
- if (settings.Yissuedebug) {
- log("issue error: " + err.errMsg)
- (new Exception).printStackTrace()
- }
- if (pf isDefinedAt err) pf(err)
- else if (bufferErrors) { reportBuffer += err }
- else throw new TypeError(err.errPos, err.errMsg)
- }
-
/** Issue/buffer/throw the given type error according to the current mode for error reporting. */
- def issue(err: AbsTypeError) {
- issueCommon(err) { case _ if reportErrors =>
- unitError(err.errPos, addDiagString(err.errMsg))
- }
- }
-
- /** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors =>
- if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
- unitError(err.errPos, err.errMsg)
- }
- }
-
+ private[typechecker] def issue(err: AbsTypeError) = reporter.issue(err)(this)
/** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors => unitError(err.errPos, addDiagString(err.errMsg)) }
- }
-
- /** Issue/throw the given `err` according to the current mode for error reporting. */
- def error(pos: Position, err: Throwable) =
- if (reportErrors) unitError(pos, addDiagString(err.getMessage()))
- else throw err
-
+ private[typechecker] def issueAmbiguousError(err: AbsAmbiguousTypeError) = reporter.issueAmbiguousError(err)(this)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def error(pos: Position, msg: String) = {
- val msg1 = addDiagString(msg)
- if (reportErrors) unitError(pos, msg1)
- else throw new TypeError(pos, msg1)
- }
-
+ def error(pos: Position, msg: String) = reporter.error(pos, msg)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def warning(pos: Position, msg: String, force: Boolean = false) {
- if (reportErrors || force) reporter.warning(pos, msg)
- else if (bufferErrors) reportBuffer += (pos -> msg)
- }
+ def warning(pos: Position, msg: String) = reporter.warning(pos, msg)
+ def echo(pos: Position, msg: String) = reporter.echo(pos, msg)
+
def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit =
currentRun.reporting.deprecationWarning(pos, sym, msg)
@@ -601,7 +585,6 @@ trait Contexts { self: Analyzer =>
def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit =
currentRun.reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required)
- def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg)
// nextOuter determines which context is searched next for implicits
// (after `this`, which contributes `newImplicits` below.) In
@@ -1238,61 +1221,176 @@ trait Contexts { self: Analyzer =>
override final def toString = super.toString + " with " + s"ImportContext { $impInfo; outer.owner = ${outer.owner} }"
}
- /** A buffer for warnings and errors that are accumulated during speculative type checking. */
- final class ReportBuffer {
+ /** A reporter for use during type checking. It has multiple modes for handling errors.
+ *
+ * The default (immediate mode) is to send the error to the global reporter.
+ * When switched into buffering mode via makeBuffering, errors and warnings are buffered and not be reported
+ * (there's a special case for ambiguity errors for some reason: those are force to the reporter when context.ambiguousErrors,
+ * or else they are buffered -- TODO: can we simplify this?)
+ *
+ * When using the type checker after typers, an error results in a TypeError being thrown. TODO: get rid of this mode.
+ *
+ * To handle nested contexts, reporters share buffers. TODO: only buffer in BufferingReporter, emit immediately in ImmediateReporter
+ */
+ abstract class ContextReporter(private[this] var _errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, private[this] var _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends Reporter {
type Error = AbsTypeError
type Warning = (Position, String)
- private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ def issue(err: AbsTypeError)(implicit context: Context): Unit = handleError(err.errPos, addDiagString(err.errMsg))
- // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
- // is replicated here out of conservatism.
- private var _errorBuffer: mutable.LinkedHashSet[Error] = _
- private def errorBuffer = {if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer}
- def errors: immutable.Seq[Error] = errorBuffer.toVector
+ protected def handleError(pos: Position, msg: String): Unit
+ protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = ()
+ protected def handleWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
- private var _warningBuffer: mutable.LinkedHashSet[Warning] = _
- private def warningBuffer = {if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer}
- def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ def makeImmediate: ContextReporter = this
+ def makeBuffering: ContextReporter = this
+ def isBuffering: Boolean = false
- def +=(error: AbsTypeError): this.type = {
- errorBuffer += error
- this
- }
- def ++=(errors: Traversable[AbsTypeError]): this.type = {
- errorBuffer ++= errors
- this
- }
- def +=(warning: Warning): this.type = {
- warningBuffer += warning
- this
+ /** Emit an ambiguous error according to context.ambiguousErrors
+ *
+ * - when true, use global.reporter regardless of whether we're buffering (TODO: can we change this?)
+ * - else, let this context reporter decide
+ */
+ final def issueAmbiguousError(err: AbsAmbiguousTypeError)(implicit context: Context): Unit =
+ if (context.ambiguousErrors) reporter.error(err.errPos, addDiagString(err.errMsg)) // force reporting... see TODO above
+ else handleSuppressedAmbiguous(err)
+
+ @inline final def withFreshErrorBuffer[T](expr: => T): T = {
+ val previousBuffer = _errorBuffer
+ _errorBuffer = newBuffer
+ val res = expr // expr will read _errorBuffer
+ _errorBuffer = previousBuffer
+ res
}
- def clearAll(): this.type = {
- clearAllErrors(); clearAllWarnings();
+ @inline final def propagatingErrorsTo[T](target: ContextReporter)(expr: => T): T = {
+ val res = expr // TODO: make sure we're okay skipping the try/finally overhead
+ if ((this ne target) && hasErrors) { // `this eq target` in e.g., test/files/neg/divergent-implicit.scala
+ // assert(target.errorBuffer ne _errorBuffer)
+ target ++= errors
+ // TODO: is clearAllErrors necessary? (no tests failed when dropping it)
+ // NOTE: even though `this ne target`, it may still be that `target.errorBuffer eq _errorBuffer`,
+ // so don't clear the buffer, but null out the reference so that a new one will be created when necessary (should be never??)
+ // (we should refactor error buffering to avoid mutation on shared buffers)
+ clearAllErrors()
+ }
+ res
}
- def clearAllErrors(): this.type = {
- errorBuffer.clear()
- this
- }
- def clearErrors(removeF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(!PartialFunction.cond(_)(removeF))
- this
+ protected final def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit =
+ severity match {
+ case ERROR => handleError(pos, msg)
+ case WARNING => handleWarning(pos, msg)
+ case INFO => reporter.echo(pos, msg)
+ }
+
+ final override def hasErrors = super.hasErrors || errorBuffer.nonEmpty
+
+ // TODO: everything below should be pushed down to BufferingReporter (related to buffering)
+ // Implicit relies on this most heavily, but there you know reporter.isInstanceOf[BufferingReporter]
+ // can we encode this statically?
+
+ // have to pass in context because multiple contexts may share the same ReportBuffer
+ def reportFirstDivergentError(fun: Tree, param: Symbol, paramTp: Type)(implicit context: Context): Unit =
+ errors.collectFirst {
+ case dte: DivergentImplicitTypeError => dte
+ } match {
+ case Some(divergent) =>
+ // DivergentImplicit error has higher priority than "no implicit found"
+ // no need to issue the problem again if we are still in silent mode
+ if (context.reportErrors) {
+ context.issue(divergent.withPt(paramTp))
+ errorBuffer.retain {
+ case dte: DivergentImplicitTypeError => false
+ case _ => true
+ }
+ }
+ case _ =>
+ NoImplicitFoundError(fun, param)(context)
+ }
+
+ def retainDivergentErrorsExcept(saved: DivergentImplicitTypeError) =
+ errorBuffer.retain {
+ case err: DivergentImplicitTypeError => err ne saved
+ case _ => false
+ }
+
+ def propagateImplicitTypeErrorsTo(target: ContextReporter) = {
+ errors foreach {
+ case err@(_: DivergentImplicitTypeError | _: AmbiguousImplicitTypeError) =>
+ target.errorBuffer += err
+ case _ =>
+ }
+ // debuglog("propagateImplicitTypeErrorsTo: " + errors)
}
- def retainErrors(leaveF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(PartialFunction.cond(_)(leaveF))
- this
+
+ protected def addDiagString(msg: String)(implicit context: Context): String = {
+ val diagUsedDefaultsMsg = "Error occurred in an application involving default arguments."
+ if (context.diagUsedDefaults && !(msg endsWith diagUsedDefaultsMsg)) msg + "\n" + diagUsedDefaultsMsg
+ else msg
}
- def clearAllWarnings(): this.type = {
- warningBuffer.clear()
- this
+
+ final def emitWarnings() = if (_warningBuffer != null) {
+ _warningBuffer foreach {
+ case (pos, msg) => reporter.warning(pos, msg)
+ }
+ _warningBuffer = null
}
- def hasErrors = errorBuffer.nonEmpty
- def firstError = errorBuffer.headOption
+ // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
+ // is replicated here out of conservatism.
+ private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ final protected def errorBuffer = { if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer }
+ final protected def warningBuffer = { if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer }
+
+ final def errors: immutable.Seq[Error] = errorBuffer.toVector
+ final def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ final def firstError: Option[AbsTypeError] = errorBuffer.headOption
+
+ // TODO: remove ++= and clearAll* entirely in favor of more high-level combinators like withFreshErrorBuffer
+ final private[typechecker] def ++=(errors: Traversable[AbsTypeError]): Unit = errorBuffer ++= errors
+
+ // null references to buffers instead of clearing them,
+ // as the buffers may be shared between different reporters
+ final def clearAll(): Unit = { _errorBuffer = null; _warningBuffer = null }
+ final def clearAllErrors(): Unit = { _errorBuffer = null }
+ }
+
+ private[typechecker] class ImmediateReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def makeBuffering: ContextReporter = new BufferingReporter(errorBuffer, warningBuffer)
+ protected def handleError(pos: Position, msg: String): Unit = reporter.error(pos, msg)
+ }
+
+
+ private[typechecker] class BufferingReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def isBuffering = true
+
+ override def issue(err: AbsTypeError)(implicit context: Context): Unit = errorBuffer += err
+
+ // this used to throw new TypeError(pos, msg) -- buffering lets us report more errors (test/files/neg/macro-basic-mamdmi)
+ // the old throwing behavior was relied on by diagnostics in manifestOfType
+ protected def handleError(pos: Position, msg: String): Unit = errorBuffer += TypeErrorWrapper(new TypeError(pos, msg))
+ override protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = errorBuffer += err
+ override protected def handleWarning(pos: Position, msg: String): Unit = warningBuffer += ((pos, msg))
+
+ // TODO: emit all buffered errors, warnings
+ override def makeImmediate: ContextReporter = new ImmediateReporter(errorBuffer, warningBuffer)
}
+ /** Used after typer (specialization relies on TypeError being thrown, among other post-typer phases).
+ *
+ * TODO: get rid of it, use ImmediateReporter and a check for reporter.hasErrors where necessary
+ */
+ private[typechecker] class ThrowingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = throw new TypeError(pos, msg)
+ }
+
+ /** Used during a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
+ private[typechecker] class CheckingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = onTreeCheckerError(pos, msg)
+ }
+
+
class ImportInfo(val tree: Import, val depth: Int) {
def pos = tree.pos
def posOf(sel: ImportSelector) = tree.pos withPoint sel.namePos
@@ -1385,8 +1483,6 @@ object ContextMode {
def apply(bits: Int): ContextMode = new ContextMode(bits)
final val NOmode: ContextMode = 0
- final val ReportErrors: ContextMode = 1 << 0
- final val BufferErrors: ContextMode = 1 << 1
final val AmbiguousErrors: ContextMode = 1 << 2
/** Are we in a secondary constructor after the this constructor call? */
@@ -1409,8 +1505,6 @@ object ContextMode {
/** To selectively allow enrichment in patterns, where other kinds of implicit conversions are not allowed */
final val EnrichmentEnabled: ContextMode = 1 << 8
- /** Are we in a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
- final val Checking: ContextMode = 1 << 9
/** Are we retypechecking arguments independently from the function applied to them? See `Typer.tryTypedApply`
* TODO - iron out distinction/overlap with SecondTry.
@@ -1447,17 +1541,14 @@ object ContextMode {
PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructorAllowed
)
- final val DefaultMode: ContextMode = MacrosEnabled
+ final val DefaultMode: ContextMode = MacrosEnabled
private val contextModeNameMap = Map(
- ReportErrors -> "ReportErrors",
- BufferErrors -> "BufferErrors",
AmbiguousErrors -> "AmbiguousErrors",
ConstructorSuffix -> "ConstructorSuffix",
SelfSuperCall -> "SelfSuperCall",
ImplicitsEnabled -> "ImplicitsEnabled",
MacrosEnabled -> "MacrosEnabled",
- Checking -> "Checking",
ReTyping -> "ReTyping",
PatternAlternative -> "PatternAlternative",
StarPatterns -> "StarPatterns",
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 73c3e6f016..b85c8e6d42 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -71,13 +71,10 @@ trait Implicits {
typingStack.printTyping(tree, "typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
- if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
- context.updateBuffer(implicitSearchContext.reportBuffer.errors.collect {
- case dte: DivergentImplicitTypeError => dte
- case ate: AmbiguousImplicitTypeError => ate
- })
- debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
- }
+
+ if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.reporter.hasErrors)
+ implicitSearchContext.reporter.propagateImplicitTypeErrorsTo(context.reporter)
+
// SI-7944 undetermined type parameters that result from inference within typedImplicit land in
// `implicitSearchContext.undetparams`, *not* in `context.undetparams`
// Here, we copy them up to parent context (analogously to the way the errors are copied above),
@@ -99,7 +96,7 @@ trait Implicits {
def wrapper(inference: => SearchResult) = wrapper1(inference)
val result = wrapper(inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos))
if (result.isFailure && !silent) {
- val err = context.firstError
+ val err = context.reporter.firstError
val errPos = err.map(_.errPos).getOrElse(pos)
val errMsg = err.map(_.errMsg).getOrElse("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
onError(errPos, errMsg)
@@ -635,7 +632,7 @@ trait Implicits {
}
case _ => fallback
}
- context.firstError match { // using match rather than foreach to avoid non local return.
+ context.reporter.firstError match { // using match rather than foreach to avoid non local return.
case Some(err) =>
log("implicit adapt failed: " + err.errMsg)
return fail(err.errMsg)
@@ -658,8 +655,8 @@ trait Implicits {
}
}
- if (context.hasErrors)
- fail("hasMatchingSymbol reported error: " + context.firstError.get.errMsg)
+ if (context.reporter.hasErrors)
+ fail("hasMatchingSymbol reported error: " + context.reporter.firstError.get.errMsg)
else if (itree3.isErroneous)
fail("error typechecking implicit candidate")
else if (isLocalToCallsite && !hasMatchingSymbol(itree2))
@@ -677,7 +674,7 @@ trait Implicits {
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
checkBounds(itree3, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg)
case None =>
@@ -716,7 +713,7 @@ trait Implicits {
case t => t
}
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg)
case None =>
@@ -857,13 +854,11 @@ trait Implicits {
SearchFailure
} else {
if (search.isFailure) {
- // We don't want errors that occur during checking implicit info
+ // Discard the divergentError we saved (if any), as well as all errors that are not of type DivergentImplicitTypeError
+ // We don't want errors that occur while checking the implicit info
// to influence the check of further infos, but we should retain divergent implicit errors
// (except for the one we already squirreled away)
- val saved = divergentError.getOrElse(null)
- context.reportBuffer.retainErrors {
- case err: DivergentImplicitTypeError => err ne saved
- }
+ context.reporter.retainDivergentErrorsExcept(divergentError.getOrElse(null))
}
search
}
@@ -909,7 +904,7 @@ trait Implicits {
// the first `DivergentImplicitTypeError` that is being propagated
// from a nested implicit search; this one will be
// re-issued if this level of the search fails.
- DivergentImplicitRecovery(typedFirstPending, firstPending, context.errors) match {
+ DivergentImplicitRecovery(typedFirstPending, firstPending, context.reporter.errors) match {
case sr if sr.isDivergent => Nil
case sr if sr.isFailure => rankImplicits(otherPending, acc)
case newBest =>
@@ -1146,7 +1141,7 @@ trait Implicits {
try {
val tree1 = typedPos(pos.focus)(arg)
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) => processMacroExpansionError(err.errPos, err.errMsg)
case None => new SearchResult(tree1, EmptyTreeTypeSubstituter, Nil)
}
@@ -1278,19 +1273,20 @@ trait Implicits {
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (ReflectRuntimeUniverse == NoSymbol) {
- // todo. write a test for this
- context.error(pos,
+ // TODO: write a test for this (the next error message is already checked by neg/interop_typetags_without_classtags_arenot_manifests.scala)
+ // TODO: this was using context.error, and implicit search always runs in silent mode, thus it was actually throwing a TypeError
+ // with the new strategy-based reporting, a BufferingReporter buffers instead of throwing
+ // it would be good to rework this logic to fit into the regular context.error mechanism
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath.
|to proceed put scala-reflect.jar on your compilation classpath and recompile.""")
- return SearchFailure
}
if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
- context.error(pos,
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
|to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""")
- return SearchFailure
}
val cm = typed(Ident(ReflectRuntimeCurrentMirror))
val internal = gen.mkAttributedSelect(gen.mkAttributedRef(ReflectRuntimeUniverse), UniverseInternal)
@@ -1346,52 +1342,66 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = if (Statistics.canEnable) Statistics.startTimer(inscopeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(inscopeSucceedNanos) else null
+ val stats = Statistics.canEnable
+ val failstart = if (stats) Statistics.startTimer(inscopeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(inscopeSucceedNanos) else null
var result = searchImplicit(context.implicitss, isLocalToCallsite = true)
- if (result.isFailure) {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits)
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(inscopeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ Statistics.incCounter(inscopeImplicitHits)
+ }
}
+
if (result.isFailure) {
- val previousErrs = context.flushAndReturnBuffer()
- val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null
+ val failstart = if (stats) Statistics.startTimer(oftypeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(oftypeSucceedNanos) else null
+
+ // SI-6667, never search companions after an ambiguous error in in-scope implicits
+ val wasAmbigious = result.isAmbiguousFailure
+
+ // TODO: encapsulate
+ val previousErrs = context.reporter.errors
+ context.reporter.clearAllErrors()
- val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits
result = materializeImplicit(pt)
+
// `materializeImplicit` does some preprocessing for `pt`
// is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
if (result.isFailure && !wasAmbigious)
result = searchImplicit(implicitsOfExpectedType, isLocalToCallsite = false)
- if (result.isFailure) {
- context.updateBuffer(previousErrs)
- if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(oftypeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
+ if (result.isFailure)
+ context.reporter ++= previousErrs
+
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(oftypeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ Statistics.incCounter(oftypeImplicitHits)
+ }
}
}
if (result.isSuccess && isView) {
def maybeInvalidConversionError(msg: String) {
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
+ // AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
if (context.ambiguousErrors)
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg))
}
pt match {
case Function1(_, out) =>
- def prohibit(sym: Symbol) = if (sym.tpe <:< out) {
- maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
- result = SearchFailure
+ // must inline to avoid capturing result
+ def prohibit(sym: Symbol) = (sym.tpe <:< out) && {
+ maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
+ true
}
- prohibit(AnyRefClass)
- if (settings.isScala211) prohibit(AnyValClass)
+ if (prohibit(AnyRefClass) || (settings.isScala211 && prohibit(AnyValClass)))
+ result = SearchFailure
case _ => false
}
if (settings.isScala211 && isInvalidConversionSource(pt)) {
@@ -1399,8 +1409,9 @@ trait Implicits {
result = SearchFailure
}
}
- if (result.isFailure)
- debuglog("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
+
+ if (result.isFailure && settings.debug) // debuglog is not inlined for some reason
+ log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
result
}
@@ -1422,20 +1433,19 @@ trait Implicits {
val eligible = new ImplicitComputation(iss, isLocalToCallsite).eligible
eligible.toList.flatMap {
(ii: ImplicitInfo) =>
- // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
- // thus, start each type var off with a fresh for every typedImplicit
- resetTVars()
- // any previous errors should not affect us now
- context.flushBuffer()
-
- val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
- if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
- else Nil
+ // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
+ // thus, start each type var off with a fresh for every typedImplicit
+ resetTVars()
+ // any previous errors should not affect us now
+ context.reporter.clearAllErrors()
+ val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
+ if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
+ else Nil
+ }
}
- }
eligibleInfos(context.implicitss, isLocalToCallsite = true) ++
eligibleInfos(implicitsOfExpectedType, isLocalToCallsite = false)
- }
+ }
}
object ImplicitNotFoundMsg {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index a3f1da60ce..fb7651ffd6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -199,8 +199,6 @@ trait Infer extends Checkable {
def getContext = context
- def issue(err: AbsTypeError): Unit = context.issue(err)
-
def explainTypes(tp1: Type, tp2: Type) = {
if (context.reportErrors)
withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2))
@@ -781,7 +779,7 @@ trait Infer extends Checkable {
def applicableExpectingPt(pt: Type): Boolean = {
val silent = context.makeSilent(reportAmbiguousErrors = false)
val result = newTyper(silent).infer.isApplicable(undetparams, ftpe, argtpes0, pt)
- if (silent.hasErrors && !pt.isWildcard)
+ if (silent.reporter.hasErrors && !pt.isWildcard)
applicableExpectingPt(WildcardType) // second try
else
result
@@ -1266,33 +1264,36 @@ trait Infer extends Checkable {
* If no alternative matches `pt`, take the parameterless one anyway.
*/
def inferExprAlternative(tree: Tree, pt: Type): Tree = {
- def tryOurBests(pre: Type, alts: List[Symbol], isSecondTry: Boolean): Unit = {
- val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
- val alts1 = if (alts0.isEmpty) alts else alts0
- val bests = bestAlternatives(alts1) { (sym1, sym2) =>
- val tp1 = pre memberType sym1
- val tp2 = pre memberType sym2
-
- ( (tp2 eq ErrorType)
- || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
- || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
- )
- }
- // todo: missing test case for bests.isEmpty
- bests match {
- case best :: Nil => tree setSymbol best setType (pre memberType best)
- case best :: competing :: _ if alts0.nonEmpty =>
- // SI-6912 Don't give up and leave an OverloadedType on the tree.
- // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
- // unless an error is issued. We're not issuing an error, in the assumption that it would be
- // spurious in light of the erroneous expected type
- if (pt.isErroneous) setError(tree)
- else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
- case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ val c = context
+ class InferTwice(pre: Type, alts: List[Symbol]) extends c.TryTwice {
+ def tryOnce(isSecondTry: Boolean): Unit = {
+ val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
+ val alts1 = if (alts0.isEmpty) alts else alts0
+ val bests = bestAlternatives(alts1) { (sym1, sym2) =>
+ val tp1 = pre memberType sym1
+ val tp2 = pre memberType sym2
+
+ ( (tp2 eq ErrorType)
+ || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
+ || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
+ )
+ }
+ // todo: missing test case for bests.isEmpty
+ bests match {
+ case best :: Nil => tree setSymbol best setType (pre memberType best)
+ case best :: competing :: _ if alts0.nonEmpty =>
+ // SI-6912 Don't give up and leave an OverloadedType on the tree.
+ // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
+ // unless an error is issued. We're not issuing an error, in the assumption that it would be
+ // spurious in light of the erroneous expected type
+ if (pt.isErroneous) setError(tree)
+ else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
+ case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ }
}
}
tree.tpe match {
- case OverloadedType(pre, alts) => tryTwice(tryOurBests(pre, alts, _)) ; tree
+ case OverloadedType(pre, alts) => (new InferTwice(pre, alts)).apply() ; tree
case _ => tree
}
}
@@ -1370,70 +1371,41 @@ trait Infer extends Checkable {
* @pre tree.tpe is an OverloadedType.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes0: List[Type], pt0: Type): Unit = {
- val OverloadedType(pre, alts) = tree.tpe
- var varargsStar = false
- val argtpes = argtpes0 mapConserve {
- case RepeatedType(tp) => varargsStar = true ; tp
- case tp => tp
- }
- def followType(sym: Symbol) = followApply(pre memberType sym)
- def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
- val applicable0 = alts filter (alt => context inSilentMode isApplicable(undetparams, followType(alt), argtpes, pt))
- val applicable = overloadsToConsiderBySpecificity(applicable0, argtpes, varargsStar)
- val ranked = bestAlternatives(applicable)((sym1, sym2) =>
- isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
- )
- ranked match {
- case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
- case best :: Nil => tree setSymbol best setType (pre memberType best) // success
- case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
- case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
- }
- }
- // This potentially makes up to four attempts: tryTwice may execute
+ // This potentially makes up to four attempts: tryOnce may execute
// with and without views enabled, and bestForExpectedType will try again
// with pt = WildcardType if it fails with pt != WildcardType.
- tryTwice { isLastTry =>
- val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
- debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
- bestForExpectedType(pt, isLastTry)
- }
- }
+ val c = context
+ class InferMethodAlternativeTwice extends c.TryTwice {
+ private[this] val OverloadedType(pre, alts) = tree.tpe
+ private[this] var varargsStar = false
+ private[this] val argtpes = argtpes0 mapConserve {
+ case RepeatedType(tp) => varargsStar = true ; tp
+ case tp => tp
+ }
- /** Try inference twice, once without views and once with views,
- * unless views are already disabled.
- */
- def tryTwice(infer: Boolean => Unit): Unit = {
- if (context.implicitsEnabled) {
- val savedContextMode = context.contextMode
- var fallback = false
- context.setBufferErrors()
- // We cache the current buffer because it is impossible to
- // distinguish errors that occurred before entering tryTwice
- // and our first attempt in 'withImplicitsDisabled'. If the
- // first attempt fails we try with implicits on *and* clean
- // buffer but that would also flush any pre-tryTwice valid
- // errors, hence some manual buffer tweaking is necessary.
- val errorsToRestore = context.flushAndReturnBuffer()
- try {
- context.withImplicitsDisabled(infer(false))
- if (context.hasErrors) {
- fallback = true
- context.contextMode = savedContextMode
- context.flushBuffer()
- infer(true)
+ private def followType(sym: Symbol) = followApply(pre memberType sym)
+ // separate method to help the inliner
+ private def isAltApplicable(pt: Type)(alt: Symbol) = context inSilentMode { isApplicable(undetparams, followType(alt), argtpes, pt) && !context.reporter.hasErrors }
+ private def rankAlternatives(sym1: Symbol, sym2: Symbol) = isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
+ private def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
+ val applicable = overloadsToConsiderBySpecificity(alts filter isAltApplicable(pt), argtpes, varargsStar)
+ val ranked = bestAlternatives(applicable)(rankAlternatives)
+ ranked match {
+ case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
+ case best :: Nil => tree setSymbol best setType (pre memberType best) // success
+ case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
+ case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
}
- } catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError => // recoverable cyclic references
- context.contextMode = savedContextMode
- if (!fallback) infer(true) else ()
- } finally {
- context.contextMode = savedContextMode
- context.updateBuffer(errorsToRestore)
+ }
+
+ private[this] val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
+ def tryOnce(isLastTry: Boolean): Unit = {
+ debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
+ bestForExpectedType(pt, isLastTry)
}
}
- else infer(true)
+
+ (new InferMethodAlternativeTwice).apply()
}
/** Assign `tree` the type of all polymorphic alternatives
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 33d3432ae2..da7b8b09aa 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -226,7 +226,8 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
val Apply(_, pickledPayload) = wrapped
val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap
- import typer.TyperErrorGen._
+ // TODO: refactor error handling: fail always throws a TypeError,
+ // and uses global state (analyzer.lastTreeToTyper) to determine the position for the error
def fail(msg: String) = MacroCantExpandIncompatibleMacrosError(msg)
def unpickle[T](field: String, clazz: Class[T]): T = {
def failField(msg: String) = fail(s"$field $msg")
@@ -624,7 +625,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
// therefore we need to re-enable the conversions back temporarily
val result = typer.context.withImplicitsEnabled(typer.typed(tree, mode, pt))
- if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reportBuffer.errors}")
+ if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reporter.errors}")
result
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 7bbd81118a..fdff2f3076 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -1494,8 +1494,7 @@ trait Namers extends MethodSynthesis {
case defn: MemberDef =>
val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann =>
val ctx = typer.context
- val annCtx = ctx.make(ann)
- annCtx.setReportErrors()
+ val annCtx = ctx.makeNonSilent(ann)
// need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892.
AnnotationInfo lazily {
enteringTyper(newTyper(annCtx) typedAnnotation ann)
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
index cf3f265f0c..da0e67a2a5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
@@ -261,7 +261,7 @@ trait PatternTypers {
def doTypedUnapply(tree: Tree, fun0: Tree, fun: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
if (args.length > MaxTupleArity)
return duplErrorTree(TooManyArgsPatternError(fun))
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 399a4ca8d5..743bbe53bd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -208,8 +208,7 @@ abstract class TreeCheckers extends Analyzer {
}
def check(unit: CompilationUnit) {
informProgress("checking "+unit)
- val context = rootContext(unit)
- context.checking = true
+ val context = rootContext(unit, checking = true)
tpeOfTree.clear()
SymbolTracker.check(phase, unit)
val checker = new TreeChecker(context)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 7440f69e93..89b064e7c1 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -572,11 +572,11 @@ trait TypeDiagnostics {
} else f
}
def apply(tree: Tree): Tree = {
- // Error suppression will squash some of these warnings unless we circumvent it.
+ // Error suppression (in context.warning) would squash some of these warnings.
// It is presumed if you are using a -Y option you would really like to hear
- // the warnings you've requested.
+ // the warnings you've requested; thus, use reporter.warning.
if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK)
- context.warning(tree.pos, "dead code following this construct", force = true)
+ reporter.warning(tree.pos, "dead code following this construct")
tree
}
@@ -629,7 +629,7 @@ trait TypeDiagnostics {
throw new FatalError("cannot redefine root "+sym)
}
case _ =>
- context0.error(ex.pos, ex)
+ context0.error(ex.pos, ex.msg)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 70f44c4fc6..0621fbefe4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -155,21 +155,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
} else {
mkArg = gen.mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args
if (!param.hasDefault && !paramFailed) {
- context.reportBuffer.errors.collectFirst {
- case dte: DivergentImplicitTypeError => dte
- } match {
- case Some(divergent) =>
- // DivergentImplicit error has higher priority than "no implicit found"
- // no need to issue the problem again if we are still in silent mode
- if (context.reportErrors) {
- context.issue(divergent.withPt(paramTp))
- context.reportBuffer.clearErrors {
- case dte: DivergentImplicitTypeError => true
- }
- }
- case _ =>
- NoImplicitFoundError(fun, param)
- }
+ context.reporter.reportFirstDivergentError(fun, param, paramTp)(context)
paramFailed = true
}
/* else {
@@ -478,20 +464,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (cond) typerWithLocalContext(c)(f) else f(this)
@inline
- final def typerWithLocalContext[T](c: Context)(f: Typer => T): T = {
- val res = f(newTyper(c))
- if (c.hasErrors)
- context.updateBuffer(c.flushAndReturnBuffer())
- res
- }
-
- @inline
- final def withSavedContext[T](c: Context)(f: => T) = {
- val savedErrors = c.flushAndReturnBuffer()
- val res = f
- c.updateBuffer(savedErrors)
- res
- }
+ final def typerWithLocalContext[T](c: Context)(f: Typer => T): T =
+ c.reporter.propagatingErrorsTo(context.reporter)(f(newTyper(c)))
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
@@ -684,6 +658,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (Statistics.canEnable) Statistics.stopCounter(subtypeFailed, subtypeStart)
if (Statistics.canEnable) Statistics.stopTimer(failedSilentNanos, failedSilentStart)
}
+ @inline def wrapResult(reporter: ContextReporter, result: T) =
+ if (reporter.hasErrors) {
+ stopStats()
+ SilentTypeError(reporter.errors: _*)
+ } else SilentResultValue(result)
+
try {
if (context.reportErrors ||
reportAmbiguousErrors != context.ambiguousErrors ||
@@ -697,20 +677,17 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- if (context1.hasErrors) {
- stopStats()
- SilentTypeError(context1.errors: _*)
- } else {
- // If we have a successful result, emit any warnings it created.
- context1.flushAndIssueWarnings()
- SilentResultValue(result)
- }
+
+ // If we have a successful result, emit any warnings it created.
+ if (!context1.reporter.hasErrors)
+ context1.reporter.emitWarnings()
+
+ wrapResult(context1.reporter, result)
} else {
assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
- withSavedContext(context){
- val res = op(this)
- val errorsToReport = context.flushAndReturnBuffer()
- if (errorsToReport.isEmpty) SilentResultValue(res) else SilentTypeError(errorsToReport.head)
+
+ context.reporter.withFreshErrorBuffer {
+ wrapResult(context.reporter, op(this))
}
}
} catch {
@@ -816,14 +793,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
// avoid throwing spurious DivergentImplicit errors
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else
withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree))(typer1 =>
if (original != EmptyTree && pt != WildcardType) (
typer1 silent { tpr =>
val withImplicitArgs = tpr.applyImplicitArgs(tree)
- if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway
+ if (tpr.context.reporter.hasErrors) tree // silent will wrap it in SilentTypeError anyway
else tpr.typed(withImplicitArgs, mode, pt)
}
orElse { _ =>
@@ -1057,7 +1034,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val silentContext = context.makeImplicit(context.ambiguousErrors)
val res = newTyper(silentContext).typed(
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- silentContext.firstError match {
+ silentContext.reporter.firstError match {
case Some(err) => context.issue(err)
case None => return res
}
@@ -2990,7 +2967,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ConstructorsOrderError(stat)
}
- if (treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
+ if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
@@ -3149,7 +3126,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
// TODO_NMT: check the assumption that args nonEmpty
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
def preSelectOverloaded(fun: Tree): Tree = {
if (fun.hasSymbolField && fun.symbol.isOverloaded) {
@@ -3229,7 +3206,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
(arg1, arg1.tpe.deconst)
}.unzip
}
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else {
inferMethodAlternative(fun, undetparams, argTpes, pt)
@@ -3357,8 +3334,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
duplErrTree
} else if (lencmp2 == 0) {
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
- val note = "Error occurred in an application involving default arguments."
- if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
+ context.diagUsedDefaults = true
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
rollbackNamesDefaultsOwnerChanges()
@@ -4331,7 +4307,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
c.retyping = true
try {
val res = newTyper(c).typedArgs(args, mode)
- if (c.hasErrors) None else Some(res)
+ if (c.reporter.hasErrors) None else Some(res)
} catch {
case ex: CyclicReference =>
throw ex
@@ -4395,7 +4371,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => ()
}
}
- typeErrors foreach issue
+ typeErrors foreach context.issue
setError(treeCopy.Apply(tree, fun, args))
}
@@ -4449,7 +4425,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
doTypedApply(tree, fun2, args, mode, pt)
case err: SilentTypeError =>
onError({
- err.reportableErrors foreach issue
+ err.reportableErrors foreach context.issue
args foreach (arg => typed(arg, mode, ErrorType))
setError(tree)
})
@@ -4686,7 +4662,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else
// before failing due to access, try a dynamic call.
asDynamicCall getOrElse {
- issue(accessibleError.get)
+ context.issue(accessibleError.get)
setError(tree)
}
case _ =>