scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.88k stars 1.06k forks source link

Quoted type pattern for `'[Map[k, v]]` doesn't match when `k` is an `OrType` #21634

Open felher opened 1 month ago

felher commented 1 month ago

Compiler version

3.5.1

Minimized code

A simple macro that has a quoted type pattern for a 'Map[k, v]:

Macro.scala:

import scala.quoted.*

object Macro:
  inline def matchMap[T]: String =
    ${ matchMapImpl[T] }

  def matchMapImpl[T](using t: Type[T], q: Quotes): Expr[String] =
    t match
      case '[Map[k, v]] => Expr("Found map")
      case _            => Expr("Not a map")
@main def hello(): Unit =
  println(Macro.matchMap[Map[String, Boolean]])
  println(Macro.matchMap[Map["A" | "B", Boolean]])

Output

Found map
Not a map

Expectation

Found map
Found map

Notes

Maybe this is not a bug, maybe it is a limitation or I'm thinking wrong, but for me it is not entirely clear why it depends on the key type whether I can match it. I asked in metaprogramming on discord and nobody seemed to know either, so here we are.

Also, thanks for your fantastic work on scala <3

Workaround

If somebody finds this ticket, whether it is a bug or not, and needs a quick workaround: Match on the TypeRepr:

val tpe: TypeRepr = ???
val mapTycon = Symbol.requiredClass("scala.collection.immutable.Map").typeRef
tpe.asMatchable match
  case AppliedType(tycon, args) if tycon =:= mapTycon =>
    val keyRepr   = args(0)
    val valueRepr = args(1)
    keyRepr.asType match
      case '[k] =>
        valueRepr.asType match
          case '[v] => ... 

Now you have both k and v matched and it works even if k is an OrType, which you can then deconstruct further

smarter commented 1 month ago

Related but different issue for reference (since the same fix might apply to both): https://github.com/scala/scala3/issues/16782