Skip to content

Commit 08373f4

Browse files
committed
add error message for missing unapply on pattern matching
this commit adds a message and explanation by unapply method on class' object companion, causing the compiler not founding a way to extract the arguments
1 parent 2b73f9d commit 08373f4

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ public enum ErrorMessageID {
133133
TypeTestAlwaysSucceedsID,
134134
TermMemberNeedsNeedsResultTypeForImplicitSearchID,
135135
CaseClassCannotExtendEnumID,
136-
ValueClassParameterMayNotBeCallByNameID
136+
ValueClassParameterMayNotBeCallByNameID,
137+
NotAnExtractorID
137138
;
138139

139140
public int errorNumber() {

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,4 +2117,18 @@ object messages {
21172117
override def msg: String = hl"""normal case class cannot extend an enum. case $cls in ${cls.owner} is extending enum ${parent.name}."""
21182118
override def explanation: String = ""
21192119
}
2120+
2121+
case class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends Message(NotAnExtractorID) {
2122+
override def msg: String = hl"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method"
2123+
override def kind: String = "Syntax"
2124+
override def explanation: String =
2125+
hl"""|An `unapply` method should be defined in an `object` as follow:
2126+
| - If it is just a test, return a `Boolean`. For example `case even()`
2127+
| - If it returns a single sub-value of type T, return an `Option[T]`
2128+
| - If it returns several sub-values T1,...,Tn, group them in an optional tuple `Option[(T1,...,Tn)]`
2129+
|
2130+
|Sometimes, the number of sub-values isn’t fixed and we would like to return a sequence.
2131+
|For this reason, you can also define patterns through `unapplySeq` which returns `Option[Seq[T]]`.
2132+
|This mechanism is used for instance in pattern `case List(x1, ..., xn)`""".stripMargin
2133+
}
21202134
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import language.implicitConversions
3232
import reporting.diagnostic.Message
3333
import reporting.trace
3434
import Constants.{Constant, IntTag, LongTag}
35-
import dotty.tools.dotc.reporting.diagnostic.messages.UnapplyInvalidNumberOfArguments
35+
import dotty.tools.dotc.reporting.diagnostic.messages.{NotAnExtractor, UnapplyInvalidNumberOfArguments}
3636

3737
import scala.collection.mutable.ListBuffer
3838

@@ -895,8 +895,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
895895
def typedUnApply(tree: untpd.Apply, selType: Type)(implicit ctx: Context): Tree = track("typedUnApply") {
896896
val Apply(qual, args) = tree
897897

898-
def notAnExtractor(tree: Tree) =
899-
errorTree(tree, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method")
898+
def notAnExtractor(tree: Tree) = errorTree(tree, NotAnExtractor(qual))
900899

901900
/** If this is a term ref tree, try to typecheck with its type name.
902901
* If this refers to a type alias, follow the alias, and if

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,4 +1511,20 @@ class ErrorMessagesTests extends ErrorMessagesTest {
15111511
assertEquals(tailRegMessages, Set("variable", "value", "object", "class"))
15121512
}
15131513

1514+
@Test def notAnExtractor() =
1515+
checkMessagesAfter(FrontEnd.name) {
1516+
"""
1517+
| class Foo
1518+
| object Test {
1519+
| def test(foo: Foo) = foo match {
1520+
| case Foo(name) => ???
1521+
| }
1522+
| }
1523+
""".stripMargin
1524+
}.expect { (ictx, messages) =>
1525+
implicit val ctx: Context = ictx
1526+
assertMessageCount(1, messages)
1527+
val NotAnExtractor(tree) = messages.head
1528+
assertEquals("Foo", tree.show)
1529+
}
15141530
}

0 commit comments

Comments
 (0)