diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 3 | ||||
-rw-r--r-- | test/files/neg/t3971.check | 21 | ||||
-rw-r--r-- | test/files/neg/t3971.scala | 12 |
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 +} |