diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index b4512be18708..438d9098c2e8 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -47,6 +47,7 @@ class Compiler { List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new PostTyper) :: // Additional checks and cleanups after type checking List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks + List(new MacrosSplitter) :: // Applies ReifyQuotes transformation to the body of the macros Nil /** Phases dealing with TASTY tree pickling and unpickling */ diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 18f46407ddd8..90c57c464b15 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -676,7 +676,7 @@ class Definitions { def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType") lazy val TastyTopLevelSpliceModule = ctx.requiredModule("scala.tasty.TopLevelSplice") - lazy val TastyTopLevelSplice_compilationTopLevelSplice = TastyTopLevelSpliceModule.requiredMethod("tastyContext") + lazy val TastyTopLevelSplice_tastyContext = TastyTopLevelSpliceModule.requiredMethod("tastyContext") lazy val EqType = ctx.requiredClassRef("scala.Eq") def EqClass(implicit ctx: Context) = EqType.symbol.asClass diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index a9f841c33697..221ad37e48b7 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -292,6 +292,7 @@ object NameKinds { val SuperArgName = new UniqueNameKind("$superArg$") val DocArtifactName = new UniqueNameKind("$doc") val UniqueInlineName = new UniqueNameKind("$i") + val UniqueSpliceName = new UniqueNameKind("$splice$") /** A kind of unique extension methods; Unlike other unique names, these can be * unmangled. diff --git a/compiler/src/dotty/tools/dotc/transform/MacrosSplitter.scala b/compiler/src/dotty/tools/dotc/transform/MacrosSplitter.scala new file mode 100644 index 000000000000..8d5ec8658ac0 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/MacrosSplitter.scala @@ -0,0 +1,188 @@ +package dotty.tools.dotc +package transform + +import core._ +import Decorators._ +import Types._ +import Contexts._ +import Symbols._ +import Constants._ +import Flags._ +import ast.Trees._ +import ast.{TreeTypeMap, tpd} +import tasty.TreePickler.Hole +import SymUtils._ +import NameKinds._ + +import scala.collection.mutable +import dotty.tools.dotc.core.StdNames._ + + +/** Translates macro implementation. + * Checks that the phase consistency principle (PCP) holds on the body of a macro. + * + * + * Transforms an inline macro definitions we assume that we have a single ~ directly as the RHS. + * We will transform the definition from + * ``` + * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Z = ~{ ... x1 ... '{ ... T1 ... x1 ... '(y) ... } } + * ``` + * to + * ``` + * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Z = ~foo$splice$1[T1, ...]('[T1], ..., x1, ..., '(y1), ...) + * + * def foo$splice$1[T1, ...](T1$1: Type[T1], ..., x1$1: X, ..., y1: Expr[Y], ....): Z = + * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... } + * ``` + * Where `inline` parameters with type Boolean, Byte, Short, Int, Long, Float, Double, Char and String are + * passed as their actual runtime value. See `isStage0Value`. Other `inline` arguments such as functions are handled + * like `y1: Y`. + * + * + * At inline site we will call reflectively the static method `foo$splice$1` with the interpreted parameters. + */ +class MacrosSplitter extends ReifyQuotes { + import ast.tpd._ + + override def phaseName: String = "macrosSplitter" + + override def run(implicit ctx: Context): Unit = + if (ctx.compilationUnit.containsQuotesOrSplices) super.run + + protected override def newTransformer(implicit ctx: Context): Transformer = { + new Transformer { + override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { + case tree: PackageDef => super.transform(tree) + case tree: TypeDef => super.transform(tree) + case tree: Template => super.transform(tree) + case macroDefTree: DefDef if macroDefTree.symbol.is(Inline) => + + val reifier = new Reifier(true, null, 1, new LevelInfo, new mutable.ListBuffer[Tree]) + + val transformedTree = reifier.transform(macroDefTree) // Ignore output, we only need the its embedding + + if (reifier.embedded.isEmpty) macroDefTree // Not a macro + else { + if (!macroDefTree.symbol.isStatic) // TODO remove restriction (issue #4803) + ctx.error("Inline macro method must be a static method.", macroDefTree.pos) + if (InlineSplice.unapply(macroDefTree.rhs).isEmpty) { // TODO allow multiple splices (issue #4801) + ctx.error( + """Malformed inline macro. + | + |Expected the ~ to be at the top of the RHS: + | inline def foo(...): Int = ~impl(...) + |or + | inline def foo(...): Int = ~{ + | val x = 1 + | impl(... x ...) + | } + """.stripMargin, macroDefTree.rhs.pos) + EmptyTree + } + else { + val splicers = List.newBuilder[DefDef] + val transformer = new TreeMap() { + override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match { + case Hole(idx, args) => + val targs = args.filter(_.isType).map(_.tpe) + + val Block((lambdaDef: tpd.DefDef) :: Nil, _) = reifier.embedded(idx) + + val splicer = genSplicer(macroDefTree, lambdaDef, targs) + splicers += splicer + + val liftedArgs = args.map { arg => + if (arg.symbol.is(Inline) || arg.symbol == defn.TastyTopLevelSplice_tastyContext) arg + else if (arg.isType) ref(defn.QuotedType_apply).appliedToType(arg.tpe) + else ref(defn.QuotedExpr_apply).appliedToType(arg.tpe.widen).appliedTo(arg) + } + ref(splicer.symbol).appliedToTypes(targs).appliedToArgs(liftedArgs).select(nme.UNARY_~) + case _ => super.transform(tree) + } + } + val newRhs = transformer.transform(transformedTree.asInstanceOf[DefDef].rhs) + val newDef = cpy.DefDef(macroDefTree)(rhs = newRhs) + Thicket(newDef :: splicers.result()) + } + } + case _ => + tree + } + } + } + + /** Generates splicer method from a lambda generated by `ReifyQuotes` + * + * Transforms `lambdaDef` (with the given `targs`) + * ``` + * (args: Seq[Any]) => { + * val T1$1 = args(0).asInstanceOf[Type[T1]] + * ... + * val x1$1 = args(0).asInstanceOf[X] + * ... + * val y1$1 = args(1).asInstanceOf[Expr[Y]] + * ... + * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... } + * } + * ``` + * + * into + * + * ``` + * def foo$splice$1[T1, ...](T1$1: Type[T1], ..., x1$1: X, ..., y1: Expr[Y], ....): Z = + * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... } + * ``` + */ + private def genSplicer(macroDefTree: DefDef, lambdaDef: DefDef, targs: List[Type])(implicit ctx: Context): DefDef = { + val sym = macroDefTree.symbol + + val DefDef(_, _, _, _, Block(args: List[ValDef] @unchecked, body: Tree @unchecked)) = lambdaDef + + val splicerRetType = { + val methodType = MethodType(args.map(_.name), args.map(_.tpt.tpe), lambdaDef.symbol.info.finalResultType) + if (targs.isEmpty) methodType + else { + val tpArgSyms = targs.map(_.typeSymbol) + val tpArgName = tpArgSyms.map(_.name.asTypeName) + val tpArgBounds = tpArgSyms.map(_.info.bounds) + PolyType(tpArgName)(_ => tpArgBounds, pt => methodType.subst(targs.map(_.typeSymbol), pt.paramRefs)) + } + } + + val splicerName = UniqueSpliceName.fresh(sym.name.asTermName) + val splicerSym = ctx.newSymbol(sym.owner, splicerName, sym.flags &~ Inline &~ Implicit, splicerRetType, sym.privateWithin, sym.coord).asTerm + + def treeTypeMap(tparams: List[Type], params: List[Tree]) = { + val treeMap: Tree => Tree = { + val map = args.map(_.symbol).zip(params).toMap + tree => map.getOrElse(tree.symbol, tree) + } + val typeMap: Type => Type = new TypeMap() { + private val map = macroDefTree.tparams.map(_.symbol).zip(tparams).toMap + def apply(tp: Type): Type = map.getOrElse(tp.typeSymbol, mapOver(tp)) + } + new TreeTypeMap( + typeMap = typeMap, treeMap = treeMap, + oldOwners = lambdaDef.symbol :: Nil, newOwners = splicerSym :: Nil, + substFrom = lambdaDef.tparams.map(_.symbol), substTo = tparams.map(_.typeSymbol) + ) + } + + polyDefDef(splicerSym, tparams => vparamss => treeTypeMap(tparams, vparamss.head).transform(body)) + } + + /** InlineSplice is used to detect cases where the expansion + * consists of a (possibly multiple & nested) block or a sole expression. + */ + object InlineSplice { + def unapply(tree: Tree)(implicit ctx: Context): Option[Select] = { + tree match { + case expansion: Select if expansion.symbol.isSplice => Some(expansion) + case Block(List(stat), Literal(Constant(()))) => unapply(stat) + case Block(Nil, expr) => unapply(expr) + case _ => None + } + } + } + +} diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 76f9c4db865a..b831f56237c0 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -2,10 +2,15 @@ package dotty.tools.dotc package transform import core._ -import Decorators._, Flags._, Types._, Contexts._, Symbols._, Constants._ +import Decorators._ +import Flags._ +import Types._ +import Contexts._ +import Symbols._ +import Constants._ import Flags._ import ast.Trees._ -import ast.{TreeTypeMap, untpd} +import ast.{TreeTypeMap, tpd, untpd} import util.Positions._ import StdNames._ import tasty.TreePickler.Hole @@ -23,6 +28,7 @@ import dotty.tools.dotc.core.quoted._ /** Translates quoted terms and types to `unpickle` method calls. * Checks that the phase consistency principle (PCP) holds. + * Expand macro calls. * * * Transforms top level quote @@ -58,35 +64,8 @@ import dotty.tools.dotc.core.quoted._ * ``` * and then performs the same transformation on `'{ ... x1$1.unary_~ ... x2$1.unary_~ ...}`. * - * - * For inline macro definitions we assume that we have a single ~ directly as the RHS. - * We will transform the definition from - * ``` - * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Z = ~{ ... T1 ... x ... '(y) ... } - * ``` - * to - * ``` - * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Seq[Any] => Object = { (args: Seq[Any]) => { - * val T1$1 = args(0).asInstanceOf[Type[T1]] - * ... - * val x1$1 = args(0).asInstanceOf[X] - * ... - * val y1$1 = args(1).asInstanceOf[Expr[Y]] - * ... - * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... } - * } - * ``` - * Where `inline` parameters with type Boolean, Byte, Short, Int, Long, Float, Double, Char and String are - * passed as their actual runtime value. See `isStage0Value`. Other `inline` arguments such as functions are handled - * like `y1: Y`. - * - * Note: the parameters of `foo` are kept for simple overloading resolution but they are not used in the body of `foo`. - * - * At inline site we will call reflectively the static method `foo` with dummy parameters, which will return a - * precompiled version of the function that will evaluate the `Expr[Z]` that `foo` produces. The lambda is then called - * at the inline site with the lifted arguments of the inlined call. */ -class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { +class ReifyQuotes extends MacroTransformWithImplicits { import ast.tpd._ /** Classloader used for loading macros */ @@ -107,7 +86,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { protected def newTransformer(implicit ctx: Context): Transformer = new Reifier(inQuote = false, null, 0, new LevelInfo, new mutable.ListBuffer[Tree]) - private class LevelInfo { + protected class LevelInfo { /** A map from locally defined symbols to the staging levels of their definitions */ val levelOf = new mutable.HashMap[Symbol, Int] @@ -134,7 +113,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { * @param levels a stacked map from symbols to the levels in which they were defined * @param embedded a list of embedded quotes (if `inSplice = true`) or splices (if `inQuote = true` */ - private class Reifier(inQuote: Boolean, val outer: Reifier, val level: Int, levels: LevelInfo, + protected class Reifier(inQuote: Boolean, val outer: Reifier, val level: Int, levels: LevelInfo, val embedded: mutable.ListBuffer[Tree]) extends ImplicitsTransformer { import levels._ assert(level >= 0) @@ -146,10 +125,10 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } /** We are in a `~(...)` context that is not shadowed by a nested `'(...)` */ - def inSplice = outer != null && !inQuote + def inSplice: Boolean = outer != null && !inQuote /** We are not in a `~(...)` or a `'(...)` */ - def isRoot = outer == null + def isRoot: Boolean = outer == null /** A map from type ref T to expressions of type `quoted.Type[T]`". * These will be turned into splices using `addTags` and represent type variables @@ -232,7 +211,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } /** Enter staging level of symbol defined by `tree`, if applicable. */ - def markDef(tree: Tree)(implicit ctx: Context) = tree match { + def markDef(tree: Tree)(implicit ctx: Context): Unit = tree match { case tree: DefTree => val sym = tree.symbol if ((sym.isClass || !sym.maybeOwner.isType) && !levelOf.contains(sym)) { @@ -267,7 +246,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { def tryHeal(tp: Type, pos: Position)(implicit ctx: Context): Option[String] = tp match { case tp: TypeRef => if (level == 0) { - assert(ctx.owner.ownersIterator.exists(_.is(Macro))) + assert(ctx.owner.ownersIterator.exists(_.is(Inline))) None } else { val reqType = defn.QuotedTypeType.appliedTo(tp) @@ -298,7 +277,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { else i"${sym.name}.this" if (!isThis && sym.maybeOwner.isType && !sym.is(Param)) check(sym.owner, sym.owner.thisType, pos) - else if (level == 1 && sym.isType && sym.is(Param) && sym.owner.is(Macro) && !outer.isRoot) + else if (level == 1 && sym.isType && sym.is(Param) && sym.owner.is(Inline) && outer != null && !outer.isRoot) importedTags(sym.typeRef) = capturers(sym)(ref(sym)) else if (sym.exists && !sym.isStaticOwner && !levelOK(sym)) for (errMsg <- tryHeal(tp, pos)) @@ -515,10 +494,10 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { outer.enteredSyms.foreach(registerCapturer) - if (ctx.owner.owner.is(Macro)) { - registerCapturer(defn.TastyTopLevelSplice_compilationTopLevelSplice) + if (ctx.owner.owner.is(Inline)) { + registerCapturer(defn.TastyTopLevelSplice_tastyContext) // Force a macro to have the context in first position - forceCapture(defn.TastyTopLevelSplice_compilationTopLevelSplice) + forceCapture(defn.TastyTopLevelSplice_tastyContext) // Force all parameters of the macro to be created in the definition order outer.enteredSyms.reverse.foreach(forceCapture) } @@ -526,7 +505,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { val tree2 = transform(tree) capturers --= outer.enteredSyms - seq(captured.result().valuesIterator.toList, tree2) + Block(captured.result().valuesIterator.toList, tree2) } /** Returns true if this tree will be captured by `makeLambda` */ @@ -583,7 +562,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { stats.foreach(markDef) mapOverTree(last) case Inlined(call, bindings, InlineSplice(expansion @ Select(body, name))) => - assert(call.symbol.is(Macro)) + assert(call.symbol.is(Inline)) val tree2 = if (level == 0) { // Simplification of the call done in PostTyper for non-macros can also be performed now @@ -600,32 +579,8 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { else tree2 case _: Import => tree - case tree: DefDef if tree.symbol.is(Macro) && level == 0 => - tree.rhs match { - case InlineSplice(_) => - if (!tree.symbol.isStatic) - ctx.error("Inline macro method must be a static method.", tree.pos) - markDef(tree) - val reifier = nested(isQuote = true) - reifier.transform(tree) // Ignore output, we only need the its embedding - assert(reifier.embedded.size == 1) - val lambda = reifier.embedded.head - // replace macro code by lambda used to evaluate the macro expansion - cpy.DefDef(tree)(tpt = TypeTree(macroReturnType), rhs = lambda) - case _ => - ctx.error( - """Malformed inline macro. - | - |Expected the ~ to be at the top of the RHS: - | inline def foo(...): Int = ~impl(...) - |or - | inline def foo(...): Int = ~{ - | val x = 1 - | impl(... x ...) - | } - """.stripMargin, tree.rhs.pos) - EmptyTree - } + case tree: DefDef if tree.symbol.is(Inline) && level == 0 => + cpy.DefDef(tree)(rhs = defaultValue(tree.rhs.tpe.widenDealias)) // TODO remove macro definitions case _ => markDef(tree) checkLevel(mapOverTree(enteredSyms)) @@ -651,8 +606,8 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } private def isStage0Value(sym: Symbol)(implicit ctx: Context): Boolean = - (sym.is(Inline) && sym.owner.is(Macro) && !defn.isFunctionType(sym.info)) || - sym == defn.TastyTopLevelSplice_compilationTopLevelSplice // intrinsic value at stage 0 + (sym.is(Inline) && sym.owner.is(Inline) && !defn.isFunctionType(sym.info)) || + sym == defn.TastyTopLevelSplice_tastyContext // intrinsic value at stage 0 private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = { list.foldRight[Tree](ref(defn.NilModule)) { (x, acc) => @@ -675,27 +630,6 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } } - def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = { - /** Transforms the return type of - * inline def foo(...): X = ~(...) - * to - * inline def foo(...): Seq[Any] => Expr[Any] = (args: Seq[Any]) => ... - */ - def transform(tp: Type): Type = tp match { - case tp: MethodType => MethodType(tp.paramNames, tp.paramInfos, transform(tp.resType)) - case tp: PolyType => PolyType(tp.paramNames, tp.paramInfos, transform(tp.resType)) - case tp: ExprType => ExprType(transform(tp.resType)) - case _ => macroReturnType - } - transform(tp) - } - - override protected def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = - ctx.compilationUnit.containsQuotesOrSplices && sym.isTerm && sym.is(Macro) - - /** Returns the type of the compiled macro as a lambda: Seq[Any] => Object */ - private def macroReturnType(implicit ctx: Context): Type = - defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.ObjectType) } object ReifyQuotes { diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index e12090a62fcd..fb80140cf455 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -5,6 +5,7 @@ import java.io.{PrintWriter, StringWriter} import java.lang.reflect.Method import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.Trees._ import dotty.tools.dotc.core.Contexts._ import dotty.tools.dotc.core.Decorators._ import dotty.tools.dotc.core.Flags.Package @@ -15,6 +16,7 @@ import dotty.tools.dotc.core.quoted._ import dotty.tools.dotc.core.Types._ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.core.TypeErasure +import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.tastyreflect.TastyImpl import scala.util.control.NonFatal @@ -35,51 +37,14 @@ object Splicer { def splice(tree: Tree, call: Tree, bindings: List[Tree], pos: Position, classLoader: ClassLoader)(implicit ctx: Context): Tree = tree match { case Quoted(quotedTree) => quotedTree case _ => - val liftedArgs = getLiftedArgs(call, bindings) val interpreter = new Interpreter(pos, classLoader) - val interpreted = interpreter.interpretCallToSymbol[Seq[Any] => Object](call.symbol) - val tctx = new TastyImpl(ctx) evaluateMacro(pos) { // Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree - val evaluated = interpreted.map(lambda => lambda(tctx :: liftedArgs).asInstanceOf[scala.quoted.Expr[Nothing]]) - evaluated.fold(tree)(PickledQuotes.quotedExprToTree) + val interpreted = interpreter.interpretCall[scala.quoted.Expr[Any]](tree) + interpreted.fold(tree)(x => PickledQuotes.quotedExprToTree(x)) } } - /** Given the inline code and bindings, compute the lifted arguments that will be used to execute the macro - * - Type parameters are lifted to quoted.Types.TreeType - * - Inline parameters are listed as their value - * - Other parameters are lifted to quoted.Types.TreeExpr (may reference a binding) - */ - private def getLiftedArgs(call: Tree, bindings: List[Tree])(implicit ctx: Context): List[Any] = { - val bindMap = bindings.collect { - case vdef: ValDef => (vdef.rhs, ref(vdef.symbol).withPos(vdef.rhs.pos)) - }.toMap - def allArgs(call: Tree, acc: List[List[Tree]]): List[List[Tree]] = call match { - case call: Apply => allArgs(call.fun, call.args :: acc) - case call: TypeApply => allArgs(call.fun, call.args :: acc) - case _ => acc - } - def liftArgs(tpe: Type, args: List[List[Tree]]): List[Any] = tpe match { - case tp: MethodType => - val args1 = args.head.zip(tp.paramInfos).map { - case (arg: Literal, tp) if tp.hasAnnotation(defn.InlineParamAnnot) => arg.const.value - case (arg, tp) => - assert(!tp.hasAnnotation(defn.InlineParamAnnot)) - // Replace argument by its binding - val arg1 = bindMap.getOrElse(arg, arg) - new scala.quoted.Exprs.TastyTreeExpr(arg1) - } - args1 ::: liftArgs(tp.resType, args.tail) - case tp: PolyType => - val args1 = args.head.map(tp => new scala.quoted.Types.TreeType(tp)) - args1 ::: liftArgs(tp.resType, args.tail) - case _ => Nil - } - - liftArgs(call.symbol.info, allArgs(call, Nil)) - } - /* Evaluate the code in the macro and handle exceptions durring evaluation */ private def evaluateMacro(pos: Position)(code: => Tree)(implicit ctx: Context): Tree = { try code @@ -92,7 +57,7 @@ object Splicer { s"""Failed to evaluate inlined quote. | Caused by ${ex.getClass}: ${if (ex.getMessage == null) "" else ex.getMessage} | ${ex.getStackTrace.takeWhile(_.getClassName != "dotty.tools.dotc.transform.Splicer$").init.mkString("\n ")} - """.stripMargin + """.stripMargin ctx.error(msg, pos) EmptyTree } @@ -108,13 +73,9 @@ object Splicer { /** Returns the interpreted result of interpreting the code a call to the symbol with default arguments. * Return Some of the result or None if some error happen during the interpretation. */ - def interpretCallToSymbol[T](sym: Symbol)(implicit ct: ClassTag[T]): Option[T] = { + def interpretCall[T](tree: Tree)(implicit ct: ClassTag[T]): Option[T] = { try { - val (clazz, instance) = loadModule(sym.owner) - val paramClasses = paramsSig(sym) - val interpretedArgs = paramClasses.map(defaultValue) - val method = getMethod(clazz, sym.name, paramClasses) - stopIfRuntimeException(method.invoke(instance, interpretedArgs: _*)) match { + interpret(tree) match { case obj: T => Some(obj) case obj => // TODO upgrade to a full type tag check or something similar @@ -128,6 +89,29 @@ object Splicer { } } + private def interpret(tree: Tree): Object = tree match { + case Apply(TypeApply(fn, _), quoted :: Nil) if fn.symbol == defn.QuotedExpr_apply => + new scala.quoted.Exprs.TastyTreeExpr(quoted) + case TypeApply(fn, quoted :: Nil) if fn.symbol == defn.QuotedType_apply => + new scala.quoted.Types.TreeType(quoted) + + case _ if tree.symbol == defn.TastyTopLevelSplice_tastyContext => + new TastyImpl(ctx) + + case Apply(fn @ Ident(name), args) if fn.symbol.isStatic => + val (clazz, instance) = loadModule(fn.symbol.owner) + val method = getMethod(clazz, name, paramsSig(fn.symbol)) + val interpretedArgs = args.map(arg => interpret(arg)) + stopIfRuntimeException(method.invoke(instance, interpretedArgs: _*)) + case Apply(TypeApply(fn @ Ident(name), _), args) if fn.symbol.isStatic => + val (clazz, instance) = loadModule(fn.symbol.owner) + val method = getMethod(clazz, name, paramsSig(fn.symbol)) + val interpretedArgs = args.map(arg => interpret(arg)) + stopIfRuntimeException(method.invoke(instance, interpretedArgs: _*)) + + case Literal(Constant(value)) => value.asInstanceOf[Object] + } + private def loadModule(sym: Symbol): (Class[_], Object) = { if (sym.owner.is(Package)) { // is top level object @@ -223,19 +207,6 @@ object Splicer { } } - /** Get the default value for the given class */ - private def defaultValue(clazz: Class[_]): Object = { - if (clazz == classOf[Boolean]) false.asInstanceOf[Object] - else if (clazz == classOf[Byte]) 0.toByte.asInstanceOf[Object] - else if (clazz == classOf[Char]) 0.toChar.asInstanceOf[Object] - else if (clazz == classOf[Short]) 0.asInstanceOf[Object] - else if (clazz == classOf[Int]) 0.asInstanceOf[Object] - else if (clazz == classOf[Long]) 0L.asInstanceOf[Object] - else if (clazz == classOf[Float]) 0f.asInstanceOf[Object] - else if (clazz == classOf[Double]) 0d.asInstanceOf[Object] - else null - } - /** Exception that stops interpretation if some issue is found */ private class StopInterpretation(val msg: String, val pos: Position) extends Exception diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index d6ea4b9d1e29..a4fff0c93099 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -950,8 +950,6 @@ class RefChecks extends MiniPhase { thisPhase => override def transformDefDef(tree: DefDef)(implicit ctx: Context) = { checkDeprecatedOvers(tree) - if (tree.symbol.is(Macro)) - tree.symbol.resetFlag(Macro) tree } diff --git a/library/src/scala/quoted/Type.scala b/library/src/scala/quoted/Type.scala index c340b3207e03..9eeed775ad69 100644 --- a/library/src/scala/quoted/Type.scala +++ b/library/src/scala/quoted/Type.scala @@ -31,7 +31,7 @@ object Type { object Types { /** A Type backed by a pickled TASTY tree */ final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] { - override def toString(): String = s"Type()" + override def toString(): String = s"Type()" } /** An Type backed by a value */ @@ -41,6 +41,6 @@ object Types { /** An Type backed by a tree */ final class TreeType[Tree](val typeTree: Tree) extends quoted.Type[Any] { - override def toString: String = s"Type()" + override def toString: String = s"Type()" } } diff --git a/tests/neg/tasty-macro-assert/quoted_1.scala b/tests/neg/tasty-macro-assert/quoted_1.scala index 66076341fc2d..0c8e26466735 100644 --- a/tests/neg/tasty-macro-assert/quoted_1.scala +++ b/tests/neg/tasty-macro-assert/quoted_1.scala @@ -11,7 +11,7 @@ object Asserts { object Ops - inline def macroAssert(cond: Boolean): Unit = + inline def macroAssert(cond: => Boolean): Unit = ~impl('(cond))(TopLevelSplice.tastyContext) // FIXME infer TopLevelSplice.tastyContext within top level ~ def impl(cond: Expr[Boolean])(implicit tasty: Tasty): Expr[Unit] = { diff --git a/tests/run/tasty-linenumber/quoted_1.scala b/tests/pending/run/tasty-linenumber/quoted_1.scala similarity index 91% rename from tests/run/tasty-linenumber/quoted_1.scala rename to tests/pending/run/tasty-linenumber/quoted_1.scala index 5f73bb0f2910..01cb1e7efb5f 100644 --- a/tests/run/tasty-linenumber/quoted_1.scala +++ b/tests/pending/run/tasty-linenumber/quoted_1.scala @@ -1,7 +1,5 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ - import scala.tasty._ class LineNumber(val value: Int) { diff --git a/tests/run/tasty-linenumber/quoted_2.scala b/tests/pending/run/tasty-linenumber/quoted_2.scala similarity index 100% rename from tests/run/tasty-linenumber/quoted_2.scala rename to tests/pending/run/tasty-linenumber/quoted_2.scala diff --git a/tests/run/tasty-positioned/quoted_1.scala b/tests/pending/run/tasty-positioned/quoted_1.scala similarity index 95% rename from tests/run/tasty-positioned/quoted_1.scala rename to tests/pending/run/tasty-positioned/quoted_1.scala index 0e8af98b87af..b1536bc1fae2 100644 --- a/tests/run/tasty-positioned/quoted_1.scala +++ b/tests/pending/run/tasty-positioned/quoted_1.scala @@ -1,7 +1,5 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ - import scala.tasty._ case class Position(path: String, start: Int, end: Int, diff --git a/tests/run/tasty-positioned/quoted_2.scala b/tests/pending/run/tasty-positioned/quoted_2.scala similarity index 100% rename from tests/run/tasty-positioned/quoted_2.scala rename to tests/pending/run/tasty-positioned/quoted_2.scala diff --git a/tests/pos/i4735/Macro_1.scala b/tests/pos/i4735/Macro_1.scala new file mode 100644 index 000000000000..2a7aabc6db47 --- /dev/null +++ b/tests/pos/i4735/Macro_1.scala @@ -0,0 +1,34 @@ +import scala.annotation.tailrec +import scala.quoted._ + +object Macro { + + inline def unrolledForeach(inline unrollSize: Int, seq: Array[Int], f: => Int => Unit): Unit = // or f: Int => Unit + ~unrolledForeachImpl(unrollSize, '(seq), '(f)) + + private def unrolledForeachImpl(unrollSize: Int, seq: Expr[Array[Int]], f: Expr[Int => Unit]): Expr[Unit] = '{ + val size = (~seq).length + assert(size % (~unrollSize.toExpr) == 0) // for simplicity of the implementation + var i = 0 + while (i < size) { + println(" start loop") + ~{ + for (j <- new UnrolledRange(0, unrollSize)) '{ + val element = (~seq)(i + ~j.toExpr) + ~f('(element)) // or `(~f)(element)` if `f` should not be inlined + } + } + i += ~unrollSize.toExpr + } + + } + + private class UnrolledRange(start: Int, end: Int) { + def foreach(f: Int => Expr[Unit]): Expr[Unit] = { + @tailrec def loop(i: Int, acc: Expr[Unit]): Expr[Unit] = + if (i >= 0) loop(i - 1, '{ ~f(i); ~acc }) + else acc + loop(end - 1, '()) + } + } +} diff --git a/tests/pos/i4735/Test_2.scala b/tests/pos/i4735/Test_2.scala new file mode 100644 index 000000000000..6846c745316b --- /dev/null +++ b/tests/pos/i4735/Test_2.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Test { + def main(args: Array[String]): Unit = { + val arr = Array.tabulate[Int](21)(x => x) + for (x <- new Unrolled(arr)) { + System.out.println(2*x) + } + } + + +} +class Unrolled(arr: Array[Int]) extends AnyVal { + inline def foreach(f: => Int => Unit): Unit = Macro.unrolledForeach(3, arr, f) +} diff --git a/tests/pos/i4773.scala b/tests/pos/i4773.scala new file mode 100644 index 000000000000..0bc686264993 --- /dev/null +++ b/tests/pos/i4773.scala @@ -0,0 +1,6 @@ +import scala.quoted._ +object Foo { + inline def foo2(): Unit = ~foo2Impl() + def foo2Impl(): Expr[Unit] = '() + inline def foo(): Unit = foo2() +} diff --git a/tests/pos/quote-0.scala b/tests/pos/quote-0.scala index ae517ec575b2..37161b0bdf7c 100644 --- a/tests/pos/quote-0.scala +++ b/tests/pos/quote-0.scala @@ -2,7 +2,6 @@ import scala.quoted._ import dotty.tools.dotc.quoted.Toolbox._ - object Macros { inline def assert(expr: => Boolean): Unit = diff --git a/tests/run/tasty-custom-show/quoted_1.scala b/tests/run/tasty-custom-show/quoted_1.scala index 9da881da6666..59ee8806a5e5 100644 --- a/tests/run/tasty-custom-show/quoted_1.scala +++ b/tests/run/tasty-custom-show/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.TopLevelSplice import scala.tasty.Tasty diff --git a/tests/run/tasty-extractors-1/quoted_1.scala b/tests/run/tasty-extractors-1/quoted_1.scala index 92d24faccb33..3bbf1d01924e 100644 --- a/tests/run/tasty-extractors-1/quoted_1.scala +++ b/tests/run/tasty-extractors-1/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty._ diff --git a/tests/run/tasty-extractors-2.check b/tests/run/tasty-extractors-2.check index 2baf5ba3e382..44d527af4cbc 100644 --- a/tests/run/tasty-extractors-2.check +++ b/tests/run/tasty-extractors-2.check @@ -7,7 +7,7 @@ Type.AppliedType(Type.SymRef(ClassDef("Function1", _, _, _, _), Type.ThisType(Ty Term.Ident("???") Type.SymRef(DefDef("???", _, _, _, _), Type.SymRef(ValDef("Predef", _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))) -Term.Typed(Term.Literal(Constant.Int(1)), TypeTree.Singleton(Term.Literal(Constant.Int(1)))) +Term.Literal(Constant.Int(1)) Type.ConstantType(Constant.Int(1)) Term.Typed(Term.Literal(Constant.Int(1)), TypeTree.TypeIdent("Int")) @@ -22,18 +22,6 @@ Type.AndType(Type.SymRef(ClassDef("Foo", _, _, _, _), Type.ThisType(Type.SymRef( Term.Typed(Term.Literal(Constant.Int(1)), TypeTree.Or(TypeTree.TypeIdent("Int"), TypeTree.TypeIdent("String"))) Type.OrType(Type.SymRef(ClassDef("Int", _, _, _, _), Type.SymRef(PackageDef("scala", _), Type.ThisType(Type.SymRef(PackageDef("", _), NoPrefix())))), Type.SymRef(TypeDef("String", _), Type.SymRef(ValDef("Predef", _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))))) -Term.Block(List(Import(Term.Select(Term.Ident("scala"), "collection", None), List(SimpleSelector(Id("mutable"))))), Term.Literal(Constant.Int(1))) -Type.ConstantType(Constant.Int(1)) - -Term.Block(List(Import(Term.Select(Term.Ident("scala"), "collection", None), List(SimpleSelector(Id("mutable")), SimpleSelector(Id("immutable"))))), Term.Literal(Constant.Int(2))) -Type.ConstantType(Constant.Int(2)) - -Term.Block(List(Import(Term.Select(Term.Ident("scala"), "collection", None), List(RenameSelector(Id("mutable"), Id("mut"))))), Term.Literal(Constant.Int(3))) -Type.ConstantType(Constant.Int(3)) - -Term.Block(List(Import(Term.Select(Term.Ident("scala"), "collection", None), List(OmitSelector(Id("mutable"))))), Term.Literal(Constant.Int(4))) -Type.ConstantType(Constant.Int(4)) - Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, Nil)), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) @@ -61,6 +49,9 @@ Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef(" Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(DefDef("a", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(0))))))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) +Term.Block(List(ClassDef("Foo", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil), TypeTree.TermSelect(Term.Select(Term.Ident("_root_"), "scala", None), "Product")), None, List(DefDef("copy", Nil, List(Nil), TypeTree.Synthetic(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, Test$._$Foo))), Nil))), DefDef("hashCode", Nil, List(Nil), TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(394005536)))), DefDef("equals", Nil, List(List(ValDef("x$0", TypeTree.Synthetic(), None))), TypeTree.Synthetic(), Some(Term.Apply(Term.Select(Term.Apply(Term.Select(Term.This(Some(Id("Foo"))), "eq", Some(Signature(List(java.lang.Object), scala.Boolean))), List(Term.TypeApply(Term.Select(Term.Ident("x$0"), "asInstanceOf", Some(Signature(Nil, java.lang.Object))), List(TypeTree.Synthetic())))), "||", Some(Signature(List(scala.Boolean), scala.Boolean))), List(Term.Match(Term.Ident("x$0"), List(CaseDef(Pattern.Bind("x$0", Pattern.TypeTest(TypeTree.Synthetic())), None, Term.Literal(Constant.Boolean(true))), CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Literal(Constant.Boolean(false))))))))), DefDef("toString", Nil, List(Nil), TypeTree.Synthetic(), Some(Term.Apply(Term.Ident("_toString"), List(Term.This(Some(Id("Foo"))))))), DefDef("canEqual", Nil, List(List(ValDef("that", TypeTree.Synthetic(), None))), TypeTree.Synthetic(), Some(Term.TypeApply(Term.Select(Term.Ident("that"), "isInstanceOf", Some(Signature(Nil, scala.Boolean))), List(TypeTree.Synthetic())))), DefDef("productArity", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.Int(0)))), DefDef("productPrefix", Nil, Nil, TypeTree.Synthetic(), Some(Term.Literal(Constant.String("Foo")))), DefDef("productElement", Nil, List(List(ValDef("n", TypeTree.Synthetic(), None))), TypeTree.Synthetic(), Some(Term.Match(Term.Ident("n"), List(CaseDef(Pattern.Value(Term.Ident("_")), None, Term.Apply(Term.Ident("throw"), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(List(java.lang.String), java.lang.IndexOutOfBoundsException))), List(Term.Apply(Term.Select(Term.Ident("n"), "toString", Some(Signature(Nil, java.lang.String))), Nil)))))))))))), ValDef("Foo", TypeTree.TypeIdent("Foo$"), Some(Term.Apply(Term.Select(Term.New(TypeTree.TypeIdent("Foo$")), "", Some(Signature(Nil, Test$._$Foo$))), Nil))), ClassDef("Foo$", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil), TypeTree.Applied(TypeTree.Synthetic(), List(TypeTree.Synthetic()))), Some(ValDef("_", TypeTree.Singleton(Term.Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), TypeTree.Synthetic(), Some(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, Test$._$Foo))), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", TypeTree.Synthetic(), None))), TypeTree.Synthetic(), Some(Term.Literal(Constant.Boolean(true))))))), Term.Literal(Constant.Unit())) +Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) + Term.Block(List(ClassDef("Foo1", DefDef("", Nil, List(List(ValDef("a", TypeTree.TypeIdent("Int"), None))), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(ValDef("a", TypeTree.Synthetic(), None)))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) @@ -79,6 +70,9 @@ Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef(" Term.Block(List(ClassDef("Foo6", DefDef("", Nil, List(List(ValDef("a", TypeTree.TypeIdent("Int"), None)), List(ValDef("b", TypeTree.Singleton(Term.Ident("a")), None))), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(ValDef("a", TypeTree.Synthetic(), None), ValDef("b", TypeTree.Synthetic(), None)))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) +Term.Block(List(ClassDef("Foo7", DefDef("", Nil, List(List(ValDef("a", TypeTree.TypeIdent("Int"), None))), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(ValDef("a", TypeTree.Synthetic(), None), DefDef("", Nil, List(Nil), TypeTree.Synthetic(), Some(Term.Block(List(Term.Apply(Term.Select(Term.This(Some(Id("Foo7"))), "", Some(Signature(List(scala.Int), Test$._$Foo7))), List(Term.Literal(Constant.Int(6))))), Term.Literal(Constant.Unit()))))))), Term.Literal(Constant.Unit())) +Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) + Term.Block(List(ClassDef("Foo8", DefDef("", Nil, List(Nil), TypeTree.Synthetic(), None), List(Term.Apply(Term.Select(Term.New(TypeTree.Synthetic()), "", Some(Signature(Nil, java.lang.Object))), Nil)), None, List(Term.Apply(Term.Ident("println"), List(Term.Literal(Constant.Int(0))))))), Term.Literal(Constant.Unit())) Type.SymRef(ClassDef("Unit", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix()))) diff --git a/tests/run/tasty-extractors-2/quoted_1.scala b/tests/run/tasty-extractors-2/quoted_1.scala index ba196f206048..49d6c5493f40 100644 --- a/tests/run/tasty-extractors-2/quoted_1.scala +++ b/tests/run/tasty-extractors-2/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty._ diff --git a/tests/run/tasty-extractors-2/quoted_2.scala b/tests/run/tasty-extractors-2/quoted_2.scala index d55a9daa7000..f2e9908649b9 100644 --- a/tests/run/tasty-extractors-2/quoted_2.scala +++ b/tests/run/tasty-extractors-2/quoted_2.scala @@ -11,10 +11,6 @@ object Test { printTree(Nil: List[Int]) printTree(new Baz: Foo & Bar) printTree(1: Int | String) - printTree { import scala.collection.mutable; 1 } - printTree { import scala.collection.{mutable, immutable}; 2 } - printTree { import scala.collection.{mutable => mut}; 3 } - printTree { import scala.collection.{mutable => _}; 4 } printTree { class Foo } printTree { object Foo } printTree { type Foo } @@ -24,14 +20,14 @@ object Test { printTree { class Foo { final def a = 0 } } printTree { class Foo { private[Foo] def a = 0 } } printTree { class Foo { protected[Foo] def a = 0 } } - // printTree { case class Foo() } // FIXME: issue #4396 + printTree { case class Foo() } printTree { class Foo1(a: Int) } printTree { class Foo2(val b: Int) } printTree { class Foo3(a: Int = 5) } printTree { class Foo4(a: Int)(b: Int) } printTree { class Foo5(a: Int)(b: Int = a) } printTree { class Foo6(a: Int)(b: a.type) } - // printTree { class Foo7(a: Int) { def this() = this(6) } } + printTree { class Foo7(a: Int) { def this() = this(6) } } printTree { class Foo8 { println(0) } } printTree { class Foo10 { val a = 9 } } printTree { class Foo11 { var a = 10 } } diff --git a/tests/run/tasty-extractors-3/quoted_1.scala b/tests/run/tasty-extractors-3/quoted_1.scala index 26094c7a78c0..e49d7b603158 100644 --- a/tests/run/tasty-extractors-3/quoted_1.scala +++ b/tests/run/tasty-extractors-3/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty.TopLevelSplice import scala.tasty.Tasty diff --git a/tests/run/tasty-extractors-constants-1/quoted_1.scala b/tests/run/tasty-extractors-constants-1/quoted_1.scala index 803f39332d54..e26eee497303 100644 --- a/tests/run/tasty-extractors-constants-1/quoted_1.scala +++ b/tests/run/tasty-extractors-constants-1/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty._ import scala.tasty.util._ diff --git a/tests/run/tasty-extractors-owners/quoted_1.scala b/tests/run/tasty-extractors-owners/quoted_1.scala index 23fc9bf21e4c..5afeb121c448 100644 --- a/tests/run/tasty-extractors-owners/quoted_1.scala +++ b/tests/run/tasty-extractors-owners/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty._ import scala.tasty.util.TreeTraverser diff --git a/tests/run/tasty-extractors-types.check b/tests/run/tasty-extractors-types.check index 6563bf5bfc42..1eb1d3cef256 100644 --- a/tests/run/tasty-extractors-types.check +++ b/tests/run/tasty-extractors-types.check @@ -1,12 +1,12 @@ -TypeTree.TypeIdent("Int") +TypeTree.Synthetic() Type.SymRef(ClassDef("Int", _, _, _, _), Type.SymRef(PackageDef("scala", _), Type.ThisType(Type.SymRef(PackageDef("", _), NoPrefix())))) -TypeTree.Applied(TypeTree.TypeIdent("List"), List(TypeTree.TypeIdent("String"))) +TypeTree.Synthetic() Type.AppliedType(Type.SymRef(ClassDef("List", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("immutable", _), NoPrefix()))), List(Type.SymRef(TypeDef("String", _), Type.SymRef(ValDef("Predef", _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))))) -TypeTree.Applied(TypeTree.TypeIdent("Map"), List(TypeTree.TypeIdent("String"), TypeTree.TypeIdent("Int"))) +TypeTree.Synthetic() Type.AppliedType(Type.SymRef(ClassDef("Map", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("immutable", _), NoPrefix()))), List(Type.SymRef(TypeDef("String", _), Type.SymRef(ValDef("Predef", _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))), Type.SymRef(ClassDef("Int", _, _, _, _), Type.SymRef(PackageDef("scala", _), Type.ThisType(Type.SymRef(PackageDef("", _), NoPrefix())))))) -TypeTree.Applied(TypeTree.TypeIdent("Map"), List(TypeTree.TypeIdent("String"), TypeTree.TypeIdent("I"))) +TypeTree.Synthetic() Type.AppliedType(Type.SymRef(ClassDef("Map", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("immutable", _), NoPrefix()))), List(Type.SymRef(TypeDef("String", _), Type.SymRef(ValDef("Predef", _, _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))), Type.SymRef(TypeDef("I", _), NoPrefix()))) diff --git a/tests/run/tasty-extractors-types/quoted_1.scala b/tests/run/tasty-extractors-types/quoted_1.scala index f9af3e59be8e..3d8f4cfe553e 100644 --- a/tests/run/tasty-extractors-types/quoted_1.scala +++ b/tests/run/tasty-extractors-types/quoted_1.scala @@ -1,5 +1,4 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ import scala.tasty._ import scala.tasty.util.TreeTraverser diff --git a/tests/run/tasty-location/quoted_1.scala b/tests/run/tasty-location/quoted_1.scala index 4c61b34e1983..96bdc2439944 100644 --- a/tests/run/tasty-location/quoted_1.scala +++ b/tests/run/tasty-location/quoted_1.scala @@ -1,7 +1,5 @@ import scala.quoted._ -import dotty.tools.dotc.quoted.Toolbox._ - import scala.tasty._ case class Location(owners: List[String]) diff --git a/tests/run/tasty-macro-assert/quoted_1.scala b/tests/run/tasty-macro-assert/quoted_1.scala index 36a83c0106f4..2bb46a820d5f 100644 --- a/tests/run/tasty-macro-assert/quoted_1.scala +++ b/tests/run/tasty-macro-assert/quoted_1.scala @@ -11,7 +11,7 @@ object Asserts { object Ops - inline def macroAssert(cond: Boolean): Unit = + inline def macroAssert(cond: => Boolean): Unit = ~impl('(cond))(TopLevelSplice.tastyContext) // FIXME infer TopLevelSplice.tastyContext within top level ~ def impl(cond: Expr[Boolean])(implicit tasty: Tasty): Expr[Unit] = {