diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 45effed04a84..23002f2c1719 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2009,6 +2009,7 @@ class Typer extends Namer fun = ref(defn.InternalQuotedMatcher_unapplyR).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil), implicits = ref(defn.InternalQuoted_exprQuoteR).appliedToType(shape.tpe).appliedTo(shape) :: + Literal(Constant(typeBindings.nonEmpty)) :: implicitArgTree(defn.TastyReflectionType, tree.span) :: Nil, patterns = splicePat :: Nil, proto = pt) diff --git a/library/src-3.x/scala/internal/quoted/Matcher.scala b/library/src-3.x/scala/internal/quoted/Matcher.scala index 71feae8b5e66..60d55f2eed3f 100644 --- a/library/src-3.x/scala/internal/quoted/Matcher.scala +++ b/library/src-3.x/scala/internal/quoted/Matcher.scala @@ -27,17 +27,18 @@ object Matcher { * * @param scrutineeExpr `Expr[_]` on which we are pattern matching * @param patternExpr `Expr[_]` containing the pattern tree + * @param hasTypeSplices `Boolean` notify if the pattern has type splices (if so we use a GADT context) * @param reflection instance of the reflection API (implicitly provided by the macro) * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]`` */ - def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], reflection: Reflection): Option[Tup] = { + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: Expr[_])(implicit patternExpr: Expr[_], hasTypeSplices: Boolean, reflection: Reflection): Option[Tup] = { // TODO improve performance import reflection.{Bind => BindPattern, _} import Matching._ type Env = Set[(Symbol, Symbol)] - class SymBinding(val sym: Symbol) + class SymBinding(val sym: Symbol, val fromBellow: Boolean) inline def withEnv[T](env: Env)(body: => given Env => T): T = body given env @@ -140,7 +141,8 @@ object Matcher { case (Block(stats1, expr1), Block(binding :: stats2, expr2)) if isTypeBinding(binding) => reflection.kernel.Context_GADT_addToConstraint(the[Context])(binding.symbol :: Nil) - matched(new SymBinding(binding.symbol)) && Block(stats1, expr1) =#= Block(stats2, expr2) + val fromBellow = true // TODO + matched(new SymBinding(binding.symbol, fromBellow)) && Block(stats1, expr1) =#= Block(stats2, expr2) case (Block(stat1 :: stats1, expr1), Block(stat2 :: stats2, expr2)) => withEnv(the[Env] + (stat1.symbol -> stat2.symbol)) { @@ -150,7 +152,8 @@ object Matcher { case (scrutinee, Block(typeBindings, expr2)) if typeBindings.forall(isTypeBinding) => val bindingSymbols = typeBindings.map(_.symbol) reflection.kernel.Context_GADT_addToConstraint(the[Context])(bindingSymbols) - bindingSymbols.foldRight(scrutinee =#= expr2)((x, acc) => matched(new SymBinding(x)) && acc) + val fromBellow = true // TODO + bindingSymbols.foldRight(scrutinee =#= expr2)((x, acc) => matched(new SymBinding(x, fromBellow)) && acc) case (If(cond1, thenp1, elsep1), If(cond2, thenp2, elsep2)) => cond1 =#= cond2 && thenp1 =#= thenp2 && elsep1 =#= elsep2 @@ -335,18 +338,24 @@ object Matcher { implied for Env = Set.empty - { - // TODO only set GADT context when needed - implicit val ctx2 = reflection.kernel.Context_GADT_setFreshGADTBounds(rootContext) - val matchings = scrutineeExpr.unseal.underlyingArgument =#= patternExpr.unseal.underlyingArgument - val res = matchings.asOptionOfTuple.map { tup => - Tuple.fromArray(tup.toArray.map { // TODO improve code - case x: SymBinding => reflection.kernel.Context_GADT_approximation(ctx2)(x.sym, true).seal - case x => x - }) + val res = { + if (hasTypeSplices) { + implied for Context = reflection.kernel.Context_GADT_setFreshGADTBounds(rootContext) + val matchings = scrutineeExpr.unseal.underlyingArgument =#= patternExpr.unseal.underlyingArgument + // After matching and doing all subtype check, we have to aproximate all the type bindings + // that we have found and seal them in a quoted.Type + matchings.asOptionOfTuple.map { tup => + Tuple.fromArray(tup.toArray.map { // TODO improve performace + case x: SymBinding => kernel.Context_GADT_approximation(the[Context])(x.sym, x.fromBellow).seal + case x => x + }) + } + } + else { + scrutineeExpr.unseal.underlyingArgument =#= patternExpr.unseal.underlyingArgument } - res.asInstanceOf[Option[Tup]] } + res.asInstanceOf[Option[Tup]] } /** Result of matching a part of an expression */ diff --git a/tests/run-macros/quote-matcher-runtime/quoted_1.scala b/tests/run-macros/quote-matcher-runtime/quoted_1.scala index 75b9e87bceca..97677157725c 100644 --- a/tests/run-macros/quote-matcher-runtime/quoted_1.scala +++ b/tests/run-macros/quote-matcher-runtime/quoted_1.scala @@ -10,7 +10,7 @@ object Macros { private def impl[A, B](a: Expr[A], b: Expr[B])(implicit reflect: Reflection): Expr[Unit] = { import reflect.{Bind => _, _} - val res = scala.internal.quoted.Matcher.unapply[Tuple, Tuple](a)(b, reflect).map { tup => + val res = scala.internal.quoted.Matcher.unapply[Tuple, Tuple](a)(b, true, reflect).map { tup => tup.toArray.toList.map { case r: Expr[_] => s"Expr(${r.unseal.show})"