summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--test/files/neg/t3971.check21
-rw-r--r--test/files/neg/t3971.scala12
4 files changed, 47 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 1f4d5cbac2..f893e4f0ff 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -157,6 +157,16 @@ trait ContextErrors {
}
def AdaptTypeError(tree: Tree, found: Type, req: Type) = {
+ // SI-3971 unwrapping to the outermost Apply helps prevent confusion with the
+ // error message point.
+ def callee = {
+ def unwrap(t: Tree): Tree = t match {
+ case Apply(app: Apply, _) => unwrap(app)
+ case _ => t
+ }
+ unwrap(tree)
+ }
+
// If the expected type is a refinement type, and the found type is a refinement or an anon
// class, we can greatly improve the error message by retyping the tree to recover the actual
// members present, then display along with the expected members. This is done here because
@@ -181,7 +191,7 @@ trait ContextErrors {
}
assert(!foundType.isErroneous && !req.isErroneous, (foundType, req))
- issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(foundType, req)))
+ issueNormalTypeError(callee, withAddendum(callee.pos)(typeErrorMsg(foundType, req)))
infer.explainTypes(foundType, req)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 157c6ba4de..d88a615c7f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4177,6 +4177,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case If(_, t, e) => treesInResult(t) ++ treesInResult(e)
case Try(b, catches, _) => treesInResult(b) ++ catches
case Typed(r, Function(Nil, EmptyTree)) => treesInResult(r)
+ case Select(qual, name) => treesInResult(qual)
+ case Apply(fun, args) => treesInResult(fun) ++ args.flatMap(treesInResult)
+ case TypeApply(fun, args) => treesInResult(fun) ++ args.flatMap(treesInResult)
case _ => Nil
})
def errorInResult(tree: Tree) = treesInResult(tree) exists (_.pos == typeError.errPos)
diff --git a/test/files/neg/t3971.check b/test/files/neg/t3971.check
new file mode 100644
index 0000000000..8685119876
--- /dev/null
+++ b/test/files/neg/t3971.check
@@ -0,0 +1,21 @@
+t3971.scala:6: error: type mismatch;
+ found : Int
+ required: String
+ f(g("abc")("def")) // g returns Int, needs String
+ ^
+t3971.scala:7: error: type mismatch;
+ found : Int(5)
+ required: String
+ f(5)
+ ^
+t3971.scala:8: error: type mismatch;
+ found : Int
+ required: String
+ f(h("abc"))
+ ^
+t3971.scala:11: error: type mismatch;
+ found : Boolean
+ required: String
+ ({"ab".reverse; "ba".equals})(0): String
+ ^
+four errors found
diff --git a/test/files/neg/t3971.scala b/test/files/neg/t3971.scala
new file mode 100644
index 0000000000..35f64fde0c
--- /dev/null
+++ b/test/files/neg/t3971.scala
@@ -0,0 +1,12 @@
+class A {
+ def f(x: String) = x
+ def g(x: String)(y: String): Int = x.length + y.length
+ def h(x: String) = x.length
+
+ f(g("abc")("def")) // g returns Int, needs String
+ f(5)
+ f(h("abc"))
+
+ // a perverse piece of code from a perverse coder
+ ({"ab".reverse; "ba".equals})(0): String
+}