Skip to content

Commit 537211c

Browse files
authored
Add an irrefutable version of the NoSuccess extractor (#496)
1 parent 2ac42b0 commit 537211c

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala

+22-1
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,34 @@ trait Parsers {
176176

177177
def get: Nothing = scala.sys.error("No result when parsing failed")
178178
}
179-
/** An extractor so `NoSuccess(msg, next)` can be used in matches. */
179+
/**
180+
* An extractor so `case NoSuccess(msg, next)` can be used in matches.
181+
*
182+
* Note: On Scala 2.13, using this extractor leads to an exhaustivity warning:
183+
*
184+
* {{{
185+
* def m(r: ParseResult[Int]) = r match {
186+
* case Success(i) => ...
187+
* case NoSuccess(msg, _) => ... // "warning: match may not be exhaustive"
188+
* }}}
189+
*
190+
* To eliminate this warning, use the irrefutable `NoSuccess.I` extractor.
191+
* Due to binary compatibility, `NoSuccess` itself cannot be changed.
192+
*/
180193
object NoSuccess {
181194
def unapply[T](x: ParseResult[T]) = x match {
182195
case Failure(msg, next) => Some((msg, next))
183196
case Error(msg, next) => Some((msg, next))
184197
case _ => None
185198
}
199+
200+
/** An irrefutable version of the `NoSuccess` extractor, used as `case NoSuccess.I(msg, next)`. */
201+
object I {
202+
def unapply(x: NoSuccess): Some[(String, Input)] = x match {
203+
case Failure(msg, next) => Some((msg, next))
204+
case Error(msg, next) => Some((msg, next))
205+
}
206+
}
186207
}
187208

188209
/** The failure case of `ParseResult`: contains an error-message and the remaining input.

shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala

+4-12
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ class PackratParsersTest {
2828

2929
def extractResult(r : ParseResult[Int]): Int = r match {
3030
case Success(a,_) => a
31-
case NoSuccess(a,_) => sys.error(a)
32-
case Failure(a, _) => sys.error(a)
33-
case Error(a, _) => sys.error(a)
31+
case NoSuccess.I(a,_) => sys.error(a)
3432
}
3533
def check(expected: Int, expr: String): Unit = {
3634
val parseResult = head(new lexical.Scanner(expr))
@@ -84,9 +82,7 @@ class PackratParsersTest {
8482

8583
def extractResult(r : ParseResult[Int]): Int = r match {
8684
case Success(a,_) => a
87-
case NoSuccess(a,_) => sys.error(a)
88-
case Failure(a, _) => sys.error(a)
89-
case Error(a, _) => sys.error(a)
85+
case NoSuccess.I(a,_) => sys.error(a)
9086
}
9187
def check(expected: Int, expr: String): Unit = {
9288
val parseResult = head(new lexical.Scanner(expr))
@@ -109,9 +105,7 @@ class PackratParsersTest {
109105
val head = phrase(AnBnCn)
110106
def extractResult(r: ParseResult[AnBnCnResult]): AnBnCnResult = r match {
111107
case Success(a,_) => a
112-
case NoSuccess(a,_) => sys.error(a)
113-
case Failure(a, _) => sys.error(a)
114-
case Error(a, _) => sys.error(a)
108+
case NoSuccess.I(a,_) => sys.error(a)
115109
}
116110
def threeLists(as: List[Symbol], bs: List[Symbol], cs: List[Symbol]): AnBnCnResult = {
117111
val as1 = as.map(_.name)
@@ -152,9 +146,7 @@ class PackratParsersTest {
152146

153147
def extractResult(r: ParseResult[Res]): Res = r match {
154148
case Success(a,_) => a
155-
case NoSuccess(a,_) => sys.error(a)
156-
case Failure(a, _) => sys.error(a)
157-
case Error(a, _) => sys.error(a)
149+
case NoSuccess.I(a,_) => sys.error(a)
158150
}
159151
def check(expected: Term, input: String, ctx: Ctx): Unit = {
160152
val parseResult = phraseTerm(new lexical.Scanner(input))

0 commit comments

Comments
 (0)