diff --git a/tests/run-separate-compilation/f-interpolation-1/FQuote_1.scala b/tests/run-separate-compilation/f-interpolation-1/FQuote_1.scala new file mode 100644 index 000000000000..330e61643432 --- /dev/null +++ b/tests/run-separate-compilation/f-interpolation-1/FQuote_1.scala @@ -0,0 +1,58 @@ +import scala.quoted._ +import scala.tasty.Reflection + +import scala.language.implicitConversions + +object FQuote { + + implicit class SCOps(ctx: StringContext) { + inline def ff(args: => Any*): String = ~impl('(this), '(args)) + } + + /*private*/ def impl(receiver: Expr[SCOps], args: Expr[Seq[Any]])(implicit reflect: Reflection): Expr[String] = { + import reflect._ + + def liftListOfAny(lst: List[Term]): Expr[List[Any]] = lst match { + case x :: xs => + val head = x.seal[Any] + val tail = liftListOfAny(xs) + '{ ~head :: ~tail } + case Nil => '(Nil) + } + + def isStringConstant(tree: Term) = tree match { + case Term.Literal(_) => true + case _ => false + } + + def isSCOpsConversion(tree: Term) = + tree.symbol.fullName == "FQuote$.SCOps" + + def isStringContextApply(tree: Term) = + tree.symbol.fullName == "scala.StringContext$.apply" + + // FQuote.SCOps(StringContext.apply([p0, ...]: String*) + val parts = receiver.unseal.underlyingArgument match { + case Term.Apply(conv, List(Term.Apply(fun, List(Term.Typed(Term.Repeated(values), _))))) + if isSCOpsConversion(conv) && + isStringContextApply(fun) && + values.forall(isStringConstant) => + values.collect { case Term.Literal(Constant.String(value)) => value } + case tree => + throw new QuoteError(s"String literal expected, but ${tree.show} found") + } + + // [a0, ...]: Any* + val Term.Typed(Term.Repeated(allArgs), _) = args.unseal.underlyingArgument + + for ((arg, part) <- allArgs.zip(parts.tail)) { + if (part.startsWith("%d") && !(arg.tpe <:< definitions.IntType)) { + return '(s"`${~arg.showCode.toExpr}` is not of type Int") + } + + } + + val string = parts.mkString("") + '{ new collection.immutable.StringOps(~string.toExpr).format(~args: _*) } + } +} diff --git a/tests/run-separate-compilation/f-interpolation-1/Test_2.scala b/tests/run-separate-compilation/f-interpolation-1/Test_2.scala new file mode 100644 index 000000000000..a343ce600a18 --- /dev/null +++ b/tests/run-separate-compilation/f-interpolation-1/Test_2.scala @@ -0,0 +1,10 @@ +import FQuote._ + +object Test { + def main(args: Array[String]): Unit = { + val one: Int = 1 + assert(ff"Hello $one%d!" == "Hello 1!") + val world: String = "world" + assert(ff"Hello $world%d!" == "`world` is not of type Int") + } +}