Skip to content

Commit 03681c5

Browse files
mbovelWojciechMazur
authored andcommitted
Add note about type mismatch in automatically inserted apply argument
Co-Authored-By: Jan-Pieter van den Heuvel <1197006+jan-pieter@users.noreply.github.com> Co-Authored-By: Lucas Nouguier <lucas.nouguier@protonmail.com> [Cherry-picked 2c70f3d]
1 parent a04403c commit 03681c5

File tree

9 files changed

+103
-4
lines changed

9 files changed

+103
-4
lines changed

compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ class ExploringReporter extends StoreReporter(null, fromTyperState = false):
1818
override def removeBufferedMessages(using Context): List[Diagnostic] =
1919
try infos.toList finally reset()
2020

21+
override def mapBufferedMessages(f: Diagnostic => Diagnostic)(using Context): Unit =
22+
infos.mapInPlace(f)
23+
2124
def reset(): Unit = infos.clear()
2225

23-
end ExploringReporter
26+
end ExploringReporter

compiler/src/dotty/tools/dotc/reporting/Reporter.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ abstract class Reporter extends interfaces.ReporterResult {
270270
/** If this reporter buffers messages, remove and return all buffered messages. */
271271
def removeBufferedMessages(using Context): List[Diagnostic] = Nil
272272

273+
/** If this reporter buffers messages, apply `f` to all buffered messages. */
274+
def mapBufferedMessages(f: Diagnostic => Diagnostic)(using Context): Unit = ()
275+
273276
/** Issue all messages in this reporter to next outer one, or make sure they are written. */
274277
def flush()(using Context): Unit =
275278
val msgs = removeBufferedMessages

compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class StoreReporter(outer: Reporter | Null = Reporter.NoReporter, fromTyperState
2121

2222
protected var infos: mutable.ListBuffer[Diagnostic] | Null = null
2323

24-
def doReport(dia: Diagnostic)(using Context): Unit = {
24+
override def doReport(dia: Diagnostic)(using Context): Unit = {
2525
typr.println(s">>>> StoredError: ${dia.message}") // !!! DEBUG
2626
if (infos == null) infos = new mutable.ListBuffer
2727
infos.uncheckedNN += dia
@@ -37,6 +37,9 @@ class StoreReporter(outer: Reporter | Null = Reporter.NoReporter, fromTyperState
3737
if (infos != null) try infos.uncheckedNN.toList finally infos = null
3838
else Nil
3939

40+
override def mapBufferedMessages(f: Diagnostic => Diagnostic)(using Context): Unit =
41+
if infos != null then infos.uncheckedNN.mapInPlace(f)
42+
4043
override def pendingMessages(using Context): List[Diagnostic] =
4144
if (infos != null) infos.uncheckedNN.toList else Nil
4245

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ extends NotFoundMsg(MissingIdentID) {
287287
}
288288
}
289289

290-
class TypeMismatch(val found: Type, expected: Type, inTree: Option[untpd.Tree], addenda: => String*)(using Context)
290+
class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tree], addenda: => String*)(using Context)
291291
extends TypeMismatchMsg(found, expected)(TypeMismatchID):
292292

293293
def msg(using Context) =

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,37 @@ trait Applications extends Compatibility {
10801080
simpleApply(fun1, proto)
10811081
} {
10821082
(failedVal, failedState) =>
1083-
def fail = { failedState.commit(); failedVal }
1083+
def fail =
1084+
insertedApplyNote()
1085+
failedState.commit()
1086+
failedVal
1087+
1088+
/** If the applied function is an automatically inserted `apply`
1089+
* method and one of its arguments has a type mismatch , append
1090+
* a note to the error message that explains where the required
1091+
* type comes from. See #19680 and associated test case.
1092+
*/
1093+
def insertedApplyNote() =
1094+
if fun1.symbol.name == nme.apply && fun1.span.isSynthetic then
1095+
fun1 match
1096+
case Select(qualifier, _) =>
1097+
failedState.reporter.mapBufferedMessages:
1098+
case dia: Diagnostic.Error =>
1099+
dia.msg match
1100+
case msg: TypeMismatch =>
1101+
msg.inTree match
1102+
case Some(arg) if tree.args.exists(_.span == arg.span) =>
1103+
val Select(qualifier, _) = fun1: @unchecked
1104+
val noteText =
1105+
i"""The required type comes from a parameter of the automatically
1106+
|inserted `apply` method of `${qualifier.tpe}`,
1107+
|which is the type of `${qualifier.show}`.""".stripMargin
1108+
Diagnostic.Error(msg.appendExplanation("\n\n" + noteText), dia.pos)
1109+
case _ => dia
1110+
case msg => dia
1111+
case dia => dia
1112+
case _ => ()
1113+
10841114
// Try once with original prototype and once (if different) with tupled one.
10851115
// The reason we need to try both is that the decision whether to use tupled
10861116
// or not was already taken but might have to be revised when an implicit

tests/neg/19680.check

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- [E007] Type Mismatch Error: tests/neg/19680.scala:9:67 --------------------------------------------------------------
2+
9 |def renderWidget(using Config): Unit = renderWebsite("/tmp")(Config()) // error: found Config, required Int
3+
| ^^^^^^^^
4+
| Found: Config
5+
| Required: Int
6+
|---------------------------------------------------------------------------------------------------------------------
7+
| Explanation (enabled by `-explain`)
8+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9+
|
10+
| Tree: new Config()
11+
| I tried to show that
12+
| Config
13+
| conforms to
14+
| Int
15+
| but none of the attempts shown below succeeded:
16+
|
17+
| ==> Config <: Int = false
18+
|
19+
| The tests were made under the empty constraint
20+
|
21+
| The required type comes from a parameter of the automatically
22+
| inserted `apply` method of `scala.collection.StringOps`,
23+
| which is the type of `augmentString(renderWebsite("/tmp")(x$1))`.
24+
---------------------------------------------------------------------------------------------------------------------

tests/neg/19680.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//> using options -explain
2+
3+
// Tests that the error message indicates that the required type `Int` comes
4+
// from the automatically inserted `apply` method of `String`. This note is
5+
// inserted by `insertedApplyNote` in `Applications`.
6+
7+
class Config()
8+
def renderWebsite(path: String)(using config: Config): String = ???
9+
def renderWidget(using Config): Unit = renderWebsite("/tmp")(Config()) // error: found Config, required Int

tests/neg/19680b.check

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- [E007] Type Mismatch Error: tests/neg/19680b.scala:2:21 -------------------------------------------------------------
2+
2 |def Test = List(1,2)("hello") // error: found String, required Int
3+
| ^^^^^^^
4+
| Found: ("hello" : String)
5+
| Required: Int
6+
|---------------------------------------------------------------------------------------------------------------------
7+
| Explanation (enabled by `-explain`)
8+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9+
|
10+
| Tree: "hello"
11+
| I tried to show that
12+
| ("hello" : String)
13+
| conforms to
14+
| Int
15+
| but none of the attempts shown below succeeded:
16+
|
17+
| ==> ("hello" : String) <: Int
18+
| ==> String <: Int = false
19+
|
20+
| The tests were made under the empty constraint
21+
|
22+
| The required type comes from a parameter of the automatically
23+
| inserted `apply` method of `List[Int]`,
24+
| which is the type of `List.apply[Int]([1,2 : Int]*)`.
25+
---------------------------------------------------------------------------------------------------------------------

tests/neg/19680b.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
//> using options -explain
2+
def Test = List(1,2)("hello") // error: found String, required Int

0 commit comments

Comments
 (0)