Skip to content

Commit 476c93e

Browse files
committed
Better error messages involving apply's.
If typing with a compiler-inserted apply gives an error, but the tree `t` in question does have an `apply` method, continue reporting errors for `t.apply` instead of `t`. This is likely more informative than simply pretending there was no `apply` to insert.
1 parent 605c465 commit 476c93e

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,6 @@ class Typer extends Namer
19931993
* (but do this at most once per tree).
19941994
*
19951995
* After that, two strategies are tried, and the first that is successful is picked.
1996-
* If neither of the strategies are successful, continues with`fallBack`.
19971996
*
19981997
* 1st strategy: Try to insert `.apply` so that the result conforms to prototype `pt`.
19991998
* This strategy is not tried if the prototype represents already
@@ -2002,6 +2001,10 @@ class Typer extends Namer
20022001
* 2nd strategy: If tree is a select `qual.name`, try to insert an implicit conversion
20032002
* around the qualifier part `qual` so that the result conforms to the expected type
20042003
* with wildcard result type.
2004+
*
2005+
* If neither of the strategies are successful, continues with the `apply` result
2006+
* if an apply insertion was tried and `tree` has an `apply` method, or continues
2007+
* with `fallBack` otherwise. `fallBack` is supposed to always give an error.
20052008
*/
20062009
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType, locked: TypeVars)(fallBack: => Tree)(implicit ctx: Context): Tree = {
20072010

@@ -2023,7 +2026,7 @@ class Typer extends Namer
20232026
else try adapt(simplify(sel, pt, locked), pt, locked) finally sel.removeAttachment(InsertedApply)
20242027
}
20252028

2026-
def tryImplicit =
2029+
def tryImplicit(fallBack: => Tree) =
20272030
tryInsertImplicitOnQualifier(tree, pt, locked).getOrElse(fallBack)
20282031

20292032
pt match {
@@ -2034,8 +2037,17 @@ class Typer extends Namer
20342037
pt.markAsDropped()
20352038
tree
20362039
case _ =>
2037-
if (isApplyProto(pt) || isMethod(tree) || isSyntheticApply(tree)) tryImplicit
2038-
else tryEither(tryApply(_))((_, _) => tryImplicit)
2040+
if (isApplyProto(pt) || isMethod(tree) || isSyntheticApply(tree)) tryImplicit(fallBack)
2041+
else tryEither(tryApply(_)) { (app, appState) =>
2042+
tryImplicit {
2043+
if (tree.tpe.member(nme.apply).exists) {
2044+
// issue the error about the apply, since it is likely more informative than the fallback
2045+
appState.commit()
2046+
app
2047+
}
2048+
else fallBack
2049+
}
2050+
}
20392051
}
20402052
}
20412053

tests/neg/i4564.scala

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
object ClashOverloadNoSig {
2+
3+
private def apply(x: Int) = if (x > 0) new ClashOverloadNoSig(x) else apply("") // error: overloaded method apply needs result type
4+
5+
def apply(x: String): ClashOverloadNoSig = ???
6+
}
7+
8+
case class ClashOverloadNoSig private(x: Int)
9+
10+
object ClashRecNoSig {
11+
private def apply(x: Int) = if (x > 0) ClashRecNoSig(1) else ??? // error: recursive method apply needs result type
12+
}
13+
14+
case class ClashRecNoSig private(x: Int)
15+
16+
object NoClashNoSig {
17+
private def apply(x: Boolean) = if (x) NoClashNoSig(1) else ??? // error: overloaded method apply needs result type
18+
}
19+
20+
case class NoClashNoSig private(x: Int)
21+
22+
object NoClashOverload {
23+
private def apply(x: Boolean) = if (x) NoClashOverload(1) else apply("") // error: overloaded method apply needs result type
24+
25+
def apply(x: String): NoClashOverload = ???
26+
}
27+
28+
case class NoClashOverload private(x: Int)
29+
30+
31+
class BaseNCNSP[T] {
32+
def apply(x: T) = if (???) NoClashNoSigPoly(1) else ??? // error: overloaded method apply needs result type
33+
}
34+
35+
object NoClashNoSigPoly extends BaseNCNSP[Boolean]
36+
case class NoClashNoSigPoly private(x: Int) // error: recursive method apply needs result type
37+
38+
39+
40+
class BaseCNSP[T] {
41+
def apply(x: T) = if (???) ClashNoSigPoly(1) else ??? // error: recursive method apply needs result type
42+
}
43+
44+
object ClashNoSigPoly extends BaseCNSP[Int]
45+
// TODO: improve error message
46+
case class ClashNoSigPoly private(x: Int) // error: found: ClashNoSigPoly required: Nothing

0 commit comments

Comments
 (0)