diff --git a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala index 737244ba..82a4bf8a 100644 --- a/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala +++ b/shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala @@ -176,13 +176,34 @@ trait Parsers { def get: Nothing = scala.sys.error("No result when parsing failed") } - /** An extractor so `NoSuccess(msg, next)` can be used in matches. */ + /** + * An extractor so `case NoSuccess(msg, next)` can be used in matches. + * + * Note: On Scala 2.13, using this extractor leads to an exhaustivity warning: + * + * {{{ + * def m(r: ParseResult[Int]) = r match { + * case Success(i) => ... + * case NoSuccess(msg, _) => ... // "warning: match may not be exhaustive" + * }}} + * + * To eliminate this warning, use the irrefutable `NoSuccess.I` extractor. + * Due to binary compatibility, `NoSuccess` itself cannot be changed. + */ object NoSuccess { def unapply[T](x: ParseResult[T]) = x match { case Failure(msg, next) => Some((msg, next)) case Error(msg, next) => Some((msg, next)) case _ => None } + + /** An irrefutable version of the `NoSuccess` extractor, used as `case NoSuccess.I(msg, next)`. */ + object I { + def unapply(x: NoSuccess): Some[(String, Input)] = x match { + case Failure(msg, next) => Some((msg, next)) + case Error(msg, next) => Some((msg, next)) + } + } } /** The failure case of `ParseResult`: contains an error-message and the remaining input. diff --git a/shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala b/shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala index 2bf7881f..b56b4628 100644 --- a/shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala +++ b/shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala @@ -28,9 +28,7 @@ class PackratParsersTest { def extractResult(r : ParseResult[Int]): Int = r match { case Success(a,_) => a - case NoSuccess(a,_) => sys.error(a) - case Failure(a, _) => sys.error(a) - case Error(a, _) => sys.error(a) + case NoSuccess.I(a,_) => sys.error(a) } def check(expected: Int, expr: String): Unit = { val parseResult = head(new lexical.Scanner(expr)) @@ -84,9 +82,7 @@ class PackratParsersTest { def extractResult(r : ParseResult[Int]): Int = r match { case Success(a,_) => a - case NoSuccess(a,_) => sys.error(a) - case Failure(a, _) => sys.error(a) - case Error(a, _) => sys.error(a) + case NoSuccess.I(a,_) => sys.error(a) } def check(expected: Int, expr: String): Unit = { val parseResult = head(new lexical.Scanner(expr)) @@ -109,9 +105,7 @@ class PackratParsersTest { val head = phrase(AnBnCn) def extractResult(r: ParseResult[AnBnCnResult]): AnBnCnResult = r match { case Success(a,_) => a - case NoSuccess(a,_) => sys.error(a) - case Failure(a, _) => sys.error(a) - case Error(a, _) => sys.error(a) + case NoSuccess.I(a,_) => sys.error(a) } def threeLists(as: List[Symbol], bs: List[Symbol], cs: List[Symbol]): AnBnCnResult = { val as1 = as.map(_.name) @@ -152,9 +146,7 @@ class PackratParsersTest { def extractResult(r: ParseResult[Res]): Res = r match { case Success(a,_) => a - case NoSuccess(a,_) => sys.error(a) - case Failure(a, _) => sys.error(a) - case Error(a, _) => sys.error(a) + case NoSuccess.I(a,_) => sys.error(a) } def check(expected: Term, input: String, ctx: Ctx): Unit = { val parseResult = phraseTerm(new lexical.Scanner(input))