Skip to content

Export / Pattern match interplay #23707

@Quafadas

Description

@Quafadas

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    itype:bugstat:needs triageEvery issue needs to have an "area" and "itype" label

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions