diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f88c88eabdfb..3d0293ae53d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -796,6 +796,8 @@ class Definitions { @tu lazy val QuoteContextClass: ClassSymbol = requiredClass("scala.quoted.QuoteContext") @tu lazy val QuoteContextInternalClass: ClassSymbol = requiredClass("scala.internal.quoted.QuoteContextInternal") + @tu lazy val QuoteContextInternalClass_ExprMatch: Symbol = QuoteContextInternalClass.requiredMethod("ExprMatch") + @tu lazy val QuoteContextInternalClass_TypeMatch: Symbol = QuoteContextInternalClass.requiredMethod("TypeMatch") @tu lazy val LiftableModule: Symbol = requiredModule("scala.quoted.Liftable") @tu lazy val LiftableModule_BooleanLiftable: Symbol = LiftableModule.requiredMethod("BooleanLiftable") @@ -821,14 +823,6 @@ class Definitions { @tu lazy val InternalQuotedPatterns_patternTypeAnnot: ClassSymbol = InternalQuotedPatterns.requiredClass("patternType") @tu lazy val InternalQuotedPatterns_fromAboveAnnot: ClassSymbol = InternalQuotedPatterns.requiredClass("fromAbove") - @tu lazy val InternalQuotedExprModule: Symbol = requiredModule("scala.internal.quoted.Expr") - @tu lazy val InternalQuotedExpr_unapply: Symbol = InternalQuotedExprModule.requiredMethod(nme.unapply) - @tu lazy val InternalQuotedExpr_null: Symbol = InternalQuotedExprModule.requiredMethod(nme.null_) - @tu lazy val InternalQuotedExpr_unit: Symbol = InternalQuotedExprModule.requiredMethod(nme.Unit) - - @tu lazy val InternalQuotedTypeModule: Symbol = requiredModule("scala.internal.quoted.Type") - @tu lazy val InternalQuotedType_unapply: Symbol = InternalQuotedTypeModule.requiredMethod(nme.unapply) - @tu lazy val QuotedTypeClass: ClassSymbol = requiredClass("scala.quoted.Type") @tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.Underlying) diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 79002a72868e..668fa7d71547 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -2639,11 +2639,19 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern val tree = PickledQuotes.unpickleTypeTree(pickledQuote)(using reflect.rootContext) new scala.internal.quoted.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]] - def exprMatch(scrutinee: scala.quoted.Expr[Any], pattern: scala.quoted.Expr[Any]): Option[Tuple] = - treeMatch(scrutinee.unseal(using this), pattern.unseal(using this)) - - def typeMatch(scrutinee: scala.quoted.Type[?], pattern: scala.quoted.Type[?]): Option[Tuple] = - treeMatch(reflect.TypeTree.of(using scrutinee), reflect.TypeTree.of(using pattern)) + object ExprMatch extends ExprMatchModule: + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] = + val scrutineeTree = scrutinee.unseal(using QuoteContextImpl.this) + val patternTree = pattern.unseal(using QuoteContextImpl.this) + treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]] + end ExprMatch + + object TypeMatch extends TypeMatchModule: + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Type[?])(using pattern: scala.quoted.Type[?]): Option[Tup] = + val scrutineeTree = reflect.TypeTree.of(using scrutinee) + val patternTree = reflect.TypeTree.of(using pattern) + treeMatch(scrutineeTree, patternTree).asInstanceOf[Option[Tup]] + end TypeMatch private def treeMatch(scrutinee: reflect.Tree, pattern: reflect.Tree): Option[Tuple] = { import reflect._ diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index 051eabf6f5cd..d8c8255ad17b 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -458,14 +458,17 @@ trait QuotesAndSplices { if splices.isEmpty then ref(defn.EmptyTupleModule.termRef) else typed(untpd.Tuple(splices.map(x => untpd.TypedSplice(replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType) - val unapplySym = if (tree.quoted.isTerm) defn.InternalQuotedExpr_unapply else defn.InternalQuotedType_unapply val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass val quotedPattern = if (tree.quoted.isTerm) ref(defn.InternalQuoted_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx) else ref(defn.QuotedTypeModule_apply.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx) + + val matchModule = if tree.quoted.isTerm then defn.QuoteContextInternalClass_ExprMatch else defn.QuoteContextInternalClass_TypeMatch + val unapplyFun = qctx.asInstance(defn.QuoteContextInternalClass.typeRef).select(matchModule).select(nme.unapply) + UnApply( - fun = ref(unapplySym.termRef).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil), - implicits = quotedPattern :: qctx :: Nil, + fun = unapplyFun.appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil), + implicits = quotedPattern :: Nil, patterns = splicePat :: Nil, proto = quoteClass.typeRef.appliedTo(replaceBindings(quoted1.tpe) & quotedPt)) } diff --git a/library/src-bootstrapped/scala/internal/quoted/Expr.scala b/library/src-bootstrapped/scala/internal/quoted/Expr.scala index b3addc34bdd2..2472dfd068a5 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Expr.scala @@ -29,33 +29,3 @@ final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Ex override def hashCode: Int = tree.hashCode override def toString: String = "'{ ... }" } - -object Expr { - - /** Pattern matches an the scrutineeExpr against the patternExpr and returns a tuple - * with the matched holes if successful. - * - * Examples: - * - `Matcher.unapply('{ f(0, myInt) })('{ f(0, myInt) }, _)` - * will return `Some(())` (where `()` is a tuple of arity 0) - * - `Matcher.unapply('{ f(0, myInt) })('{ f(patternHole[Int], patternHole[Int]) }, _)` - * will return `Some(Tuple2('{0}, '{ myInt }))` - * - `Matcher.unapply('{ f(0, "abc") })('{ f(0, patternHole[Int]) }, _)` - * will return `None` due to the missmatch of types in the hole - * - * Holes: - * - 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 scrutineeExpr `Expr[Any]` on which we are pattern matching - * @param patternExpr `Expr[Any]` containing the pattern tree - * @param hasTypeSplices `Boolean` notify if the pattern has type splices - * @param qctx the current QuoteContext - * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]`` - */ - def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeExpr: scala.quoted.Expr[Any]) - (using patternExpr: scala.quoted.Expr[Any], qctx: QuoteContext): Option[Tup] = { - qctx.asInstanceOf[QuoteContextInternal].exprMatch(scrutineeExpr, patternExpr).asInstanceOf[Option[Tup]] - } - -} diff --git a/library/src-bootstrapped/scala/internal/quoted/Type.scala b/library/src-bootstrapped/scala/internal/quoted/Type.scala index 35d1b5e6b16c..1f17299f3a01 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Type.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Type.scala @@ -24,21 +24,3 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote override def hashCode: Int = typeTree.hashCode override def toString: String = "'[ ... ]" } - -object Type { - - /** Pattern matches an the scrutineeType against the patternType and returns a tuple - * with the matched holes if successful. - * - * @param scrutineeType `Type[_]` on which we are pattern matching - * @param patternType `Type[_]` containing the pattern tree - * @param hasTypeSplices `Boolean` notify if the pattern has type splices - * @param qctx the current QuoteContext - * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Type[Ti]`` - */ - def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeType: scala.quoted.Type[_]) - (using patternType: scala.quoted.Type[_], qctx: QuoteContext): Option[Tup] = { - qctx.asInstanceOf[QuoteContextInternal].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 31ba66b5f2d3..17ab4d554c6c 100644 --- a/library/src-bootstrapped/scala/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/quoted/Expr.scala @@ -18,7 +18,8 @@ abstract class Expr[+T] private[scala] { * ``` */ final def matches(that: Expr[Any])(using qctx: QuoteContext): Boolean = - !scala.internal.quoted.Expr.unapply[EmptyTuple, EmptyTuple](this)(using that, qctx).isEmpty + val ExprMatch = qctx.asInstanceOf[scala.internal.quoted.QuoteContextInternal].ExprMatch + ExprMatch.unapply[EmptyTuple, EmptyTuple](this)(using that).nonEmpty /** Checked cast to a `quoted.Expr[U]` */ def cast[U](using tp: scala.quoted.Type[U])(using qctx: QuoteContext): scala.quoted.Expr[U] = asExprOf[U] @@ -121,57 +122,141 @@ object Expr { * `'{ ($e1, $e2, ...) }` typed as an `Expr[Tuple]` */ def ofTupleFromSeq(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = { - seq match { - case Seq() => - '{ Tuple() } - case Seq('{ $x1: t1 }) => - '{ Tuple1($x1) } - case Seq('{ $x1: t1 }, '{ $x2: t2 }) => - '{ Tuple2($x1, $x2) } - case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }) => - '{ Tuple3($x1, $x2, $x3) } + seq.size match { + case 0 => '{ Tuple() } + case 1 => ofTupleFromSeq1(seq) + case 2 => ofTupleFromSeq2(seq) + case 3 => ofTupleFromSeq3(seq) + case 4 => ofTupleFromSeq4(seq) + case 5 => ofTupleFromSeq5(seq) + case 6 => ofTupleFromSeq6(seq) + case 7 => ofTupleFromSeq7(seq) + case 8 => ofTupleFromSeq8(seq) + case 9 => ofTupleFromSeq9(seq) + case 10 => ofTupleFromSeq10(seq) + case 11 => ofTupleFromSeq11(seq) + case 12 => ofTupleFromSeq12(seq) + case 13 => ofTupleFromSeq13(seq) + case 14 => ofTupleFromSeq14(seq) + case 15 => ofTupleFromSeq15(seq) + case 16 => ofTupleFromSeq16(seq) + case 17 => ofTupleFromSeq17(seq) + case 18 => ofTupleFromSeq18(seq) + case 19 => ofTupleFromSeq19(seq) + case 20 => ofTupleFromSeq20(seq) + case 21 => ofTupleFromSeq21(seq) + case 22 => ofTupleFromSeq22(seq) + case _ => '{ Tuple.fromIArray(IArray(${Varargs(seq)}: _*)) } + } + } + + private def ofTupleFromSeq1(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match + case Seq('{ $x1: t1 }) => '{ Tuple1($x1) } + + private def ofTupleFromSeq2(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match + case Seq('{ $x1: t1 }, '{ $x2: t2 }) => '{ Tuple2($x1, $x2) } + + private def ofTupleFromSeq3(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match + case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }) => '{ Tuple3($x1, $x2, $x3) } + + private def ofTupleFromSeq4(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }) => - '{ Tuple4($x1, $x2, $x3, $x4) } + '{ Tuple4($x1, $x2, $x3, $x4) } + + private def ofTupleFromSeq5(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }) => '{ Tuple5($x1, $x2, $x3, $x4, $x5) } + + private def ofTupleFromSeq6(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }) => '{ Tuple6($x1, $x2, $x3, $x4, $x5, $x6) } + + private def ofTupleFromSeq7(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }) => '{ Tuple7($x1, $x2, $x3, $x4, $x5, $x6, $x7) } + + private def ofTupleFromSeq8(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }) => '{ Tuple8($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8) } + + private def ofTupleFromSeq9(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }) => '{ Tuple9($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9) } + + private def ofTupleFromSeq10(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }) => '{ Tuple10($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10) } + + private def ofTupleFromSeq11(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }) => '{ Tuple11($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11) } + + private def ofTupleFromSeq12(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }) => '{ Tuple12($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12) } + + private def ofTupleFromSeq13(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }) => '{ Tuple13($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13) } + + private def ofTupleFromSeq14(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }) => '{ Tuple14($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14) } + + private def ofTupleFromSeq15(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }) => '{ Tuple15($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15) } + + private def ofTupleFromSeq16(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }) => '{ Tuple16($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16) } + + private def ofTupleFromSeq17(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }) => '{ Tuple17($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17) } + + private def ofTupleFromSeq18(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }, '{ $x18: t18 }) => '{ Tuple18($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18) } + + private def ofTupleFromSeq19(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }, '{ $x18: t18 }, '{ $x19: t19 }) => '{ Tuple19($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19) } + + private def ofTupleFromSeq20(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }, '{ $x18: t18 }, '{ $x19: t19 }, '{ $x20: t20 }) => '{ Tuple20($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20) } + + private def ofTupleFromSeq21(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }, '{ $x18: t18 }, '{ $x19: t19 }, '{ $x20: t20 }, '{ $x21: t21 }) => '{ Tuple21($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20, $x21) } + + private def ofTupleFromSeq22(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = + seq match case Seq('{ $x1: t1 }, '{ $x2: t2 }, '{ $x3: t3 }, '{ $x4: t4 }, '{ $x5: t5 }, '{ $x6: t6 }, '{ $x7: t7 }, '{ $x8: t8 }, '{ $x9: t9 }, '{ $x10: t10 }, '{ $x11: t11 }, '{ $x12: t12 }, '{ $x13: t13 }, '{ $x14: t14 }, '{ $x15: t15 }, '{ $x16: t16 }, '{ $x17: t17 }, '{ $x18: t18 }, '{ $x19: t19 }, '{ $x20: t20 }, '{ $x21: t21 }, '{ $x22: t22 }) => '{ Tuple22($x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15, $x16, $x17, $x18, $x19, $x20, $x21, $x22) } - case _ => - '{ Tuple.fromIArray(IArray(${Varargs(seq)}: _*)) } - } - } + /** Given a tuple of the form `(Expr[A1], ..., Expr[An])`, outputs a tuple `Expr[(A1, ..., An)]`. */ def ofTuple[T <: Tuple: Tuple.IsMappedBy[Expr]: Type](tup: T)(using qctx: QuoteContext): Expr[Tuple.InverseMap[T, Expr]] = { diff --git a/library/src/scala/internal/quoted/QuoteContextInternal.scala b/library/src/scala/internal/quoted/QuoteContextInternal.scala index 9d752fabb0bb..33e0a140956b 100644 --- a/library/src/scala/internal/quoted/QuoteContextInternal.scala +++ b/library/src/scala/internal/quoted/QuoteContextInternal.scala @@ -1,11 +1,11 @@ package scala.internal.quoted -import scala.quoted.QuoteContext +import scala.quoted.{QuoteContext, Expr, Type} import scala.tasty.reflect._ import scala.internal.quoted.PickledQuote /** Part of the QuoteContext interface that needs to be implemented by the compiler but is not visible to users */ -trait QuoteContextInternal { self: scala.quoted.QuoteContext => +trait QuoteContextInternal { self: QuoteContext => /** Unpickle `repr` which represents a pickled `Expr` tree, * replacing splice nodes with `holes` @@ -17,34 +17,45 @@ trait QuoteContextInternal { self: scala.quoted.QuoteContext => */ def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T] - /** Pattern matches the scrutinee against the pattern and returns a tuple - * with the matched holes if successful. - * - * Examples: - * - `termMatch(< f(0, myInt) >, < f(0, myInt) >)` - * will return `Some(())` (where `()` is a tuple of arity 0) - * - `termMatch(< f(0, myInt) >, < f(patternHole[Int], patternHole[Int]) >)` - * will return `Some(Tuple2('{0}, '{ myInt }))` - * - `termMatch(< f(0, "abc") >, < f(0, patternHole[Int]) >)` - * will return `None` due to the missmatch of types in the hole - * - * Holes: - * - 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 `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 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 `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 typeMatch(scrutinee: scala.quoted.Type[?], pattern: scala.quoted.Type[?]): Option[Tuple] + val ExprMatch: ExprMatchModule + + trait ExprMatchModule { self: ExprMatch.type => + /** Pattern matches an the scrutineeExpr against the patternExpr and returns a tuple + * with the matched holes if successful. + * + * Examples: + * - `ExprMatch.unapply('{ f(0, myInt) })('{ f(0, myInt) }, _)` + * will return `Some(())` (where `()` is a tuple of arity 0) + * - `ExprMatch.unapply('{ f(0, myInt) })('{ f(patternHole[Int], patternHole[Int]) }, _)` + * will return `Some(Tuple2('{0}, '{ myInt }))` + * - `ExprMatch.unapply('{ f(0, "abc") })('{ f(0, patternHole[Int]) }, _)` + * will return `None` due to the missmatch of types in the hole + * + * Holes: + * - scala.internal.quoted.Patterns.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 `Expr[Any]` on which we are pattern matching + * @param pattern `Expr[Any]` containing the pattern tree + * @param hasTypeSplices `Boolean` notify if the pattern has type splices + * @param qctx the current QuoteContext + * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]`` + */ + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: Expr[Any])(using pattern: Expr[Any]): Option[Tup] + } + + val TypeMatch: TypeMatchModule + trait TypeMatchModule { self: TypeMatch.type => + /** Pattern matches an the scrutineeType against the patternType and returns a tuple + * with the matched holes if successful. + * + * @param scrutinee `Type[?]` on which we are pattern matching + * @param pattern `Type[?]` containing the pattern tree + * @param hasTypeSplices `Boolean` notify if the pattern has type splices + * @param qctx the current QuoteContext + * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Type[Ti]`` + */ + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: Type[?])(using pattern: Type[?]): Option[Tup] + } } diff --git a/tests/run-macros/quote-matcher-runtime/quoted_1.scala b/tests/run-macros/quote-matcher-runtime/quoted_1.scala index e9280998a8a5..573af2af3316 100644 --- a/tests/run-macros/quote-matcher-runtime/quoted_1.scala +++ b/tests/run-macros/quote-matcher-runtime/quoted_1.scala @@ -7,7 +7,7 @@ object Macros { private def impl[A, B](a: Expr[A], b: Expr[B])(using qctx: QuoteContext) : Expr[Unit] = { import qctx.reflect._ - val res = scala.internal.quoted.Expr.unapply[Tuple, Tuple](a)(using b, qctx).map { tup => + val res = qctx.asInstanceOf[scala.internal.quoted.QuoteContextInternal].ExprMatch.unapply[Tuple, Tuple](a)(using b).map { tup => tup.toArray.toList.map { case r: Expr[_] => s"Expr(${r.show})" diff --git a/tests/run-macros/quote-matcher-runtime/quoted_2.scala b/tests/run-macros/quote-matcher-runtime/quoted_2.scala index 1d78d6c64531..b6c4a9df6d22 100644 --- a/tests/run-macros/quote-matcher-runtime/quoted_2.scala +++ b/tests/run-macros/quote-matcher-runtime/quoted_2.scala @@ -1,8 +1,6 @@ import Macros._ -import scala.internal.quoted.Expr._ - import scala.internal.quoted.Patterns._ object Test { diff --git a/tests/run-macros/quote-type-matcher/quoted_1.scala b/tests/run-macros/quote-type-matcher/quoted_1.scala index 20dce5ab98f4..c7cc5622a913 100644 --- a/tests/run-macros/quote-type-matcher/quoted_1.scala +++ b/tests/run-macros/quote-type-matcher/quoted_1.scala @@ -7,7 +7,7 @@ object Macros { private def matchesExpr[A, B](using a: Type[A], b: Type[B])(using qctx: QuoteContext) : Expr[Unit] = { import qctx.reflect._ - val res = scala.internal.quoted.Type.unapply[Tuple, Tuple](a)(using b, qctx).map { tup => + val res = qctx.asInstanceOf[scala.internal.quoted.QuoteContextInternal].TypeMatch.unapply[Tuple, Tuple](a)(using b).map { tup => tup.toArray.toList.map { case r: Type[_] => s"Type(${TypeTree.of(using r).show})"