Skip to content
Permalink
Browse files

More consistent solution for errorenous situations when infering the …

…alternative.

From now on we specify explicity which attempt is tried and setError on the tree
depending on that. Relying on the context was a nice idea to avoid that but was
fragile when we were in the silent mode (like checking named arguments).
  • Loading branch information
hubertp committed May 21, 2012
1 parent bbfbd66 commit 1ddc9358f551f4586adb1a540e0255fd0e5a33c9
@@ -690,35 +690,43 @@ trait ContextErrors {
setError(tree)
}

def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = {
// side-effect on the tree, break the overloaded type cycle in infer
private def setErrorOnLastTry(lastTry: Boolean, tree: Tree) = if (lastTry) setError(tree)

def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type, lastTry: Boolean) = {
issueNormalTypeError(tree,
applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
// since inferMethodAlternative modifies the state of the tree
// we have to set the type of tree to ErrorType only in the very last
// fallback action that is done in the inference (tracking it manually is error prone).
// fallback action that is done in the inference.
// This avoids entering infinite loop in doTypeApply.
if (implicitly[Context].reportErrors) setError(tree)
setErrorOnLastTry(lastTry, tree)
//if (implicitly[Context].reportErrors) setError(tree)
}

def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol,
firstCompeting: Symbol, argtpes: List[Type], pt: Type) = {
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)
// discover last attempt in a similar way as for NoBestMethodAlternativeError
if (implicitly[Context].ambiguousErrors) setError(tree)
issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
firstCompeting: Symbol, argtpes: List[Type], pt: Type, lastTry: Boolean) = {

if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) {
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)
setErrorOnLastTry(lastTry, tree)
issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
} 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)

}

def NoBestExprAlternativeError(tree: Tree, pt: Type) = {
def NoBestExprAlternativeError(tree: Tree, pt: Type, lastTry: Boolean) = {
issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(tree.symbol.tpe, pt, isPossiblyMissingArgs(tree.symbol.tpe, pt))))
if (implicitly[Context].reportErrors) setError(tree)
setErrorOnLastTry(lastTry, tree)
}

def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type) = {
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)
if (implicitly[Context].ambiguousErrors) setError(tree)
setErrorOnLastTry(lastTry, tree)
issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
}

@@ -1448,12 +1448,10 @@ trait Infer {
* If no alternative matches `pt`, take the parameterless one anyway.
*/
def inferExprAlternative(tree: Tree, pt: Type) = tree.tpe match {
case OverloadedType(pre, alts) => tryTwice {
val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt))
// secondTry is not a sufficient condition to decide whether that was our final attempt.
// This is because it doesn't take into account tryTwice implicits search option.
val secondTry = alts0.isEmpty
val alts1 = if (secondTry) alts else alts0
case OverloadedType(pre, alts) => tryTwice { isSecondTry =>
val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt))
val noAlternatives = alts0.isEmpty
val alts1 = if (noAlternatives) alts else alts0

//println("trying "+alts1+(alts1 map (_.tpe))+(alts1 map (_.locationString))+" for "+pt)
def improves(sym1: Symbol, sym2: Symbol): Boolean =
@@ -1481,10 +1479,10 @@ trait Infer {
}
}
// todo: missing test case
NoBestExprAlternativeError(tree, pt)
NoBestExprAlternativeError(tree, pt, isSecondTry)
} else if (!competing.isEmpty) {
if (secondTry) NoBestExprAlternativeError(tree, pt)
else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt)
if (noAlternatives) NoBestExprAlternativeError(tree, pt, isSecondTry)
else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt, isSecondTry)
} else {
// val applicable = alts1 filter (alt =>
// global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt))
@@ -1563,10 +1561,10 @@ trait Infer {
* assignment expression.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol],
argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match {
argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false, lastInferAttempt: Boolean = true): Unit = tree.tpe match {
case OverloadedType(pre, alts) =>
val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
tryTwice {
tryTwice { isSecondTry =>
debuglog("infer method alt "+ tree.symbol +" with alternatives "+
(alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt)

@@ -1588,13 +1586,10 @@ trait Infer {
if (improves(alt, best)) alt else best)
val competing = applicable.dropWhile(alt => best == alt || improves(best, alt))
if (best == NoSymbol) {
if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt)
else inferMethodAlternative(tree, undetparams, argtpes, WildcardType)
if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt, isSecondTry && lastInferAttempt)
else inferMethodAlternative(tree, undetparams, argtpes, WildcardType, lastInferAttempt = isSecondTry)
} else if (!competing.isEmpty) {
if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous)
AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt)
else setError(tree)
()
AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt, isSecondTry && lastInferAttempt)
} else {
// checkNotShadowed(tree.pos, pre, best, applicable)
tree.setSymbol(best).setType(pre.memberType(best))
@@ -1608,29 +1603,28 @@ trait Infer {
*
* @param infer ...
*/
def tryTwice(infer: => Unit): Unit = {
def tryTwice(infer: Boolean => Unit): Unit = {
if (context.implicitsEnabled) {
val saved = context.state
var fallback = false
context.setBufferErrors()
val res = try {
context.withImplicitsDisabled(infer)
try {
context.withImplicitsDisabled(infer(false))
if (context.hasErrors) {
fallback = true
context.restoreState(saved)
context.flushBuffer()
infer
infer(true)
}
} catch {
case ex: CyclicReference => throw ex
case ex: TypeError => // recoverable cyclic references
context.restoreState(saved)
if (!fallback) infer else ()
if (!fallback) infer(true) else ()
}
context.restoreState(saved)
res
}
else infer
else infer(true)
}

/** Assign <code>tree</code> the type of all polymorphic alternatives

0 comments on commit 1ddc935

Please sign in to comment.
You can’t perform that action at this time.