diff options
4 files changed, 54 insertions, 46 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 5dd945eaea..a0660ce71d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -21,39 +21,39 @@ trait ContextErrors { import global._ import definitions._ - object ErrorKinds extends Enumeration { - type ErrorKind = Value - val Normal, Access, Ambiguous, Divergent = Value - } - - import ErrorKinds.ErrorKind - - trait AbsTypeError extends Throwable { + abstract class AbsTypeError extends Throwable { def errPos: Position def errMsg: String - def kind: ErrorKind + override def toString() = "[Type error at:" + errPos + "] " + errMsg } - case class NormalTypeError(underlyingTree: Tree, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) - extends AbsTypeError { - - def errPos:Position = underlyingTree.pos - override def toString() = "[Type error at:" + underlyingTree.pos + "] " + errMsg + abstract class TreeTypeError extends AbsTypeError { + def underlyingTree: Tree + def errPos = underlyingTree.pos } - case class SymbolTypeError(underlyingSym: Symbol, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) + case class NormalTypeError(underlyingTree: Tree, errMsg: String) + extends TreeTypeError + + 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 { def errPos = underlyingSym.pos } - case class TypeErrorWrapper(ex: TypeError, kind: ErrorKind = ErrorKinds.Normal) + case class TypeErrorWrapper(ex: TypeError) extends AbsTypeError { def errMsg = ex.msg def errPos = ex.pos } - case class TypeErrorWithUnderlyingTree(tree: Tree, ex: TypeError, kind: ErrorKind = ErrorKinds.Normal) + case class TypeErrorWithUnderlyingTree(tree: Tree, ex: TypeError) extends AbsTypeError { def errMsg = ex.msg def errPos = tree.pos @@ -67,18 +67,19 @@ trait ContextErrors { // (pt at the point of divergence gives less information to the user) // Note: it is safe to delay error message generation in this case // becasue we don't modify implicits' infos. - case class DivergentImplicitTypeError(tree: Tree, pt0: Type, sym: Symbol) extends AbsTypeError { - def errPos: Position = tree.pos + case class DivergentImplicitTypeError(underlyingTree: Tree, pt0: Type, sym: Symbol) + extends TreeTypeError { def errMsg: String = errMsgForPt(pt0) - def kind = ErrorKinds.Divergent - def withPt(pt: Type): AbsTypeError = NormalTypeError(tree, errMsgForPt(pt), kind) + def withPt(pt: Type): AbsTypeError = this.copy(pt0 = pt) private def errMsgForPt(pt: Type) = s"diverging implicit expansion for type ${pt}\nstarting with ${sym.fullLocationString}" } - case class AmbiguousTypeError(underlyingTree: Tree, errPos: Position, errMsg: String, kind: ErrorKind = ErrorKinds.Ambiguous) extends AbsTypeError + case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String) + extends TreeTypeError - case class PosAndMsgTypeError(errPos: Position, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError + case class PosAndMsgTypeError(errPos: Position, errMsg: String) + extends AbsTypeError object ErrorUtils { def issueNormalTypeError(tree: Tree, msg: String)(implicit context: Context) { @@ -89,7 +90,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) } @@ -844,7 +844,7 @@ trait ContextErrors { underlyingSymbol(sym).fullLocationString + " cannot be accessed in " + location + explanation } - NormalTypeError(tree, errMsg, ErrorKinds.Access) + AccessTypeError(tree, errMsg) } def NoMethodInstanceError(fn: Tree, args: List[Tree], msg: String) = @@ -889,7 +889,7 @@ trait ContextErrors { "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(tree, pos, msg)) + issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg)) 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) @@ -903,7 +903,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(tree, pos, msg)) + issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg)) setErrorOnLastTry(lastTry, tree) } @@ -1188,7 +1188,7 @@ trait ContextErrors { if (explanation == "") "" else "\n" + explanation ) } - context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, + context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, if (isView) viewMsg else s"ambiguous implicit values:\n${coreMsg}match expected type $pt") ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 538b3b3b6c..f7b4a60144 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1195,12 +1195,12 @@ trait Contexts { self: Analyzer => errorBuffer.clear() this } - def clearErrors(kind: ErrorKinds.ErrorKind): this.type = { - errorBuffer.retain(_.kind != kind) + def clearErrors(removeF: PartialFunction[AbsTypeError, Boolean]): this.type = { + errorBuffer.retain(!PartialFunction.cond(_)(removeF)) this } - def retainErrors(kind: ErrorKinds.ErrorKind): this.type = { - errorBuffer.retain(_.kind == kind) + def retainErrors(leaveF: PartialFunction[AbsTypeError, Boolean]): this.type = { + errorBuffer.retain(PartialFunction.cond(_)(leaveF)) this } def clearAllWarnings(): this.type = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 59ed64ac03..875aa5a9d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -81,7 +81,10 @@ trait Implicits { 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.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent)) + context.updateBuffer(implicitSearchContext.reportBuffer.errors.collect { + case dte: DivergentImplicitTypeError => dte + case ate: AmbiguousImplicitTypeError => ate + }) debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors) } printInference("[infer implicit] inferred " + result) @@ -590,7 +593,7 @@ trait Implicits { case Some(err) => log("implicit adapt failed: " + err.errMsg) return fail(err.errMsg) - case None => + case None => } if (Statistics.canEnable) Statistics.incCounter(typedImplicits) @@ -639,7 +642,7 @@ trait Implicits { context.firstError match { case Some(err) => return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg) - case None => + case None => } // filter out failures from type inference, don't want to remove them from undetParams! @@ -678,7 +681,7 @@ trait Implicits { context.firstError match { case Some(err) => fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg) - case None => + case None => val result = new SearchResult(itree2, subst) if (Statistics.canEnable) Statistics.incCounter(foundImplicits) printInference("[success] found %s for pt %s".format(result, ptInstantiated)) @@ -839,7 +842,9 @@ trait Implicits { case sr if sr.isFailure => // We don't want errors that occur during checking implicit info // to influence the check of further infos. - context.reportBuffer.retainErrors(ErrorKinds.Divergent) + context.reportBuffer.retainErrors { + case err: DivergentImplicitTypeError => true + } rankImplicits(is, acc) case newBest => best = newBest diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 637abe4be2..fcdc4c1a9c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -150,15 +150,19 @@ trait Typers extends Adaptations with Tags { } 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.find(_.kind == ErrorKinds.Divergent) match { - case Some(divergent: DivergentImplicitTypeError) => + 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(ErrorKinds.Divergent) + context.reportBuffer.clearErrors { + case dte: DivergentImplicitTypeError => true + } } - case None => + case _ => NoImplicitFoundError(fun, param) } paramFailed = true @@ -4688,12 +4692,11 @@ trait Typers extends Adaptations with Tags { case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) } val (result, accessibleError) = silent(_.makeAccessible(tree1, sym, qual.tpe, qual)) match { + case SilentTypeError(err: AccessTypeError) => + (tree1, Some(err)) case SilentTypeError(err) => - if (err.kind != ErrorKinds.Access) { - context issue err - return setError(tree) - } - else (tree1, Some(err)) + context issue err + return setError(tree) case SilentResultValue(treeAndPre) => (stabilize(treeAndPre._1, treeAndPre._2, mode, pt), None) } |