From 4e1e0496eb8f6d82491797529549b7374308a5c2 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 20 Nov 2019 19:28:12 +0100 Subject: [PATCH 1/8] Add Expr.matches --- library/src/scala/quoted/Expr.scala | 11 +++++++++++ tests/run-staging/expr-matches.scala | 13 +++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/run-staging/expr-matches.scala diff --git a/library/src/scala/quoted/Expr.scala b/library/src/scala/quoted/Expr.scala index ed9a35c5bea1..8d37819b107f 100644 --- a/library/src/scala/quoted/Expr.scala +++ b/library/src/scala/quoted/Expr.scala @@ -19,6 +19,17 @@ package quoted { */ final def getValue[U >: T](given qctx: QuoteContext, valueOf: ValueOfExpr[U]): Option[U] = valueOf(this) + /** Pattern matches `this` against `that`. Effectively performing a deep equality check. + * It does the equivalent of + * ``` + * this match + * case '{...} => true // where the contens of the pattern are the contents of `that` + * case _ => false + * ``` + */ + final def matches(that: Expr[Any])(given qctx: QuoteContext): Boolean = + !scala.internal.quoted.Expr.unapply[Unit, Unit](this)(given that, false, qctx).isEmpty + } object Expr { diff --git a/tests/run-staging/expr-matches.scala b/tests/run-staging/expr-matches.scala new file mode 100644 index 000000000000..2f0255fbadfb --- /dev/null +++ b/tests/run-staging/expr-matches.scala @@ -0,0 +1,13 @@ +import scala.quoted._ +import scala.quoted.staging._ + + +object Test { + given Toolbox = Toolbox.make(getClass.getClassLoader) + def main(args: Array[String]): Unit = withQuoteContext { + assert('{1} matches '{1}) + assert('{println("foo")} matches '{println("foo")}) + assert('{println("foo")} matches '{println(${Expr("foo")})}) + assert('{println(Some("foo"))} matches '{println(${ val a = '{Some("foo")}; a})}) + } +} From 15782927a7136395da9f9a833d68e50f187891a3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 18 Nov 2019 10:33:17 +0100 Subject: [PATCH 2/8] Add quoted.util.ExprMap --- .../ReflectionCompilerInterface.scala | 7 + .../scala/quoted/util/ExprMap.scala | 158 ++++++++++++++++++ .../tasty/reflect/CompilerInterface.scala | 6 + .../src/scala/tasty/reflect/SymbolOps.scala | 10 ++ tests/run-macros/expr-map-1.check | 26 +++ tests/run-macros/expr-map-1/Macro_1.scala | 18 ++ tests/run-macros/expr-map-1/Test_2.scala | 122 ++++++++++++++ .../run-macros/flops-rewrite-2/Macro_1.scala | 36 +--- .../run-macros/flops-rewrite-3/Macro_1.scala | 36 +--- tests/run-macros/flops-rewrite/Macro_1.scala | 36 +--- 10 files changed, 362 insertions(+), 93 deletions(-) create mode 100644 library/src-bootstrapped/scala/quoted/util/ExprMap.scala create mode 100644 tests/run-macros/expr-map-1.check create mode 100644 tests/run-macros/expr-map-1/Macro_1.scala create mode 100644 tests/run-macros/expr-map-1/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala index f0ae6c92b86b..3a594cb62aa9 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala @@ -1713,6 +1713,13 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend def Symbol_noSymbol(given ctx: Context): Symbol = core.Symbols.NoSymbol + def Symbol_typeRef(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.typeRef + + def Symbol_termRef(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.termRef + + def Symbol_info(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.info + + // // FLAGS // diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala new file mode 100644 index 000000000000..64c7f8e69e82 --- /dev/null +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -0,0 +1,158 @@ +package scala.quoted.util + +import scala.quoted._ + +trait ExprMap { + + /** Map an expression `e` with a type `tpe` */ + def map[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] + + /** Map subexpressions an expression `e` with a type `tpe` */ + def mapChildren[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] = { + import qctx.tasty.{_, given} + class MapChildren() { + + def transformStatement(tree: Statement)(given ctx: Context): Statement = { + def localCtx(definition: Definition): Context = definition.symbol.localContext + tree match { + case tree: Term => + transformTerm(tree, defn.AnyType) + case tree: Definition => + transformDefinition(tree) + case tree: Import => + tree + } + } + + def transformDefinition(tree: Definition)(given ctx: Context): Definition = { + def localCtx(definition: Definition): Context = definition.symbol.localContext + tree match { + case tree: ValDef => + implicit val ctx = localCtx(tree) + val rhs1 = tree.rhs.map(x => transformTerm(x, tree.tpt.tpe)) + ValDef.copy(tree)(tree.name, tree.tpt, rhs1) + case tree: DefDef => + implicit val ctx = localCtx(tree) + DefDef.copy(tree)(tree.name, tree.typeParams, tree.paramss, tree.returnTpt, tree.rhs.map(x => transformTerm(x, tree.returnTpt.tpe))) + case tree: TypeDef => + tree + case tree: ClassDef => + ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.derived, tree.self, tree.body) + } + } + + def transformTermChildren(tree: Term, tpe: Type)(given ctx: Context): Term = tree match { + case Ident(name) => + tree + case Select(qualifier, name) => + Select.copy(tree)(transformTerm(qualifier, qualifier.tpe.widen), name) + case This(qual) => + tree + case Super(qual, mix) => + tree + case tree @ Apply(fun, args) => + val MethodType(_, tpes, _) = fun.tpe.widen + Apply.copy(tree)(transformTerm(fun, defn.AnyType), transformTerms(args, tpes)) + case TypeApply(fun, args) => + TypeApply.copy(tree)(transformTerm(fun, defn.AnyType), args) + case _: Literal => + tree + case New(tpt) => + New.copy(tree)(transformTypeTree(tpt)) + case Typed(expr, tpt) => + val tp = tpt.tpe match + // TODO improve code + case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), ""), List(tp0: Type)) => + type T + val a = tp0.seal.asInstanceOf[quoted.Type[T]] + '[Seq[$a]].unseal.tpe + case tp => tp + Typed.copy(tree)(transformTerm(expr, tp), transformTypeTree(tpt)) + case tree: NamedArg => + NamedArg.copy(tree)(tree.name, transformTerm(tree.value, tpe)) + case Assign(lhs, rhs) => + Assign.copy(tree)(lhs, transformTerm(rhs, lhs.tpe.widen)) + case Block(stats, expr) => + Block.copy(tree)(transformStats(stats), transformTerm(expr, tpe)) + case If(cond, thenp, elsep) => + If.copy(tree)( + transformTerm(cond, defn.BooleanType), + transformTerm(thenp, tpe), + transformTerm(elsep, tpe)) + case _: Closure => + tree + case Match(selector, cases) => + Match.copy(tree)(transformTerm(selector, selector.tpe), transformCaseDefs(cases, tpe)) + case Return(expr) => + // FIXME + // ctx.owner seems to be set to the wrong symbol + // Return.copy(tree)(transformTerm(expr, expr.tpe)) + tree + case While(cond, body) => + While.copy(tree)(transformTerm(cond, defn.BooleanType), transformTerm(body, defn.AnyType)) + case Try(block, cases, finalizer) => + Try.copy(tree)(transformTerm(block, tpe), transformCaseDefs(cases, defn.AnyType), finalizer.map(x => transformTerm(x, defn.AnyType))) + case Repeated(elems, elemtpt) => + Repeated.copy(tree)(transformTerms(elems, elemtpt.tpe), elemtpt) + case Inlined(call, bindings, expansion) => + Inlined.copy(tree)(call, transformDefinitions(bindings), transformTerm(expansion, tpe)/*()call.symbol.localContext)*/) + } + + def transformTerm(tree: Term, tpe: Type)(given ctx: Context): Term = + tree match { + case _: Closure => + tree + case _: Inlined | _: Select => + transformTermChildren(tree, tpe) + case _ => + tree.tpe.widen match { + case _: MethodType | _: PolyType => + transformTermChildren(tree, tpe) + case _ => + type X + val expr = tree.seal.asInstanceOf[Expr[X]] + val t = tpe.seal.asInstanceOf[quoted.Type[X]] + map(expr)(given qctx, t).unseal + } + } + + def transformTypeTree(tree: TypeTree)(given ctx: Context): TypeTree = tree + + def transformCaseDef(tree: CaseDef, tpe: Type)(given ctx: Context): CaseDef = + CaseDef.copy(tree)(tree.pattern, tree.guard.map(x => transformTerm(x, defn.BooleanType)), transformTerm(tree.rhs, tpe)) + + def transformTypeCaseDef(tree: TypeCaseDef)(given ctx: Context): TypeCaseDef = { + TypeCaseDef.copy(tree)(transformTypeTree(tree.pattern), transformTypeTree(tree.rhs)) + } + + def transformStats(trees: List[Statement])(given ctx: Context): List[Statement] = + trees mapConserve (transformStatement(_)) + + def transformDefinitions(trees: List[Definition])(given ctx: Context): List[Definition] = + trees mapConserve (transformDefinition(_)) + + def transformTerms(trees: List[Term], tpes: List[Type])(given ctx: Context): List[Term] = + var tpes2 = tpes // TODO use proper zipConserve + trees mapConserve { x => + val tpe :: tail = tpes2 + tpes2 = tail + transformTerm(x, tpe) + } + + def transformTerms(trees: List[Term], tpe: Type)(given ctx: Context): List[Term] = + trees.mapConserve(x => transformTerm(x, tpe)) + + def transformTypeTrees(trees: List[TypeTree])(given ctx: Context): List[TypeTree] = + trees mapConserve (transformTypeTree(_)) + + def transformCaseDefs(trees: List[CaseDef], tpe: Type)(given ctx: Context): List[CaseDef] = + trees mapConserve (x => transformCaseDef(x, tpe)) + + def transformTypeCaseDefs(trees: List[TypeCaseDef])(given ctx: Context): List[TypeCaseDef] = + trees mapConserve (transformTypeCaseDef(_)) + + } + new MapChildren().transformTermChildren(e.unseal, tpe.unseal.tpe).seal.cast[T] // Cast will only fail if this implementation has a bug + } + +} diff --git a/library/src/scala/tasty/reflect/CompilerInterface.scala b/library/src/scala/tasty/reflect/CompilerInterface.scala index 32754b1cf41a..8bb2258519da 100644 --- a/library/src/scala/tasty/reflect/CompilerInterface.scala +++ b/library/src/scala/tasty/reflect/CompilerInterface.scala @@ -1255,6 +1255,12 @@ trait CompilerInterface { def Symbol_noSymbol(given ctx: Context): Symbol + def Symbol_typeRef(symbol: Symbol)(given ctx: Context): TypeOrBounds + + def Symbol_termRef(symbol: Symbol)(given ctx: Context): TypeOrBounds + + def Symbol_info(symbol: Symbol)(given ctx: Context): TypeOrBounds + // // FLAGS // diff --git a/library/src/scala/tasty/reflect/SymbolOps.scala b/library/src/scala/tasty/reflect/SymbolOps.scala index cceaf785fe17..682f03741362 100644 --- a/library/src/scala/tasty/reflect/SymbolOps.scala +++ b/library/src/scala/tasty/reflect/SymbolOps.scala @@ -143,6 +143,16 @@ trait SymbolOps extends Core { selfSymbolOps: FlagsOps => /** The symbol of the companion module */ def companionModule(given ctx: Context): Symbol = internal.Symbol_companionModule(self) + + def typeRef(given ctx: Context): TypeOrBounds = + internal.Symbol_typeRef(self) + + def termRef(given ctx: Context): TypeOrBounds = + internal.Symbol_termRef(self) + + def info(given ctx: Context): TypeOrBounds = + internal.Symbol_info(self) + } } diff --git a/tests/run-macros/expr-map-1.check b/tests/run-macros/expr-map-1.check new file mode 100644 index 000000000000..edd7344f60f0 --- /dev/null +++ b/tests/run-macros/expr-map-1.check @@ -0,0 +1,26 @@ +oof +oofoof +ylppa +kcolb +kcolb +neht +esle +lav +vals +fed +defs +fed +rab +yrt +yllanif +hctac +elihw +wen +depyt +depyt +grAdeman +qual +adbmal +ravsgra +hctam +def diff --git a/tests/run-macros/expr-map-1/Macro_1.scala b/tests/run-macros/expr-map-1/Macro_1.scala new file mode 100644 index 000000000000..cd3f20726e3d --- /dev/null +++ b/tests/run-macros/expr-map-1/Macro_1.scala @@ -0,0 +1,18 @@ +import scala.quoted._ +import scala.quoted.matching._ + +inline def rewrite[T](x: => Any): Any = ${ stringRewriter('x) } + +private def stringRewriter(e: Expr[Any])(given QuoteContext): Expr[Any] = + StringRewriter.map(e) + +private object StringRewriter extends util.ExprMap { + + def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = e match + case Const(s: String) => + Expr(s.reverse) match + case '{ $x: T } => x + case _ => e // e had a singlton String type + case _ => mapChildren(e) + +} diff --git a/tests/run-macros/expr-map-1/Test_2.scala b/tests/run-macros/expr-map-1/Test_2.scala new file mode 100644 index 000000000000..9c8e93146569 --- /dev/null +++ b/tests/run-macros/expr-map-1/Test_2.scala @@ -0,0 +1,122 @@ +object Test { + + def main(args: Array[String]): Unit = { + println(rewrite("foo")) + println(rewrite("foo" + "foo")) + + rewrite { + println("apply") + } + + rewrite { + println("block") + println("block") + } + + val b: Boolean = true + rewrite { + if b then println("then") + else println("else") + } + + rewrite { + if !b then println("then") + else println("else") + } + + rewrite { + val s: String = "val" + println(s) + } + + rewrite { + val s: "vals" = "vals" + println(s) // prints "foo" not "oof" + } + + rewrite { + def s: String = "def" + println(s) + } + + rewrite { + def s: "defs" = "defs" + println(s) // prints "foo" not "oof" + } + + rewrite { + def s(x: String): String = x + println(s("def")) + } + + rewrite { + var s: String = "var" + s = "bar" + println(s) + } + + rewrite { + try println("try") + finally println("finally") + } + + rewrite { + try throw new Exception() + catch case x: Exception => println("catch") + } + + rewrite { + var x = true + while (x) { + println("while") + x = false + } + } + + rewrite { + val t = new Tuple1("new") + println(t._1) + } + + rewrite { + println("typed": String) + println("typed": Any) + } + + rewrite { + val f = new Foo(foo = "namedArg") + println(f.foo) + } + + rewrite { + println("qual".reverse) + } + + rewrite { + val f = () => "lambda" + println(f()) + } + + rewrite { + def f(args: String*): String = args.mkString + println(f("var", "args")) + } + + rewrite { + "match" match { + case "match" => println("match") + case x => println("x") + } + } + + // FIXME should print fed + rewrite { + def s: String = return "def" + println(s) + } + + } + +} + +class Foo(val foo: String) diff --git a/tests/run-macros/flops-rewrite-2/Macro_1.scala b/tests/run-macros/flops-rewrite-2/Macro_1.scala index 97ee354c8611..11e29d1fe7df 100644 --- a/tests/run-macros/flops-rewrite-2/Macro_1.scala +++ b/tests/run-macros/flops-rewrite-2/Macro_1.scala @@ -35,7 +35,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { fixPoint = true ) - val x2 = rewriter.rewrite(x) + val x2 = rewriter.map(x) '{ println(${Expr(x.show)}) @@ -63,39 +63,13 @@ private object Rewriter { new Rewriter(preTransform, postTransform, fixPoint) } -private class Rewriter(preTransform: List[Transformation[_]] = Nil, postTransform: List[Transformation[_]] = Nil, fixPoint: Boolean) { - def rewrite[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { +private class Rewriter(preTransform: List[Transformation[_]] = Nil, postTransform: List[Transformation[_]] = Nil, fixPoint: Boolean) extends util.ExprMap { + def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = preTransform.foldLeft(e)((ei, transform) => transform(ei)) - val e3 = rewriteChildren(e2) + val e3 = mapChildren(e2) val e4 = postTransform.foldLeft(e3)((ei, transform) => transform(ei)) - if fixPoint && e4 != e then rewrite(e4) + if fixPoint && !e4.matches(e) then map(e4) else e4 } - def rewriteChildren[T: Type](e: Expr[T])(given qctx: QuoteContext): Expr[T] = { - import qctx.tasty.{_, given} - class MapChildren extends TreeMap { - override def transformTerm(tree: Term)(given ctx: Context): Term = tree match { - case _: Closure => - tree - case _: Inlined | _: Select => - transformChildrenTerm(tree) - case _ => - tree.tpe.widen match { - case _: MethodType | _: PolyType => - transformChildrenTerm(tree) - case _ => - tree.seal match { - case '{ $x: $t } => rewrite(x).unseal - } - } - } - def transformChildrenTerm(tree: Term)(given ctx: Context): Term = - super.transformTerm(tree) - } - (new MapChildren).transformChildrenTerm(e.unseal).seal.cast[T] // Cast will only fail if this implementation has a bug - } - } - - diff --git a/tests/run-macros/flops-rewrite-3/Macro_1.scala b/tests/run-macros/flops-rewrite-3/Macro_1.scala index 55543e0a7c8a..61ebff34396e 100644 --- a/tests/run-macros/flops-rewrite-3/Macro_1.scala +++ b/tests/run-macros/flops-rewrite-3/Macro_1.scala @@ -33,7 +33,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { } ) - val x2 = rewriter.rewrite(x) + val x2 = rewriter.map(x) '{ println(${Expr(x.show)}) @@ -92,7 +92,7 @@ private object Rewriter { def apply(): Rewriter = new Rewriter(Nil, Nil, false) } -private class Rewriter private (preTransform: List[Transformation] = Nil, postTransform: List[Transformation] = Nil, fixPoint: Boolean) { +private class Rewriter private (preTransform: List[Transformation] = Nil, postTransform: List[Transformation] = Nil, fixPoint: Boolean) extends util.ExprMap { def withFixPoint: Rewriter = new Rewriter(preTransform, postTransform, fixPoint = true) @@ -101,37 +101,11 @@ private class Rewriter private (preTransform: List[Transformation] = Nil, postTr def withPost(transform: Transformation): Rewriter = new Rewriter(preTransform, transform :: postTransform, fixPoint) - def rewrite[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { + def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = preTransform.foldLeft(e)((ei, transform) => transform(ei)) - val e3 = rewriteChildren(e2) + val e3 = mapChildren(e2) val e4 = postTransform.foldLeft(e3)((ei, transform) => transform(ei)) - if fixPoint && e4 != e then rewrite(e4) else e4 - } - - def rewriteChildren[T: Type](e: Expr[T])(given qctx: QuoteContext): Expr[T] = { - import qctx.tasty.{_, given} - class MapChildren extends TreeMap { - override def transformTerm(tree: Term)(given ctx: Context): Term = tree match { - case _: Closure => - tree - case _: Inlined | _: Select => - transformChildrenTerm(tree) - case _ => - tree.tpe.widen match { - case _: MethodType | _: PolyType => - transformChildrenTerm(tree) - case _ => - tree.seal match { - case '{ $x: $t } => rewrite(x).unseal - } - } - } - def transformChildrenTerm(tree: Term)(given ctx: Context): Term = - super.transformTerm(tree) - } - (new MapChildren).transformChildrenTerm(e.unseal).seal.cast[T] // Cast will only fail if this implementation has a bug + if fixPoint && !e4.matches(e) then map(e4) else e4 } } - - diff --git a/tests/run-macros/flops-rewrite/Macro_1.scala b/tests/run-macros/flops-rewrite/Macro_1.scala index d78df3dc4cbf..7bc70965f5d7 100644 --- a/tests/run-macros/flops-rewrite/Macro_1.scala +++ b/tests/run-macros/flops-rewrite/Macro_1.scala @@ -13,7 +13,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { } ) - val x2 = rewriter.rewrite(x) + val x2 = rewriter.map(x) '{ println(${Expr(x.show)}) @@ -28,12 +28,12 @@ private object Rewriter { new Rewriter(preTransform, postTransform, fixPoint) } -private class Rewriter(preTransform: Expr[Any] => Expr[Any], postTransform: Expr[Any] => Expr[Any], fixPoint: Boolean) { - def rewrite[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { +private class Rewriter(preTransform: Expr[Any] => Expr[Any], postTransform: Expr[Any] => Expr[Any], fixPoint: Boolean) extends util.ExprMap { + def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = checkedTransform(e, preTransform) - val e3 = rewriteChildren(e2) + val e3 = mapChildren(e2) val e4 = checkedTransform(e3, postTransform) - if fixPoint && e4 != e then rewrite(e4) + if fixPoint && !e4.matches(e) then map(e4) else e4 } @@ -54,30 +54,4 @@ private class Rewriter(preTransform: Expr[Any] => Expr[Any], postTransform: Expr } } - def rewriteChildren[T: Type](e: Expr[T])(given qctx: QuoteContext): Expr[T] = { - import qctx.tasty.{_, given} - class MapChildren extends TreeMap { - override def transformTerm(tree: Term)(given ctx: Context): Term = tree match { - case _: Closure => - tree - case _: Inlined | _: Select => - transformChildrenTerm(tree) - case _ => - tree.tpe.widen match { - case _: MethodType | _: PolyType => - transformChildrenTerm(tree) - case _ => - tree.seal match { - case '{ $x: $t } => rewrite(x).unseal - } - } - } - def transformChildrenTerm(tree: Term)(given ctx: Context): Term = - super.transformTerm(tree) - } - (new MapChildren).transformChildrenTerm(e.unseal).seal.cast[T] // Cast will only fail if this implementation has a bug - } - } - - From a43f7be71e960e1be1b8c3fbc279c9dbc0d14db0 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 20 Nov 2019 20:38:55 +0100 Subject: [PATCH 3/8] Rename methods to `transform` --- library/src-bootstrapped/scala/quoted/util/ExprMap.scala | 6 +++--- tests/run-macros/expr-map-1/Macro_1.scala | 6 +++--- tests/run-macros/flops-rewrite-2/Macro_1.scala | 8 ++++---- tests/run-macros/flops-rewrite-3/Macro_1.scala | 8 ++++---- tests/run-macros/flops-rewrite/Macro_1.scala | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index 64c7f8e69e82..d4761c5dff6e 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -5,10 +5,10 @@ import scala.quoted._ trait ExprMap { /** Map an expression `e` with a type `tpe` */ - def map[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] + def transform[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] /** Map subexpressions an expression `e` with a type `tpe` */ - def mapChildren[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] = { + def transformChildren[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] = { import qctx.tasty.{_, given} class MapChildren() { @@ -112,7 +112,7 @@ trait ExprMap { type X val expr = tree.seal.asInstanceOf[Expr[X]] val t = tpe.seal.asInstanceOf[quoted.Type[X]] - map(expr)(given qctx, t).unseal + transform(expr)(given qctx, t).unseal } } diff --git a/tests/run-macros/expr-map-1/Macro_1.scala b/tests/run-macros/expr-map-1/Macro_1.scala index cd3f20726e3d..872c072a1b3d 100644 --- a/tests/run-macros/expr-map-1/Macro_1.scala +++ b/tests/run-macros/expr-map-1/Macro_1.scala @@ -4,15 +4,15 @@ import scala.quoted.matching._ inline def rewrite[T](x: => Any): Any = ${ stringRewriter('x) } private def stringRewriter(e: Expr[Any])(given QuoteContext): Expr[Any] = - StringRewriter.map(e) + StringRewriter.transform(e) private object StringRewriter extends util.ExprMap { - def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = e match + def transform[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = e match case Const(s: String) => Expr(s.reverse) match case '{ $x: T } => x case _ => e // e had a singlton String type - case _ => mapChildren(e) + case _ => transformChildren(e) } diff --git a/tests/run-macros/flops-rewrite-2/Macro_1.scala b/tests/run-macros/flops-rewrite-2/Macro_1.scala index 11e29d1fe7df..9b6124ad499a 100644 --- a/tests/run-macros/flops-rewrite-2/Macro_1.scala +++ b/tests/run-macros/flops-rewrite-2/Macro_1.scala @@ -35,7 +35,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { fixPoint = true ) - val x2 = rewriter.map(x) + val x2 = rewriter.transform(x) '{ println(${Expr(x.show)}) @@ -64,11 +64,11 @@ private object Rewriter { } private class Rewriter(preTransform: List[Transformation[_]] = Nil, postTransform: List[Transformation[_]] = Nil, fixPoint: Boolean) extends util.ExprMap { - def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { + def transform[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = preTransform.foldLeft(e)((ei, transform) => transform(ei)) - val e3 = mapChildren(e2) + val e3 = transformChildren(e2) val e4 = postTransform.foldLeft(e3)((ei, transform) => transform(ei)) - if fixPoint && !e4.matches(e) then map(e4) + if fixPoint && !e4.matches(e) then transform(e4) else e4 } diff --git a/tests/run-macros/flops-rewrite-3/Macro_1.scala b/tests/run-macros/flops-rewrite-3/Macro_1.scala index 61ebff34396e..241abe5ccb21 100644 --- a/tests/run-macros/flops-rewrite-3/Macro_1.scala +++ b/tests/run-macros/flops-rewrite-3/Macro_1.scala @@ -33,7 +33,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { } ) - val x2 = rewriter.map(x) + val x2 = rewriter.transform(x) '{ println(${Expr(x.show)}) @@ -101,11 +101,11 @@ private class Rewriter private (preTransform: List[Transformation] = Nil, postTr def withPost(transform: Transformation): Rewriter = new Rewriter(preTransform, transform :: postTransform, fixPoint) - def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { + def transform[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = preTransform.foldLeft(e)((ei, transform) => transform(ei)) - val e3 = mapChildren(e2) + val e3 = transformChildren(e2) val e4 = postTransform.foldLeft(e3)((ei, transform) => transform(ei)) - if fixPoint && !e4.matches(e) then map(e4) else e4 + if fixPoint && !e4.matches(e) then transform(e4) else e4 } } diff --git a/tests/run-macros/flops-rewrite/Macro_1.scala b/tests/run-macros/flops-rewrite/Macro_1.scala index 7bc70965f5d7..65c33bfd2033 100644 --- a/tests/run-macros/flops-rewrite/Macro_1.scala +++ b/tests/run-macros/flops-rewrite/Macro_1.scala @@ -13,7 +13,7 @@ private def rewriteMacro[T: Type](x: Expr[T])(given QuoteContext): Expr[T] = { } ) - val x2 = rewriter.map(x) + val x2 = rewriter.transform(x) '{ println(${Expr(x.show)}) @@ -29,11 +29,11 @@ private object Rewriter { } private class Rewriter(preTransform: Expr[Any] => Expr[Any], postTransform: Expr[Any] => Expr[Any], fixPoint: Boolean) extends util.ExprMap { - def map[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { + def transform[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = { val e2 = checkedTransform(e, preTransform) - val e3 = mapChildren(e2) + val e3 = transformChildren(e2) val e4 = checkedTransform(e3, postTransform) - if fixPoint && !e4.matches(e) then map(e4) + if fixPoint && !e4.matches(e) then transform(e4) else e4 } From 69f428559de83ee7379145e9eddc4604a732fdbc Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 20 Nov 2019 20:54:28 +0100 Subject: [PATCH 4/8] Fix Select matching as an Expr --- .../scala/quoted/util/ExprMap.scala | 2 +- tests/run-macros/expr-map-2.check | 3 +++ tests/run-macros/expr-map-2/Macro_1.scala | 19 +++++++++++++++++++ tests/run-macros/expr-map-2/Test_2.scala | 13 +++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/run-macros/expr-map-2.check create mode 100644 tests/run-macros/expr-map-2/Macro_1.scala create mode 100644 tests/run-macros/expr-map-2/Test_2.scala diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index d4761c5dff6e..0bfc59332607 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -102,7 +102,7 @@ trait ExprMap { tree match { case _: Closure => tree - case _: Inlined | _: Select => + case _: Inlined => transformTermChildren(tree, tpe) case _ => tree.tpe.widen match { diff --git a/tests/run-macros/expr-map-2.check b/tests/run-macros/expr-map-2.check new file mode 100644 index 000000000000..cbaaa5a883be --- /dev/null +++ b/tests/run-macros/expr-map-2.check @@ -0,0 +1,3 @@ +Foo(2) +4 +4 diff --git a/tests/run-macros/expr-map-2/Macro_1.scala b/tests/run-macros/expr-map-2/Macro_1.scala new file mode 100644 index 000000000000..ede05f1f9f87 --- /dev/null +++ b/tests/run-macros/expr-map-2/Macro_1.scala @@ -0,0 +1,19 @@ +import scala.quoted._ +import scala.quoted.matching._ + +inline def rewrite[T](x: => Any): Any = ${ stringRewriter('x) } + +private def stringRewriter(e: Expr[Any])(given QuoteContext): Expr[Any] = + StringRewriter.transform(e) + +private object StringRewriter extends util.ExprMap { + + def transform[T](e: Expr[T])(given QuoteContext, Type[T]): Expr[T] = e match + case '{ ($x: Foo).x } => + '{ new Foo(4).x } match case '{ $e: T } => e + case _ => + transformChildren(e) + +} + +case class Foo(x: Int) diff --git a/tests/run-macros/expr-map-2/Test_2.scala b/tests/run-macros/expr-map-2/Test_2.scala new file mode 100644 index 000000000000..7790ec34cf9f --- /dev/null +++ b/tests/run-macros/expr-map-2/Test_2.scala @@ -0,0 +1,13 @@ +object Test { + + def main(args: Array[String]): Unit = { + println(rewrite(new Foo(2))) + println(rewrite(new Foo(2).x)) + + rewrite { + val foo = new Foo(2) + println(foo.x) + } + + } +} From e126a8822ea2cdf8c48977843c6917ec445212ca Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 20 Nov 2019 21:03:52 +0100 Subject: [PATCH 5/8] Map subexpressions in classes --- library/src-bootstrapped/scala/quoted/util/ExprMap.scala | 3 ++- tests/run-macros/expr-map-1.check | 1 + tests/run-macros/expr-map-1/Test_2.scala | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index 0bfc59332607..424a7d368311 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -37,7 +37,8 @@ trait ExprMap { case tree: TypeDef => tree case tree: ClassDef => - ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.derived, tree.self, tree.body) + val newBody = transformStats(tree.body) + ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.derived, tree.self, newBody) } } diff --git a/tests/run-macros/expr-map-1.check b/tests/run-macros/expr-map-1.check index edd7344f60f0..0f16bb01c517 100644 --- a/tests/run-macros/expr-map-1.check +++ b/tests/run-macros/expr-map-1.check @@ -24,3 +24,4 @@ adbmal ravsgra hctam def +ooF wen diff --git a/tests/run-macros/expr-map-1/Test_2.scala b/tests/run-macros/expr-map-1/Test_2.scala index 9c8e93146569..70aada14219a 100644 --- a/tests/run-macros/expr-map-1/Test_2.scala +++ b/tests/run-macros/expr-map-1/Test_2.scala @@ -115,6 +115,14 @@ object Test { println(s) } + rewrite { + class Foo { + println("new Foo") + } + new Foo + } + + } } From 7c2b6e3b97c8826e7e04bb405b59a41285bf40df Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 21 Nov 2019 15:09:23 +0100 Subject: [PATCH 6/8] Remove widen on select qualifier --- library/src-bootstrapped/scala/quoted/util/ExprMap.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index 424a7d368311..a8df8e93de4e 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -46,7 +46,7 @@ trait ExprMap { case Ident(name) => tree case Select(qualifier, name) => - Select.copy(tree)(transformTerm(qualifier, qualifier.tpe.widen), name) + Select.copy(tree)(transformTerm(qualifier, qualifier.tpe), name) case This(qual) => tree case Super(qual, mix) => From 1aad5e7a3ba3275b2dad93bbe1c264d32c03e070 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 21 Nov 2019 15:22:02 +0100 Subject: [PATCH 7/8] Remove extra members of Symbol --- .../tastyreflect/ReflectionCompilerInterface.scala | 7 ------- .../src/scala/tasty/reflect/CompilerInterface.scala | 6 ------ library/src/scala/tasty/reflect/SymbolOps.scala | 10 ---------- 3 files changed, 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala index 3a594cb62aa9..f0ae6c92b86b 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala @@ -1713,13 +1713,6 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend def Symbol_noSymbol(given ctx: Context): Symbol = core.Symbols.NoSymbol - def Symbol_typeRef(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.typeRef - - def Symbol_termRef(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.termRef - - def Symbol_info(symbol: Symbol)(given ctx: Context): TypeOrBounds = symbol.info - - // // FLAGS // diff --git a/library/src/scala/tasty/reflect/CompilerInterface.scala b/library/src/scala/tasty/reflect/CompilerInterface.scala index 8bb2258519da..32754b1cf41a 100644 --- a/library/src/scala/tasty/reflect/CompilerInterface.scala +++ b/library/src/scala/tasty/reflect/CompilerInterface.scala @@ -1255,12 +1255,6 @@ trait CompilerInterface { def Symbol_noSymbol(given ctx: Context): Symbol - def Symbol_typeRef(symbol: Symbol)(given ctx: Context): TypeOrBounds - - def Symbol_termRef(symbol: Symbol)(given ctx: Context): TypeOrBounds - - def Symbol_info(symbol: Symbol)(given ctx: Context): TypeOrBounds - // // FLAGS // diff --git a/library/src/scala/tasty/reflect/SymbolOps.scala b/library/src/scala/tasty/reflect/SymbolOps.scala index 682f03741362..cceaf785fe17 100644 --- a/library/src/scala/tasty/reflect/SymbolOps.scala +++ b/library/src/scala/tasty/reflect/SymbolOps.scala @@ -143,16 +143,6 @@ trait SymbolOps extends Core { selfSymbolOps: FlagsOps => /** The symbol of the companion module */ def companionModule(given ctx: Context): Symbol = internal.Symbol_companionModule(self) - - def typeRef(given ctx: Context): TypeOrBounds = - internal.Symbol_typeRef(self) - - def termRef(given ctx: Context): TypeOrBounds = - internal.Symbol_termRef(self) - - def info(given ctx: Context): TypeOrBounds = - internal.Symbol_info(self) - } } From 4eb132ab2940318066faa331f6c7c0b6815cfb75 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 22 Nov 2019 07:09:55 +0100 Subject: [PATCH 8/8] Make class final --- library/src-bootstrapped/scala/quoted/util/ExprMap.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index a8df8e93de4e..bbd37f11ea5f 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -10,7 +10,7 @@ trait ExprMap { /** Map subexpressions an expression `e` with a type `tpe` */ def transformChildren[T](e: Expr[T])(given qctx: QuoteContext, tpe: Type[T]): Expr[T] = { import qctx.tasty.{_, given} - class MapChildren() { + final class MapChildren() { def transformStatement(tree: Statement)(given ctx: Context): Statement = { def localCtx(definition: Definition): Context = definition.symbol.localContext