diff --git a/compiler/src/dotty/tools/dotc/quoted/Matcher.scala b/compiler/src/dotty/tools/dotc/quoted/Matcher.scala index f916161e8acb..dda40070d7d8 100644 --- a/compiler/src/dotty/tools/dotc/quoted/Matcher.scala +++ b/compiler/src/dotty/tools/dotc/quoted/Matcher.scala @@ -4,7 +4,6 @@ import scala.annotation.internal.sharable import scala.annotation.{Annotation, compileTimeOnly} import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface /** Matches a quoted tree against a quoted pattern tree. * A quoted pattern tree may have type and term holes in addition to normal terms. @@ -98,7 +97,7 @@ import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface */ object Matcher { - abstract class QuoteMatcher[QCtx <: QuoteContext { val reflect: scala.internal.tasty.CompilerInterface } & Singleton](val qctx: QCtx) { + abstract class QuoteMatcher[QCtx <: QuoteContext & scala.internal.quoted.CompilerInterface & Singleton](val qctx: QCtx) { // TODO improve performance diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 142c808b9e4b..184e76d28e6f 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -45,9 +45,9 @@ object QuoteContextImpl { } -class QuoteContextImpl private (ctx: Context) extends QuoteContext: +class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.internal.quoted.CompilerInterface: - object reflect extends scala.tasty.Reflection, scala.internal.tasty.CompilerInterface: + object reflect extends scala.tasty.Reflection: def rootContext: Context = ctx @@ -2615,70 +2615,74 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: private def withDefaultPos[T <: Tree](fn: Context ?=> T): T = fn(using ctx.withSource(Position.ofMacroExpansion.source)).withSpan(Position.ofMacroExpansion.span) - def unpickleTerm(pickledQuote: PickledQuote): Term = - PickledQuotes.unpickleTerm(pickledQuote) - - def unpickleTypeTree(pickledQuote: PickledQuote): TypeTree = - PickledQuotes.unpickleTypeTree(pickledQuote) + end reflect - def termMatch(scrutinee: Term, pattern: Term): Option[Tuple] = - treeMatch(scrutinee, pattern) + def unpickleExpr(pickledQuote: PickledQuote): scala.quoted.Expr[Any] = + val tree = PickledQuotes.unpickleTerm(pickledQuote)(using reflect.rootContext) + new scala.internal.quoted.Expr(tree, hash) - def typeTreeMatch(scrutinee: TypeTree, pattern: TypeTree): Option[Tuple] = - treeMatch(scrutinee, pattern) + def unpickleType(pickledQuote: PickledQuote): scala.quoted.Type[?] = + val tree = PickledQuotes.unpickleTypeTree(pickledQuote)(using reflect.rootContext) + new scala.internal.quoted.Type(tree, hash) - private def treeMatch(scrutinee: Tree, pattern: Tree): Option[Tuple] = { - def isTypeHoleDef(tree: Tree): Boolean = - tree match - case tree: TypeDef => - tree.symbol.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_patternTypeAnnot) - case _ => false - - def extractTypeHoles(pat: Term): (Term, List[Symbol]) = - pat match - case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2) - case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) => - val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol) - val otherStats = stats.dropWhile(isTypeHoleDef) - (tpd.cpy.Block(pat)(otherStats, expr), holes) - case _ => - (pat, Nil) + def exprMatch(scrutinee: scala.quoted.Expr[Any], pattern: scala.quoted.Expr[Any]): Option[Tuple] = + treeMatch(scrutinee.unseal(using this), pattern.unseal(using this)) - val (pat1, typeHoles) = extractTypeHoles(pattern) + def typeMatch(scrutinee: scala.quoted.Type[?], pattern: scala.quoted.Type[?]): Option[Tuple] = + treeMatch(scrutinee.unseal(using this), pattern.unseal(using this)) - val ctx1 = - if typeHoles.isEmpty then ctx - else - val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference) - ctx1.gadt.addToConstraint(typeHoles) - ctx1 - - val qctx1 = dotty.tools.dotc.quoted.QuoteContextImpl()(using ctx1) - .asInstanceOf[QuoteContext { val reflect: QuoteContextImpl.this.reflect.type }] + private def treeMatch(scrutinee: reflect.Tree, pattern: reflect.Tree): Option[Tuple] = { + import reflect._ + given Context = rootContext + def isTypeHoleDef(tree: Tree): Boolean = + tree match + case tree: TypeDef => + tree.symbol.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_patternTypeAnnot) + case _ => false - val matcher = new Matcher.QuoteMatcher[qctx1.type](qctx1) { - def patternHoleSymbol: Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_patternHole - def higherOrderHoleSymbol: Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_higherOrderHole - } + def extractTypeHoles(pat: Term): (Term, List[Symbol]) = + pat match + case tpd.Inlined(_, Nil, pat2) => extractTypeHoles(pat2) + case tpd.Block(stats @ ((typeHole: TypeDef) :: _), expr) if isTypeHoleDef(typeHole) => + val holes = stats.takeWhile(isTypeHoleDef).map(_.symbol) + val otherStats = stats.dropWhile(isTypeHoleDef) + (tpd.cpy.Block(pat)(otherStats, expr), holes) + case _ => + (pat, Nil) + + val (pat1, typeHoles) = extractTypeHoles(pattern) + + val ctx1 = + if typeHoles.isEmpty then ctx + else + val ctx1 = ctx.fresh.setFreshGADTBounds.addMode(dotc.core.Mode.GadtConstraintInference) + ctx1.gadt.addToConstraint(typeHoles) + ctx1 + + val qctx1 = dotty.tools.dotc.quoted.QuoteContextImpl()(using ctx1) + .asInstanceOf[QuoteContext & scala.internal.quoted.CompilerInterface] + + val matcher = new Matcher.QuoteMatcher[qctx1.type](qctx1) { + def patternHoleSymbol: qctx1.reflect.Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_patternHole.asInstanceOf + def higherOrderHoleSymbol: qctx1.reflect.Symbol = dotc.core.Symbols.defn.InternalQuotedPatterns_higherOrderHole.asInstanceOf + } - val matchings = - if pat1.isType then matcher.termMatch(scrutinee, pat1) - else matcher.termMatch(scrutinee, pat1) - - // val matchings = matcher.termMatch(scrutinee, pattern) - if typeHoles.isEmpty then matchings - else { - // After matching and doing all subtype checks, we have to approximate all the type bindings - // that we have found, seal them in a quoted.Type and add them to the result - def typeHoleApproximation(sym: Symbol) = - ctx1.gadt.approximation(sym, !sym.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_fromAboveAnnot)).seal - matchings.map { tup => - Tuple.fromIArray(typeHoles.map(typeHoleApproximation).toArray.asInstanceOf[IArray[Object]]) ++ tup - } + val matchings = + if pat1.isType then matcher.termMatch(scrutinee.asInstanceOf[matcher.qctx.reflect.Term], pat1.asInstanceOf[matcher.qctx.reflect.Term]) + else matcher.termMatch(scrutinee.asInstanceOf[matcher.qctx.reflect.Term], pat1.asInstanceOf[matcher.qctx.reflect.Term]) + + // val matchings = matcher.termMatch(scrutinee, pattern) + if typeHoles.isEmpty then matchings + else { + // After matching and doing all subtype checks, we have to approximate all the type bindings + // that we have found, seal them in a quoted.Type and add them to the result + def typeHoleApproximation(sym: Symbol) = + ctx1.gadt.approximation(sym, !sym.hasAnnotation(dotc.core.Symbols.defn.InternalQuotedPatterns_fromAboveAnnot)).asInstanceOf[qctx1.reflect.TypeRepr].seal + matchings.map { tup => + Tuple.fromIArray(typeHoles.map(typeHoleApproximation).toArray.asInstanceOf[IArray[Object]]) ++ tup } } - - end reflect + } private[this] val hash = QuoteContextImpl.scopeId(using ctx) override def hashCode: Int = hash diff --git a/library/src-bootstrapped/scala/internal/quoted/Expr.scala b/library/src-bootstrapped/scala/internal/quoted/Expr.scala index 6412ebc46142..3bb78a5ae035 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Expr.scala @@ -1,7 +1,7 @@ package scala.internal.quoted import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface +import scala.internal.quoted.CompilerInterface.quoteContextWithCompilerInterface /** An Expr backed by a tree. Only the current compiler trees are allowed. * @@ -54,7 +54,7 @@ object Expr { def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: scala.quoted.Expr[Any]) (using patternExpr: scala.quoted.Expr[Any], qctx: QuoteContext): Option[Tup] = { val qctx1 = quoteContextWithCompilerInterface(qctx) - qctx1.reflect.termMatch(scrutineeExpr.unseal, patternExpr.unseal).asInstanceOf[Option[Tup]] + qctx1.exprMatch(scrutineeExpr, patternExpr).asInstanceOf[Option[Tup]] } /** Returns a null expresssion equivalent to `'{null}` */ diff --git a/library/src-bootstrapped/scala/internal/quoted/Type.scala b/library/src-bootstrapped/scala/internal/quoted/Type.scala index 8ef20510f050..cbe730578d51 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Type.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Type.scala @@ -1,7 +1,7 @@ package scala.internal.quoted import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface +import scala.internal.quoted.CompilerInterface.quoteContextWithCompilerInterface /** Quoted type (or kind) `T` backed by a tree */ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quoted.Type[Any] { @@ -37,7 +37,7 @@ object Type { def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeType: scala.quoted.Type[_]) (using patternType: scala.quoted.Type[_], qctx: QuoteContext): Option[Tup] = { val qctx1 = quoteContextWithCompilerInterface(qctx) - qctx1.reflect.typeTreeMatch(scrutineeType.unseal, patternType.unseal).asInstanceOf[Option[Tup]] + qctx1.typeMatch(scrutineeType, patternType).asInstanceOf[Option[Tup]] } diff --git a/library/src-bootstrapped/scala/quoted/Expr.scala b/library/src-bootstrapped/scala/quoted/Expr.scala index de10502bb4fd..e3918de2fcdd 100644 --- a/library/src-bootstrapped/scala/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/quoted/Expr.scala @@ -1,7 +1,5 @@ package scala.quoted -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface - /** Quoted expression of type `T` */ abstract class Expr[+T] private[scala] { diff --git a/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala b/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala index 727d780df797..2682c3d8d99a 100644 --- a/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala +++ b/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala @@ -1,7 +1,6 @@ package scala.internal.quoted import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface /** An Expr backed by a tree. Only the current compiler trees are allowed. * diff --git a/library/src-non-bootstrapped/scala/internal/quoted/Type.scala b/library/src-non-bootstrapped/scala/internal/quoted/Type.scala index c4b36f789b1d..329158243a35 100644 --- a/library/src-non-bootstrapped/scala/internal/quoted/Type.scala +++ b/library/src-non-bootstrapped/scala/internal/quoted/Type.scala @@ -1,7 +1,6 @@ package scala.internal.quoted import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface /** Quoted type (or kind) `T` backed by a tree */ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quoted.Type[Any] { diff --git a/library/src/scala/internal/tasty/CompilerInterface.scala b/library/src/scala/internal/quoted/CompilerInterface.scala similarity index 66% rename from library/src/scala/internal/tasty/CompilerInterface.scala rename to library/src/scala/internal/quoted/CompilerInterface.scala index a40321be8a56..0d0c8174501d 100644 --- a/library/src/scala/internal/tasty/CompilerInterface.scala +++ b/library/src/scala/internal/quoted/CompilerInterface.scala @@ -1,25 +1,23 @@ -package scala.internal.tasty +package scala.internal.quoted import scala.quoted.QuoteContext import scala.tasty.reflect._ import scala.internal.quoted.PickledQuote /** Part of the reflection interface that needs to be implemented by the compiler */ -trait CompilerInterface { self: scala.tasty.Reflection => +trait CompilerInterface { self: scala.quoted.QuoteContext => - ////////////////////// - // QUOTE UNPICKLING // - ////////////////////// + import self.reflect._ /** Unpickle `repr` which represents a pickled `Expr` tree, * replacing splice nodes with `holes` */ - def unpickleTerm(pickledQuote: PickledQuote): Term + def unpickleExpr(pickledQuote: PickledQuote): scala.quoted.Expr[Any] /** Unpickle `repr` which represents a pickled `Type` tree, * replacing splice nodes with `holes` */ - def unpickleTypeTree(pickledQuote: PickledQuote): TypeTree + def unpickleType(pickledQuote: PickledQuote): scala.quoted.Type[?] /** Pattern matches the scrutinee against the pattern and returns a tuple * with the matched holes if successful. @@ -36,27 +34,27 @@ trait CompilerInterface { self: scala.tasty.Reflection => * - scala.internal.Quoted.patternHole[T]: hole that matches an expression `x` of type `Expr[U]` * if `U <:< T` and returns `x` as part of the match. * - * @param scrutinee `Term` on which we are pattern matching - * @param pattern `Term` containing the pattern tree + * @param scrutinee `Expr` on which we are pattern matching + * @param pattern `Expr` containing the pattern tree * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Term`` */ - def termMatch(scrutinee: Term, pattern: Term): Option[Tuple] + def exprMatch(scrutinee: scala.quoted.Expr[Any], pattern: scala.quoted.Expr[Any]): Option[Tuple] /** Pattern matches the scrutineeType against the patternType and returns a tuple * with the matched holes if successful. * - * @param scrutinee `TypeTree` on which we are pattern matching - * @param pattern `TypeTree` containing the pattern tree - * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `quoted.Type[Ti]`` + * @param scrutinee `Type` on which we are pattern matching + * @param pattern `Type` containing the pattern tree + * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `scala.quoted.Type[Ti]`` */ - def typeTreeMatch(scrutinee: TypeTree, pattern: TypeTree): Option[Tuple] + def typeMatch(scrutinee: scala.quoted.Type[?], pattern: scala.quoted.Type[?]): Option[Tuple] } object CompilerInterface { - private[scala] def quoteContextWithCompilerInterface(qctx: QuoteContext): qctx.type { val reflect: qctx.reflect.type & scala.internal.tasty.CompilerInterface } = - qctx.asInstanceOf[qctx.type { val reflect: qctx.reflect.type & scala.internal.tasty.CompilerInterface }] + private[scala] def quoteContextWithCompilerInterface(qctx: QuoteContext): qctx.type { val reflect: qctx.reflect.type } & CompilerInterface = + qctx.asInstanceOf[qctx.type { val reflect: qctx.reflect.type } & CompilerInterface] } diff --git a/library/src/scala/internal/quoted/PickledQuote.scala b/library/src/scala/internal/quoted/PickledQuote.scala index e03d52bfd033..db8b1e2ce7f7 100644 --- a/library/src/scala/internal/quoted/PickledQuote.scala +++ b/library/src/scala/internal/quoted/PickledQuote.scala @@ -1,7 +1,6 @@ package scala.internal.quoted import scala.quoted._ -import scala.internal.tasty.CompilerInterface.quoteContextWithCompilerInterface /** Pickled representation of a quoted expression or type */ trait PickledQuote: @@ -18,14 +17,12 @@ trait PickledQuote: object PickledQuote: def unpickleExpr[T](pickledQuote: PickledQuote): QuoteContext ?=> Expr[T] = - val qctx = quoteContextWithCompilerInterface(summon[QuoteContext]) - val tree = qctx.reflect.unpickleTerm(pickledQuote) - new scala.internal.quoted.Expr(tree, qctx.hashCode).asInstanceOf[Expr[T]] + val qctx = CompilerInterface.quoteContextWithCompilerInterface(summon[QuoteContext]) + qctx.unpickleExpr(pickledQuote).asInstanceOf[Expr[T]] def unpickleType[T](pickledQuote: PickledQuote): QuoteContext ?=> Type[T] = - val qctx = quoteContextWithCompilerInterface(summon[QuoteContext]) - val tree = qctx.reflect.unpickleTypeTree(pickledQuote) - new scala.internal.quoted.Type(tree, qctx.hashCode).asInstanceOf[Type[T]] + val qctx = CompilerInterface.quoteContextWithCompilerInterface(summon[QuoteContext]) + qctx.unpickleType(pickledQuote).asInstanceOf[Type[T]] /** Create an instance of PickledExpr from encoded tasty and sequence of labmdas to fill holes * diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index b2b561af29d0..49d70309bb96 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -1,7 +1,5 @@ package scala.tasty -import scala.internal.tasty.CompilerInterface - import scala.quoted.QuoteContext import scala.tasty.reflect._ diff --git a/tests/run-macros/quote-matcher-runtime/quoted_1.scala b/tests/run-macros/quote-matcher-runtime/quoted_1.scala index 704ac751a308..6bad6afb3547 100644 --- a/tests/run-macros/quote-matcher-runtime/quoted_1.scala +++ b/tests/run-macros/quote-matcher-runtime/quoted_1.scala @@ -13,8 +13,6 @@ object Macros { s"Expr(${r.unseal.show})" case r: Type[_] => s"Type(${r.unseal.show})" - case r: String => - s"String($r)" } }