Skip to content

Macro-generated match gives an exhaustivity warning, even though it shouldn't #12188

Closed
@adamw

Description

@adamw

Compiler version

3.0.0-RC3

Minimized example

In a macro, I want to generate a pattern match for a sealed trait/enum, covering each case and performing some actions. The code I've got is the following:

import scala.quoted.*

object MatchTest {
  inline def test[T](inline obj: T): Unit = ${testImpl('obj)}

  def testImpl[T](objExpr: Expr[T])(using qctx: Quotes, t: Type[T]): Expr[Unit] = {
    import qctx.reflect.*

    val obj = objExpr.asTerm
    val cases = obj.tpe.typeSymbol.children.map { child =>
      val subtype = TypeIdent(child)
      val bind = Symbol.newBind(Symbol.spliceOwner, "c", Flags.EmptyFlags, subtype.tpe)
      CaseDef(Bind(bind, Typed(Ref(bind), subtype)), None, '{()}.asTerm)
    }
    val bind = Symbol.newBind(Symbol.spliceOwner, "o", Flags.EmptyFlags, obj.tpe)
    val result = Match(obj, cases)
    println(result.show(using Printer.TreeAnsiCode))
    result.asExprOf[Unit]
  }
}

Tested using:

sealed trait P
case class PC1(a: String) extends P
case class PC2(b: Int) extends P

MatchTest.test(PC2(10): P)

Output

(PC2.apply(10): P) match {
  case c @ (c: PC1) =>
    ()
  case c @ (`c₂`: PC2) =>
    ()
}
[warn] -- [E029] Pattern Match Exhaustivity Warning: Test.scala:25:17
[warn] 25 |  MatchTest.test(PC2(10): P)
[warn]    |                 ^^^^^^^^^^
[warn]    |       match may not be exhaustive.
[warn]    |
[warn]    |       It would fail on pattern case: PC1(_), PC2(_)
[warn]    | This location contains code that was inlined from Test.scala:25

Expectation

I wouldn't expect an exhaustivity warning, as all cases are covered.

I know that the match isn't perfect, but I don't know how to generate a better one. Specifically, instead of c @ (c: PC1), I'd like to generate c @ (_: PC1), but I can't find a way to create a _ using the current macro API. A candidate would be Ident(TermRef(NoPrefix, "_")), but then I don't know how to get a NoPrefix instance.

I also tried adding a third branch with an : Any case, but this didn't help - got the same exhaustivity warning

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions