diff --git a/compiler/src/scala/quoted/runtime/impl/Matcher.scala b/compiler/src/scala/quoted/runtime/impl/Matcher.scala index 285b2c19c6c5..21fb5bb6d74f 100644 --- a/compiler/src/scala/quoted/runtime/impl/Matcher.scala +++ b/compiler/src/scala/quoted/runtime/impl/Matcher.scala @@ -101,7 +101,7 @@ object Matcher { // TODO improve performance // TODO use flag from qctx.reflect. Maybe -debug or add -debug-macros - private final val debug = false + private inline val debug = false import qctx.reflect._ import Matching._ @@ -231,7 +231,7 @@ object Matcher { scrutinee =?= expr2 /* Match selection */ - case (ref: Ref, Select(qual2, _)) if scrutinee.symbol == pattern.symbol || summon[Env].get(scrutinee.symbol).contains(pattern.symbol) => + case (ref: Ref, Select(qual2, _)) if symbolMatch(scrutinee.symbol, pattern.symbol) => ref match case Select(qual1, _) => qual1 =?= qual2 case ref: Ident => @@ -240,7 +240,7 @@ object Matcher { case _ => matched /* Match reference */ - case (_: Ref, _: Ident) if scrutinee.symbol == pattern.symbol || summon[Env].get(scrutinee.symbol).contains(pattern.symbol) => + case (_: Ref, _: Ident) if symbolMatch(scrutinee.symbol, pattern.symbol) => matched /* Match application */ @@ -329,16 +329,13 @@ object Matcher { s""">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |Scrutinee | ${scrutinee.show} - | - |${scrutinee.showExtractors} - | |did not match pattern | ${pattern.show} | - |${pattern.showExtractors} - | |with environment: ${summon[Env]} | + |Scrutinee: ${scrutinee.showExtractors} + |Pattern: ${pattern.showExtractors} | |""".stripMargin) notMatched @@ -346,6 +343,16 @@ object Matcher { } end extension + /** Does the scrutenne symbol match the pattern symbol? It matches if: + * - They are the same symbol + * - The scrutinee has is in the environment and they are equivalent + * - The scrutinee overrides the symbol of the pattern + */ + private def symbolMatch(scrutinee: Symbol, pattern: Symbol)(using Env): Boolean = + scrutinee == pattern + || summon[Env].get(scrutinee).contains(pattern) + || scrutinee.allOverriddenSymbols.contains(pattern) + private object ClosedPatternTerm { /** Matches a term that does not contain free variables defined in the pattern (i.e. not defined in `Env`) */ def unapply(term: Term)(using Env): Option[term.type] = diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index cd14c1e2f974..06388fda3071 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2348,6 +2348,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def paramSymss: List[List[Symbol]] = self.denot.paramSymss def primaryConstructor: Symbol = self.denot.primaryConstructor + def allOverriddenSymbols: Iterator[Symbol] = self.denot.allOverriddenSymbols def caseFields: List[Symbol] = if !self.isClass then Nil diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index dc40c1d141b8..bc0de8795404 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3625,6 +3625,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => */ def paramSymss: List[List[Symbol]] + /** Returns all symbols overridden by this symbol. */ + def allOverriddenSymbols: Iterator[Symbol] + /** The primary constructor of a class or trait, `noSymbol` if not applicable. */ def primaryConstructor: Symbol diff --git a/tests/run-macros/i10464.check b/tests/run-macros/i10464.check new file mode 100644 index 000000000000..c014593328ec --- /dev/null +++ b/tests/run-macros/i10464.check @@ -0,0 +1,5 @@ +matched! +matched! +matched! +not matched +not matched diff --git a/tests/run-macros/i10464/Macro_1.scala b/tests/run-macros/i10464/Macro_1.scala new file mode 100644 index 000000000000..063a3928e3c7 --- /dev/null +++ b/tests/run-macros/i10464/Macro_1.scala @@ -0,0 +1,16 @@ +import scala.quoted._ + +object MatchMac { + + inline def apply(inline any: Any): Unit = ${ printMacImpl('any) } + + def printMacImpl(any: Expr[Any])(using Quotes): Expr[Unit] = { + import quotes.reflect._ + val res = any match { + case '{ ($f: Person).name } => "matched!" + case _ => "not matched" + } + '{ println(${Expr(res)}) } + } + +} diff --git a/tests/run-macros/i10464/Person_1.scala b/tests/run-macros/i10464/Person_1.scala new file mode 100644 index 000000000000..3973f018dd83 --- /dev/null +++ b/tests/run-macros/i10464/Person_1.scala @@ -0,0 +1,5 @@ +trait Person: + def name: String + +case class PersonA(name: String) extends Person +case class PersonB(name: String) extends Person diff --git a/tests/run-macros/i10464/Test_2.scala b/tests/run-macros/i10464/Test_2.scala new file mode 100644 index 000000000000..dbc3d8dc7d7b --- /dev/null +++ b/tests/run-macros/i10464/Test_2.scala @@ -0,0 +1,11 @@ + +@main def Test = { + val personA: PersonA = PersonA("JoeA") + val personB: PersonB = PersonB("JoeB") + val person: Person = personA + MatchMac(personA.name) + MatchMac(personB.name) + MatchMac(person.name) + MatchMac(PersonA("JoeA").name) // optimized to MatchMac("JoeA") + MatchMac(PersonB("JoeB").name) // optimized to MatchMac("JoeB") +}