Skip to content

Commit aba158c

Browse files
committed
Improve error messages for overloading errors
We need to show argument lists after the first one if they were used for overloading resolution.
1 parent 903e6e5 commit aba158c

File tree

7 files changed

+54
-17
lines changed

7 files changed

+54
-17
lines changed

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

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,28 @@ object ErrorReporting {
6969
"\n(Note that variables need to be initialized to be defined)"
7070
else ""
7171

72+
/** Reveal arguments in FunProtos that are proteted by an IgnoredProto but were
73+
* revealed during type inference. This gives clearer error messages for overloading
74+
* resolution errors that need to show argument lists after the first. We do not
75+
* reveal other kinds of ignored prototypes since these might be misleading because
76+
* there might be a possible implicit conversion on the result.
77+
*/
78+
def revealDeepenedArgs(tp: Type): Type = tp match
79+
case tp @ IgnoredProto(deepTp: FunProto) if tp.wasDeepened => deepTp
80+
case _ => tp
81+
7282
def expectedTypeStr(tp: Type): String = tp match {
7383
case tp: PolyProto =>
74-
em"type arguments [${tp.targs.tpes}%, %] and ${expectedTypeStr(tp.resultType)}"
84+
em"type arguments [${tp.targs.tpes}%, %] and ${expectedTypeStr(revealDeepenedArgs(tp.resultType))}"
7585
case tp: FunProto =>
76-
val result = tp.resultType match {
77-
case _: WildcardType | _: IgnoredProto => ""
78-
case tp => em" and expected result type $tp"
79-
}
80-
em"arguments (${tp.typedArgs().tpes}%, %)$result"
86+
def argStr(tp: FunProto): String =
87+
val result = revealDeepenedArgs(tp.resultType) match {
88+
case restp: FunProto => argStr(restp)
89+
case _: WildcardType | _: IgnoredProto => ""
90+
case tp => em" and expected result type $tp"
91+
}
92+
em"(${tp.typedArgs().tpes}%, %)$result"
93+
s"arguments ${argStr(tp)}"
8194
case _ =>
8295
em"expected type $tp"
8396
}
@@ -125,25 +138,25 @@ object ErrorReporting {
125138
def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailureType = NoMatchingImplicits): Tree = {
126139
val normTp = normalize(tree.tpe, pt)
127140
val normPt = normalize(pt, pt)
128-
141+
129142
def contextFunctionCount(tp: Type): Int = tp.stripped match
130143
case defn.ContextFunctionType(_, restp, _) => 1 + contextFunctionCount(restp)
131144
case _ => 0
132145
def strippedTpCount = contextFunctionCount(tree.tpe) - contextFunctionCount(normTp)
133146
def strippedPtCount = contextFunctionCount(pt) - contextFunctionCount(normPt)
134-
147+
135148
val (treeTp, expectedTp) =
136149
if normTp <:< normPt || strippedTpCount != strippedPtCount
137150
then (tree.tpe, pt)
138151
else (normTp, normPt)
139152
// use normalized types if that also shows an error, and both sides stripped
140153
// the same number of context functions. Use original types otherwise.
141-
154+
142155
def missingElse = tree match
143156
case If(_, _, elsep @ Literal(Constant(()))) if elsep.span.isSynthetic =>
144157
"\nMaybe you are missing an else part for the conditional?"
145158
case _ => ""
146-
159+
147160
errorTree(tree, TypeMismatch(treeTp, expectedTp, Some(tree), implicitFailure.whyNoConversion, missingElse))
148161
}
149162

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,18 @@ object ProtoTypes {
131131

132132
/** A class marking ignored prototypes that can be revealed by `deepenProto` */
133133
abstract case class IgnoredProto(ignored: Type) extends CachedGroundType with MatchAlways:
134+
private var myWasDeepened = false
134135
override def revealIgnored = ignored
135-
override def deepenProto(using Context): Type = ignored
136+
override def deepenProto(using Context): Type =
137+
myWasDeepened = true
138+
ignored
136139
override def deepenProtoTrans(using Context): Type = ignored.deepenProtoTrans
137140

141+
/** Did someone look inside via deepenProto? Used for error deagniostics
142+
* to give a more extensive expected type.
143+
*/
144+
def wasDeepened: Boolean = myWasDeepened
145+
138146
override def computeHash(bs: Hashable.Binders): Int = doHash(bs, ignored)
139147

140148
override def eql(that: Type): Boolean = that match

tests/neg/i10901.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| (x: T1)
1616
| (y: BugExp4Point2D.ColumnType[T2])
1717
| (implicit evidence$5: Numeric[T1], evidence$6: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
18-
| both match arguments ((x : BugExp4Point2D.IntT.type))
18+
| both match arguments ((x : BugExp4Point2D.IntT.type))((y : BugExp4Point2D.DoubleT.type))
1919
-- [E008] Not Found Error: tests/neg/i10901.scala:48:38 ----------------------------------------------------------------
2020
48 | val pos4: Point2D[Int,Double] = x º 201.1 // error
2121
| ^^^
@@ -29,7 +29,7 @@
2929
| (x: BugExp4Point2D.ColumnType[T1])
3030
| (y: T2)(implicit evidence$9: Numeric[T1], evidence$10: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
3131
| [T1, T2](x: T1)(y: T2)(implicit evidence$3: Numeric[T1], evidence$4: Numeric[T2]): BugExp4Point2D.Point2D[T1, T2]
32-
| both match arguments ((x : BugExp4Point2D.IntT.type))
32+
| both match arguments ((x : BugExp4Point2D.IntT.type))((201.1d : Double))
3333
-- [E008] Not Found Error: tests/neg/i10901.scala:62:16 ----------------------------------------------------------------
3434
62 | val y = "abc".foo // error
3535
| ^^^^^^^^^

tests/neg/i15000.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
| Ambiguous overload. The overloaded alternatives of method apply in object ExtensionMethodReproduction with types
2222
| (c: ExtensionMethodReproduction.C)(x: Int, y: Int): String
2323
| (c: ExtensionMethodReproduction.C)(x: Int, y: String): String
24-
| both match arguments (ExtensionMethodReproduction.c.type)
24+
| both match arguments (ExtensionMethodReproduction.c.type)((ExtensionMethodReproduction.x : Int), <error Not found: barY>)

tests/neg/i15287.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- [E134] Type Error: tests/neg/i15287.scala:4:19 ----------------------------------------------------------------------
2+
4 |@main def Test() = f('c')(2) // error
3+
| ^
4+
| None of the overloaded alternatives of method f with types
5+
| (x: Char)(min: Boolean, max: Int): String
6+
| (x: Char)(someParam: String): String
7+
| match arguments (('c' : Char))((2 : Int))

tests/neg/i15287.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def f(x: Char)(someParam: String): String = "a"
2+
def f(x: Char)(min: Boolean, max: Int = 4): String = "b"
3+
4+
@main def Test() = f('c')(2) // error

tests/run/i15287.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
def f(x: Char)(someParam: String): String = "a"
2-
def f(x: Char)(min: Boolean, max: Int = 4): String = "b"
1+
extension (x: Char)
2+
def f(someParam: String): String = "a"
3+
def f(min: Boolean, max: Int = 4): String = "b"
4+
5+
@main def Test() =
6+
f('c')(false)
7+
'c'.f(true)
8+
'c'.f("a")
39

4-
@main def Test() = f('c')(false)

0 commit comments

Comments
 (0)