-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Compiler version
3.7.2
Minimized code
Requires multiple files I think due to exports and macros. Here's a tiny repo (4 files) that can run with scala-cli.
https://github.com/Quafadas/hkmatch/blob/main/exporter.scala
original.scala
package original
enum TypeInferrer:
case Auto
case FromTuple[T]()
end TypeInferrer
exporter.scala
object api :
export original.TypeInferrer.*
export original.TypeInferrer
macro.scala
import original.*
import scala.quoted.*
transparent inline def mac(
inline dataType: api.TypeInferrer
) = ${ mac_impl('dataType) }
def mac_impl(dataType: Expr[api.TypeInferrer])(using
q: Quotes
): Expr[String] =
dataType match {
case '{ TypeInferrer.Auto } =>
Expr("Auto")
// ERROR originates here
// hint: import is from the wrong package. This commented out version would probably work.
// case '{ api.TypeInferrer.FromTuple[t]() } =>
case '{ TypeInferrer.FromTuple[t]() } =>
Expr(s"FromTuple[${summon[Type[t]]}]")
}
main.scala
@main def run =
val x2 =
mac(TypeInferrer.FromTuple[(Int, Int)]())
Output
If you clone the project at the top and scala-cli run .
, you'll see this.
[error] .\project.scala:25:5
[error] Exception occurred while executing macro expansion.
[error] scala.MatchError: scala.quoted.runtime.impl.ExprImpl@78759ba1 (of class scala.quoted.runtime.impl.ExprImpl)
[error] at macro$package$.mac_impl(macro.scala:17)
[error]
[error] mac(TypeInferrer.FromTuple[(Int, Int)]())
Expectation
As the simple case of pattern matching on the exported enum works, it is awkward to me, that the more complex case of an aparently "same" match throws an error. I would expect the pattern match to succeed.
origTest match
case TypeInferrer.Auto => println("yey") // simple case succcess - _should_ this work? It does at the moment.
If you make the pattern match in user code (instead of a macro - the repo provides an example), you'll get a warning.
[warn] the type test for original.TypeInferrer.FromTuple[Int] cannot be checked at runtime because its type arguments can't be determined from original.TypeInferrer
[warn] case TypeInferrer.FromTuple[Int]() => println("???")
but in a macro, the error only shows up at the callsite, so it's tough to work with.
Perhaps related;
#12959
AI Summary
Summary
When using quoted pattern matching ('{...}') in Scala 3 macros, patterns fail to match expressions that reference types through export statements, even when the exported type is structurally identical to the original.
The Problem
Scenario
A macro uses quoted pattern matching to handle different enum cases: '{ MyEnum.CaseT }'
Users import the enum through a package object that re-exports it: export some.package.MyEnum
The macro pattern fails to match, even though semantically it should work
Root Cause
The compiler represents exported references with their full import path in the expression tree:
Direct usage: some.package.MyEnum.Case[T]()
Via export: exported.package.MyEnum.Case[T]() (internally becomes the export path)
Quoted patterns match structurally on the exact paths, so '{ MyEnum.CaseT }' won't match an expression that internally references exported.package.MyEnum.CaseT.