Skip to content

Commit c7d4187

Browse files
committed
Fix #7883: Better error message for unapplySeq matches
1 parent 30f8c6f commit c7d4187

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -327,4 +327,7 @@ abstract class Reporter extends interfaces.ReporterResult {
327327
/** Issue all error messages in this reporter to next outer one, or make sure they are written. */
328328
def flush()(implicit ctx: Context): Unit =
329329
removeBufferedMessages.foreach(ctx.reporter.report)
330+
331+
/** If this reporter buffers messages, all buffered messages, otherwise Nil */
332+
def pendingMessages(using Context): List[MessageContainer] = Nil
330333
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@ class StoreReporter(outer: Reporter) extends Reporter {
3838
if (infos != null) try infos.toList finally infos = null
3939
else Nil
4040

41+
override def pendingMessages(using Context): List[MessageContainer] = infos.toList
42+
4143
override def errorsReported: Boolean = hasErrors || (outer != null && outer.errorsReported)
4244
}

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

+21-10
Original file line numberDiff line numberDiff line change
@@ -1066,22 +1066,28 @@ trait Applications extends Compatibility {
10661066
if (!tree.tpe.isError && tree.tpe.isErroneous) tree
10671067
else errorTree(tree, NotAnExtractor(qual))
10681068

1069+
/** Does `state` contain a single "NotAMember" message as pending error message
1070+
* that says `$membername is not a member of ...` ?
1071+
*/
1072+
def saysNotAMember(state: TyperState, memberName: TermName): Boolean =
1073+
state.reporter.pendingMessages match
1074+
case msg :: Nil =>
1075+
msg.contained match
1076+
case NotAMember(_, name, _, _) => name == memberName
1077+
case _ => false
1078+
case _ => false
1079+
10691080
/** Report errors buffered in state.
10701081
* @pre state has errors to report
10711082
* If there is a single error stating that "unapply" is not a member, print
10721083
* the more informative "notAnExtractor" message instead.
10731084
*/
10741085
def reportErrors(tree: Tree, state: TyperState): Tree =
10751086
assert(state.reporter.hasErrors)
1076-
val msgs = state.reporter.removeBufferedMessages
1077-
msgs match
1078-
case msg :: Nil =>
1079-
msg.contained match
1080-
case NotAMember(_, nme.unapply, _, _) => return notAnExtractor(tree)
1081-
case _ =>
1082-
case _ =>
1083-
msgs.foreach(ctx.reporter.report)
1084-
tree
1087+
if saysNotAMember(state, nme.unapply) then notAnExtractor(tree)
1088+
else
1089+
state.reporter.flush()
1090+
tree
10851091

10861092
/** If this is a term ref tree, try to typecheck with its type name.
10871093
* If this refers to a type alias, follow the alias, and if
@@ -1145,7 +1151,12 @@ trait Applications extends Compatibility {
11451151
tryWithName(nme.unapply) {
11461152
(sel, state) =>
11471153
tryWithName(nme.unapplySeq) {
1148-
(_, _) => fallBack(sel, state)
1154+
(sel2, state2) =>
1155+
// if both fail, return unapply error, unless that is simply a
1156+
// "not a member", and the unapplySeq error is more refined.
1157+
if saysNotAMember(state, nme.unapply) && !saysNotAMember(state2, nme.unapplySeq)
1158+
then fallBack(sel2, state2)
1159+
else fallBack(sel, state)
11491160
}
11501161
}
11511162
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- [E134] Type Mismatch Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:11 -----------------------------------
2+
6 | case r(hd, tl) => Some((hd, tl)) // error // error // error
3+
| ^
4+
| None of the overloaded alternatives of method unapplySeq in class Regex with types
5+
| (m: scala.util.matching.Regex.Match): Option[List[String]]
6+
| (c: Char): Option[List[Char]]
7+
| (s: CharSequence): Option[List[String]]
8+
| match arguments (String | UncheckedNull)
9+
-- [E006] Unbound Identifier Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:30 ------------------------------
10+
6 | case r(hd, tl) => Some((hd, tl)) // error // error // error
11+
| ^^
12+
| Not found: hd
13+
14+
longer explanation available when compiling with `-explain`
15+
-- [E006] Unbound Identifier Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:34 ------------------------------
16+
6 | case r(hd, tl) => Some((hd, tl)) // error // error // error
17+
| ^^
18+
| Not found: tl
19+
20+
longer explanation available when compiling with `-explain`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.util.matching.Regex
2+
3+
object Test extends App {
4+
def head(s: String, r: Regex): Option[(String, String)] =
5+
s.trim match {
6+
case r(hd, tl) => Some((hd, tl)) // error // error // error
7+
case _ => None
8+
}
9+
}

0 commit comments

Comments
 (0)