diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 4f5ef7907a9b..8d0691037795 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -824,8 +824,11 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] => * The result can be the contents of a term or type splice, which * will return a term or type tree respectively. */ - def unapply(tree: tpd.Select)(implicit ctx: Context): Option[tpd.Tree] = - if (tree.symbol.isSplice) Some(tree.qualifier) else None + def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match { + case tree: tpd.Apply if tree.symbol.isSplice => Some(tree.args.head) + case tree: tpd.Select if tree.symbol.isSplice => Some(tree.qualifier) + case _ => None + } } } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index fb377132a626..9f9aeedf02e1 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -704,12 +704,13 @@ class Definitions { lazy val QuotedExprType: TypeRef = ctx.requiredClassRef("scala.quoted.Expr") def QuotedExprClass(implicit ctx: Context): ClassSymbol = QuotedExprType.symbol.asClass - lazy val QuotedExpr_splice : TermSymbol = QuotedExprClass.requiredMethod(nme.splice) lazy val InternalQuotedModule: TermRef = ctx.requiredModuleRef("scala.internal.Quoted") def InternalQuotedModuleClass: Symbol = InternalQuotedModule.symbol lazy val InternalQuoted_exprQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprQuote".toTermName) def InternalQuoted_exprQuote(implicit ctx: Context): Symbol = InternalQuoted_exprQuoteR.symbol + lazy val InternalQuoted_exprSpliceR: TermRef = InternalQuotedModuleClass.requiredMethodRef("exprSplice".toTermName) + def InternalQuoted_exprSplice(implicit ctx: Context): Symbol = InternalQuoted_exprSpliceR.symbol lazy val InternalQuoted_typeQuoteR: TermRef = InternalQuotedModuleClass.requiredMethodRef("typeQuote".toTermName) def InternalQuoted_typeQuote(implicit ctx: Context): Symbol = InternalQuoted_typeQuoteR.symbol diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index d192cfa579d4..482a63b7316b 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -328,8 +328,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (name.isTypeName) typeText(txt) else txt case tree @ Select(qual, name) => - if (tree.hasType && tree.symbol == defn.QuotedExpr_splice) keywordStr("${") ~ toTextLocal(qual) ~ keywordStr("}") - else if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}") + if (tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}") else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name)) else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided (name != nme.CONSTRUCTOR || ctx.settings.YprintDebug.value)) case tree: This => @@ -343,6 +342,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } else if (fun.hasType && fun.symbol == defn.InternalQuoted_exprQuote) keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}") + else if (fun.hasType && fun.symbol == defn.InternalQuoted_exprSplice) + keywordStr("${") ~ toTextGlobal(args, ", ") ~ keywordStr("}") else toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")" case tree: TypeApply => diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 373c107109f7..657c053f1369 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -49,18 +49,23 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( * - If inside inlined code, expand the macro code. * - If inside of a macro definition, check the validity of the macro. */ - protected def transformSplice(splice: Select)(implicit ctx: Context): Tree = { + protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = { if (level >= 1) { - val body1 = transform(splice.qualifier)(spliceContext) - val splice1 = cpy.Select(splice)(body1, splice.name) - if (splice1.isType) splice1 - else addSpliceCast(splice1) + val body1 = transform(body)(spliceContext) + splice match { + case Apply(fun: TypeApply, _) if splice.isTerm => + // Type of the splice itsel must also be healed + // internal.Quoted.expr[F[T]](... T ...) --> internal.Quoted.expr[F[$t]](... T ...) + val tp = checkType(splice.sourcePos).apply(splice.tpe.widenTermRefExpr) + cpy.Apply(splice)(cpy.TypeApply(fun)(fun.fun, tpd.TypeTree(tp) :: Nil), body1 :: Nil) + case splice: Select => cpy.Select(splice)(body1, splice.name) + } } else { assert(!enclosingInlineds.nonEmpty, "unexpanded macro") assert(ctx.owner.isInlineMethod) - if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside an inline definition - transform(splice.qualifier)(spliceContext) // Just check PCP + if (Splicer.canBeSpliced(body)) { // level 0 inside an inline definition + transform(body)(spliceContext) // Just check PCP splice } else { // level 0 inside an inline definition @@ -72,15 +77,6 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( } } - - /** Add cast to force boundaries where T and $t (an alias of T) are used to ensure PCP. - * '{ ${...: T} } --> '{ ${...: T}.asInstanceOf[T] } --> '{ ${...: T}.asInstanceOf[$t] } - */ - protected def addSpliceCast(tree: Tree)(implicit ctx: Context): Tree = { - val tp = checkType(tree.sourcePos).apply(tree.tpe.widenTermRefExpr) - tree.cast(tp).withSpan(tree.span) - } - /** If `tree` refers to a locally defined symbol (either directly, or in a pickled type), * check that its staging level matches the current level. References to types * that are phase-incorrect can still be healed as follows: diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 71c953c17568..ddfb98629b95 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -170,7 +170,7 @@ class ReifyQuotes extends MacroTransform { */ override protected def transformQuotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = { val isType = quote.symbol eq defn.InternalQuoted_typeQuote - assert(!body.symbol.isSplice) + assert(!(body.symbol.isSplice && (body.isInstanceOf[GenericApply[_]] || body.isInstanceOf[Select]))) if (level > 0) { val body1 = nested(isQuote = true).transform(body)(quoteContext) super.transformQuotation(body1, quote) @@ -222,21 +222,24 @@ class ReifyQuotes extends MacroTransform { * and make a hole from these parts. Otherwise issue an error, unless we * are in the body of an inline method. */ - protected def transformSplice(splice: Select)(implicit ctx: Context): Tree = { + protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = { if (level > 1) { - val body1 = nested(isQuote = false).transform(splice.qualifier)(spliceContext) - body1.select(splice.name) + val body1 = nested(isQuote = false).transform(body)(spliceContext) + splice match { + case splice: Apply => cpy.Apply(splice)(splice.fun, body1 :: Nil) + case splice: Select => cpy.Select(splice)(body1, splice.name) + } } else { assert(level == 1, "unexpected top splice outside quote") - val (body1, quotes) = nested(isQuote = false).splitSplice(splice.qualifier)(spliceContext) - val tpe = outer.embedded.getHoleType(splice) + val (body1, quotes) = nested(isQuote = false).splitSplice(body)(spliceContext) + val tpe = outer.embedded.getHoleType(body, splice) val hole = makeHole(body1, quotes, tpe).withSpan(splice.span) // We do not place add the inline marker for trees that where lifted as they come from the same file as their // enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree. // Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions. // For example we can have a lifted tree containing the LHS of an assignment (see tests/run-with-compiler/quote-var.scala). - if (splice.isType || outer.embedded.isLiftedSymbol(splice.qualifier.symbol)) hole + if (splice.isType || outer.embedded.isLiftedSymbol(body.symbol)) hole else Inlined(EmptyTree, Nil, hole).withSpan(splice.span) } } @@ -346,14 +349,13 @@ class ReifyQuotes extends MacroTransform { override def transform(tree: Tree)(implicit ctx: Context): Tree = reporting.trace(i"Reifier.transform $tree at $level", show = true) { tree match { - case TypeApply(Select(spliceTree @ Spliced(_), _), tp) if tree.symbol.isTypeCast => - // Splice term which should be in the form `${x}.asInstanceOf[T]` where T is an artifact of - // typer to allow pickling/unpickling phase consistent types - transformSplice(spliceTree) - case tree: RefTree if isCaptured(tree.symbol, level) => - val t = capturers(tree.symbol).apply(tree) - transformSplice(t.select(if (tree.isTerm) nme.splice else tpnme.splice)) + val body = capturers(tree.symbol).apply(tree) + val splice: Tree = + if (tree.isType) body.select(tpnme.splice) + else ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body) + + transformSplice(body, splice) case tree: DefDef if tree.symbol.is(Macro) && level == 0 => // Shrink size of the tree. The methods have already been inlined. @@ -396,11 +398,11 @@ object ReifyQuotes { } /** Type used for the hole that will replace this splice */ - def getHoleType(splice: tpd.Select)(implicit ctx: Context): Type = { + def getHoleType(body: tpd.Tree, splice: tpd.Tree)(implicit ctx: Context): Type = { // For most expressions the splice.tpe but there are some types that are lost by lifting // that can be recoverd from the original tree. Currently the cases are: // * Method types: the splice represents a method reference - map.get(splice.qualifier.symbol).map(_.tpe.widen).getOrElse(splice.tpe) + map.get(body.symbol).map(_.tpe.widen).getOrElse(splice.tpe) } def isLiftedSymbol(sym: Symbol)(implicit ctx: Context): Boolean = map.contains(sym) diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 43eceac8b569..77d699b36fd0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -44,8 +44,6 @@ class Staging extends MacroTransform { tree match { case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass => val checker = new PCPCheckAndHeal(freshStagingContext) { - override protected def addSpliceCast(tree: Tree)(implicit ctx: Context): Tree = tree - override protected def tryHeal(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[tpd.Tree] = { def symStr = if (!tp.isInstanceOf[ThisType]) sym.show diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 886dbc177537..deaaa39f8884 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -157,5 +157,5 @@ class SymUtils(val self: Symbol) extends AnyVal { /** Is symbol a splice operation? */ def isSplice(implicit ctx: Context): Boolean = - self == defn.QuotedExpr_splice || self == defn.QuotedType_splice + self == defn.InternalQuoted_exprSplice || self == defn.QuotedType_splice } diff --git a/compiler/src/dotty/tools/dotc/transform/TreeMapWithStages.scala b/compiler/src/dotty/tools/dotc/transform/TreeMapWithStages.scala index fcd651dea1e2..6e44cfcc8b40 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeMapWithStages.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeMapWithStages.scala @@ -64,8 +64,8 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap } } - /** Transform the splice `splice`. */ - protected def transformSplice(splice: Select)(implicit ctx: Context): Tree + /** Transform the splice `splice` which contains the spliced `body`. */ + protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree override def transform(tree: Tree)(implicit ctx: Context): Tree = { reporting.trace(i"StagingTransformer.transform $tree at $level", show = true) { @@ -93,7 +93,7 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap case tree @ Spliced(splicedTree) => dropEmptyBlocks(splicedTree) match { case Quoted(t) => transform(t) // ${ 'x } --> x - case _ => transformSplice(tree) + case _ => transformSplice(splicedTree, tree) } case Block(stats, _) => diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 807942194640..3c97d184e4d1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -968,21 +968,11 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { assert(tree.hasType, tree) val qual1 = typed(tree.qualifier, selectionProto(tree.name, pt, this)) - val res = - if (tree.symbol == defn.QuotedExpr_splice && level == 0) expandMacro(qual1, tree.span) - else untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt) + val res = untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt) ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.sourcePos) res } - private def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = { - assert(level == 0) - val inlinedFrom = enclosingInlineds.last - val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx.withSource(inlinedFrom.source)) - if (ctx.reporter.hasErrors) EmptyTree - else evaluatedSplice.withSpan(span) - } - override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree = typed(tree.cond, defn.BooleanType) match { case cond1 @ ConstantValue(b: Boolean) => @@ -1001,8 +991,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { } } - override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = - constToLiteral(betaReduce(super.typedApply(tree, pt))) + override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { + constToLiteral(betaReduce(super.typedApply(tree, pt))) match { + case res: Apply if res.symbol == defn.InternalQuoted_exprSplice && level == 0 => + expandMacro(res.args.head, tree.span) + case res => res + } + } override def typedMatchFinish(tree: untpd.Match, sel: Tree, wideSelType: Type, cases: List[untpd.CaseDef], pt: Type)(implicit ctx: Context) = if (!tree.isInline || ctx.owner.isInlineMethod) // don't reduce match of nested inline method yet @@ -1159,4 +1154,13 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { inlineTermBindings(termBindings1.asInstanceOf[List[ValOrDefDef]], tree1) } } + + private def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = { + assert(level == 0) + val inlinedFrom = enclosingInlineds.last + val evaluatedSplice = Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)(ctx.withSource(inlinedFrom.source)) + if (ctx.reporter.hasErrors) EmptyTree + else evaluatedSplice.withSpan(span) + } + } diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index e361f2137f89..04c2521c68c2 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -270,7 +270,7 @@ object PrepareInlineable { var isMacro = false new TreeMapWithStages(freshStagingContext) { - override protected def transformSplice(splice: tpd.Select)(implicit ctx: Context): tpd.Tree = { + override protected def transformSplice(body: tpd.Tree, splice: tpd.Tree)(implicit ctx: Context): tpd.Tree = { isMacro = true splice } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 84aa389ab9e7..b3bf15dfe745 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1926,7 +1926,7 @@ class Typer extends Namer } } - /** Translate '{ t }` into `scala.quoted.Expr.apply(t)` and `'[T]` into `scala.quoted.Type.apply[T]` + /** Translate `'{ t }` into `scala.quoted.Expr.apply(t)` and `'[T]` into `scala.quoted.Type.apply[T]` * while tracking the quotation level in the context. */ def typedQuote(tree: untpd.Quote, pt: Type)(implicit ctx: Context): Tree = track("typedQuote") { @@ -1941,7 +1941,7 @@ class Typer extends Namer } } - /** Translate `${ t: Expr[T] }` into expresiion `t.splice` while tracking the quotation level in the context */ + /** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */ def typedSplice(tree: untpd.Splice, pt: Type)(implicit ctx: Context): Tree = track("typedSplice") { checkSpliceOutsideQuote(tree) tree.expr match { @@ -1949,7 +1949,7 @@ class Typer extends Namer ctx.warning("Canceled quote directly inside a splice. ${ '{ XYZ } } is equivalent to XYZ.", tree.sourcePos) typed(innerExpr, pt) case expr => - typedSelect(untpd.Select(expr, nme.splice), pt)(spliceContext).withSpan(tree.span) + typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprSpliceR), tree.expr), pt)(spliceContext).withSpan(tree.span) } } @@ -1961,7 +1961,14 @@ class Typer extends Namer private def checkSpliceOutsideQuote(tree: untpd.Tree)(implicit ctx: Context): Unit = { if (level == 0 && !ctx.owner.isInlineMethod) - ctx.error("splice outside quotes or inline method", tree.sourcePos) + ctx.error("Splice ${...} outside quotes '{...} or inline method", tree.sourcePos) + else if (level < 0) + ctx.error( + """Splice ${...} at level -1. + | + |Inline method may contain a splice at level 0 but the contents of this splice cannot have a splice. + |""".stripMargin, tree.sourcePos + ) } /** Retrieve symbol attached to given tree */ diff --git a/library/src-bootstrapped/scala/StagedTuple.scala b/library/src-bootstrapped/scala/StagedTuple.scala index ff65b01770f1..30c167871ada 100644 --- a/library/src-bootstrapped/scala/StagedTuple.scala +++ b/library/src-bootstrapped/scala/StagedTuple.scala @@ -203,7 +203,8 @@ object StagedTuple { if (!specialize) '{dynamic_++[Self, That]($self, $that)} else { def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] = - fromArrayStaged[Tuple]('{${ toArrayStaged(xs, None) } ++ ${ toArrayStaged(ys, None) }}, None) + // TODO remove ascriptions when #6126 is fixed + fromArrayStaged[Tuple]('{${ toArrayStaged(xs, None) } ++ (${ toArrayStaged(ys, None) }: Array[Object])}, None) val res = selfSize match { case Some(0) => diff --git a/library/src-bootstrapped/scala/internal/Quoted.scala b/library/src-bootstrapped/scala/internal/Quoted.scala index d28fd48f9c2e..b3d3f41cec9e 100644 --- a/library/src-bootstrapped/scala/internal/Quoted.scala +++ b/library/src-bootstrapped/scala/internal/Quoted.scala @@ -8,6 +8,10 @@ object Quoted { def exprQuote[T](x: T): Expr[T] = throw new Error("Internal error: this method call should have been replaced by the compiler") + /** A term splice is desugared by the compiler into a call to this method */ + def exprSplice[T](x: Expr[T]): T = + throw new Error("Internal error: this method call should have been replaced by the compiler") + /** A type quote is desugared by the compiler into a call to this method */ def typeQuote[T <: AnyKind]: Type[T] = throw new Error("Internal error: this method call should have been replaced by the compiler") diff --git a/library/src-non-bootstrapped/scala/internal/Quoted.scala b/library/src-non-bootstrapped/scala/internal/Quoted.scala index 8ddabf2d83de..5c6dcfcd6d10 100644 --- a/library/src-non-bootstrapped/scala/internal/Quoted.scala +++ b/library/src-non-bootstrapped/scala/internal/Quoted.scala @@ -8,6 +8,10 @@ object Quoted { def exprQuote[T](x: T): Expr[T] = throw new Error("Internal error: this method call should have been replaced by the compiler") + /** A term splice is desugared by the compiler into a call to this method */ + def exprSplice[T](x: Expr[T]): T = + throw new Error("Internal error: this method call should have been replaced by the compiler") + /** A type quote is desugared by the compiler into a call to this method */ def typeQuote[T/* <: AnyKind */]: Type[T] = throw new Error("Internal error: this method call should have been replaced by the compiler") diff --git a/library/src/scala/quoted/Expr.scala b/library/src/scala/quoted/Expr.scala index 9431ba327424..c15cad31e08d 100644 --- a/library/src/scala/quoted/Expr.scala +++ b/library/src/scala/quoted/Expr.scala @@ -4,8 +4,6 @@ import scala.runtime.quoted.Unpickler.Pickled sealed abstract class Expr[+T] { - final def `$splice`: T = throw new Error("splice should have been compiled away") - /** Evaluate the contents of this expression and return the result. * * May throw a FreeVariableError on expressions that came from a macro. diff --git a/tests/pos/quote-whitebox/Macro_1.scala b/tests/disabled/pos/quote-whitebox/Macro_1.scala similarity index 100% rename from tests/pos/quote-whitebox/Macro_1.scala rename to tests/disabled/pos/quote-whitebox/Macro_1.scala diff --git a/tests/pos/quote-whitebox/Test_2.scala b/tests/disabled/pos/quote-whitebox/Test_2.scala similarity index 100% rename from tests/pos/quote-whitebox/Test_2.scala rename to tests/disabled/pos/quote-whitebox/Test_2.scala diff --git a/tests/pos/i4774f.scala b/tests/pos/i4774f.scala index c9b76b1b3688..9925755fc0bf 100644 --- a/tests/pos/i4774f.scala +++ b/tests/pos/i4774f.scala @@ -6,5 +6,5 @@ object Test { '{ def y: T = $x; ${ loop('y) } } def loop2[T](x: Expr[T])(implicit t: Type[T]): Expr[T] = - '{ def y(): T = $x; ${ loop('{y()}) } } + '{ def y(): T = $x; ${ loop2('{y()}) } } } diff --git a/tests/pos/quote-nested.scala b/tests/pos/quote-nested.scala new file mode 100644 index 000000000000..ed5d86d26fa2 --- /dev/null +++ b/tests/pos/quote-nested.scala @@ -0,0 +1,22 @@ +import scala.annotation.tailrec +import scala.quoted._ + +object Macro { + + inline def foo: Unit = ${ nested() } + + private def nested(): Expr[Unit] = '{ + var i = 0 + ${ + val x: Expr[Double] = '{ + val y: Boolean = ${ + val z: Expr[Int] = '{i + 3} + '{true} + } + 4.2 + } + '{} + } + () + } +} diff --git a/tests/pos/quote-whitebox-2/Macro_1.scala b/tests/pos/quote-whitebox-2/Macro_1.scala new file mode 100644 index 000000000000..19e1184054de --- /dev/null +++ b/tests/pos/quote-whitebox-2/Macro_1.scala @@ -0,0 +1,10 @@ + +import scala.quoted._ + +object Macro { + + inline def charOrString(inline str: String) <: Any = ${ impl(str) } + + def impl(str: String) = if (str.length == 1) str.charAt(0).toExpr else str.toExpr + +} diff --git a/tests/pos/quote-whitebox-2/Test_2.scala b/tests/pos/quote-whitebox-2/Test_2.scala new file mode 100644 index 000000000000..da5757f22d79 --- /dev/null +++ b/tests/pos/quote-whitebox-2/Test_2.scala @@ -0,0 +1,8 @@ +import Macro._ + +object Test { + + val x: Char = charOrString("1") + val y: String = charOrString("123") + +} diff --git a/tests/run/quote-unrolled-foreach/quoted_1.scala b/tests/run/quote-unrolled-foreach/quoted_1.scala index eecf8e094414..6db49679a47e 100644 --- a/tests/run/quote-unrolled-foreach/quoted_1.scala +++ b/tests/run/quote-unrolled-foreach/quoted_1.scala @@ -15,7 +15,7 @@ object Macro { ${ @tailrec def loop(j: Int, acc: Expr[Unit]): Expr[Unit] = if (j >= 0) loop(j - 1, '{ ${f('{$seq(i + ${j.toExpr})})}; $acc }) - else acc + else acc loop(unrollSize - 1, '{}) } i += ${unrollSize.toExpr}