summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2012-05-22 15:56:17 -0700
committerAdriaan Moors <adriaan.moors@epfl.ch>2012-05-22 15:56:17 -0700
commitffd2602977ccbdea34f7c233299c89e1d9152c5d (patch)
treec9e734b1d9821f618513bdc674aca3647528174c
parent9dae0deb1cd5d1f0cdc81d45a2b681a65a709b0d (diff)
parentd8b83375379f35c90ca980ef6f1467937cc9764a (diff)
downloadscala-ffd2602977ccbdea34f7c233299c89e1d9152c5d.tar.gz
scala-ffd2602977ccbdea34f7c233299c89e1d9152c5d.tar.bz2
scala-ffd2602977ccbdea34f7c233299c89e1d9152c5d.zip
Merge pull request #602 from hubertp/issue/5735
Closes SI-5735. Review by @adriaanm.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala38
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala40
-rw-r--r--test/files/neg/t5735.check6
-rw-r--r--test/files/neg/t5735.scala7
4 files changed, 55 insertions, 36 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index eb3a1ffb5b..affa9cd63b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -690,34 +690,44 @@ 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
+ @inline
+ 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)
}
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)
+ issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, 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)
+
}
- 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))))
+ 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)
- setError(tree)
issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg))
+ setErrorOnLastTry(lastTry, tree)
}
// checkBounds
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 1c1adee343..839cdee301 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1449,10 +1449,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))
- 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 =
@@ -1480,10 +1480,10 @@ trait Infer {
}
}
// todo: missing test case
- NoBestExprAlternativeError(tree, pt)
+ NoBestExprAlternativeError(tree, pt, isSecondTry)
} else if (!competing.isEmpty) {
- if (secondTry) { NoBestExprAlternativeError(tree, pt); setError(tree) }
- 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))
@@ -1562,10 +1562,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)
@@ -1587,13 +1587,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))
@@ -1607,29 +1604,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
diff --git a/test/files/neg/t5735.check b/test/files/neg/t5735.check
new file mode 100644
index 0000000000..f6e0028044
--- /dev/null
+++ b/test/files/neg/t5735.check
@@ -0,0 +1,6 @@
+t5735.scala:6: error: type mismatch;
+ found : (x: Int)Int <and> => String
+ required: Int
+ val z: Int = a
+ ^
+one error found
diff --git a/test/files/neg/t5735.scala b/test/files/neg/t5735.scala
new file mode 100644
index 0000000000..fde71ff962
--- /dev/null
+++ b/test/files/neg/t5735.scala
@@ -0,0 +1,7 @@
+abstract class Base {
+ def a: String = "one"
+}
+class Clazz extends Base {
+ def a(x: Int): Int = 2
+ val z: Int = a
+}