From 2b88a277b9aee80c8e51854d3959a5711be1f587 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 29 Mar 2022 17:16:53 +0200 Subject: [PATCH 1/4] Improve match error on reflect trees Print the tree extractors of the reflection API instead of the underlying case class toString. --- library/src/scala/quoted/Quotes.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index c1ceb98ea5d3..623708d577e7 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -4621,6 +4621,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => case Bind(_, body) => foldTree(x, body)(owner) case Unapply(fun, implicits, patterns) => foldTrees(foldTrees(foldTree(x, fun)(owner), implicits)(owner), patterns)(owner) case Alternatives(patterns) => foldTrees(x, patterns)(owner) + case _ => throw MatchError(tree.show(using Printer.TreeStructure)) } } end TreeAccumulator @@ -4685,6 +4686,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => Alternatives.copy(pattern)(transformTrees(pattern.patterns)(owner)) case TypedOrTest(inner, tpt) => TypedOrTest.copy(tree)(transformTree(inner)(owner), transformTypeTree(tpt)(owner)) + case _ => + throw MatchError(tree.show(using Printer.TreeStructure)) } } @@ -4713,6 +4716,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => Import.copy(tree)(transformTerm(tree.expr)(owner), tree.selectors) case tree: Export => tree + case _ => + throw MatchError(tree.show(using Printer.TreeStructure)) } } @@ -4758,6 +4763,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => Repeated.copy(tree)(transformTerms(elems)(owner), transformTypeTree(elemtpt)(owner)) case Inlined(call, bindings, expansion) => Inlined.copy(tree)(call, transformSubTrees(bindings)(owner), transformTerm(expansion)(owner)) + case _ => + throw MatchError(tree.show(using Printer.TreeStructure)) } } @@ -4786,6 +4793,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => TypeBind.copy(tree)(tree.name, tree.body) case tree: TypeBlock => TypeBlock.copy(tree)(tree.aliases, tree.tpt) + case _ => + throw MatchError(tree.show(using Printer.TreeStructure)) } def transformCaseDef(tree: CaseDef)(owner: Symbol): CaseDef = { From 30de3649a6a3f53ee6522c07e0c04baa22558adb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 29 Mar 2022 17:23:28 +0200 Subject: [PATCH 2/4] Handle SummonFrom in reflect TreeAccumulator Fixes #14789 --- library/src/scala/quoted/Quotes.scala | 1 + .../tasty-inspector/i14789.scala | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/run-custom-args/tasty-inspector/i14789.scala diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 623708d577e7..7b3193d55369 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -4621,6 +4621,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => case Bind(_, body) => foldTree(x, body)(owner) case Unapply(fun, implicits, patterns) => foldTrees(foldTrees(foldTree(x, fun)(owner), implicits)(owner), patterns)(owner) case Alternatives(patterns) => foldTrees(x, patterns)(owner) + case SummonFrom(cases) => foldTrees(x, cases)(owner) case _ => throw MatchError(tree.show(using Printer.TreeStructure)) } } diff --git a/tests/run-custom-args/tasty-inspector/i14789.scala b/tests/run-custom-args/tasty-inspector/i14789.scala new file mode 100644 index 000000000000..a78f19750346 --- /dev/null +++ b/tests/run-custom-args/tasty-inspector/i14789.scala @@ -0,0 +1,43 @@ +import scala.quoted.* +import scala.tasty.inspector.* + +@main def Test = { + // Artefact of the current test infrastructure + // TODO improve infrastructure to avoid needing this code on each test + val classpath = dotty.tools.dotc.util.ClasspathFromClassloader(this.getClass.getClassLoader).split(java.io.File.pathSeparator).find(_.contains("runWithCompiler")).get + val allTastyFiles = dotty.tools.io.Path(classpath).walkFilter(_.extension == "tasty").map(_.toString).toList + val tastyFiles = allTastyFiles.filter(_.contains("App")) + + // in dotty-example-project + val inspector = new Inspector { + def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = { + import quotes.reflect.* + val traverser = new TreeTraverser { + override def traverseTree(tree: Tree)(owner: Symbol): Unit = { + try { + super.traverseTree(tree)(owner) + } catch { + case e => + report.error(s"unexpected error ${e}", tree.pos) + throw e + } + } + } + tastys.foreach{ tasty => + traverser.traverseTree(tasty.ast)(tasty.ast.symbol) + } + } + } + TastyInspector.inspectTastyFiles(tastyFiles)(inspector) +} + +object App { + import scala.compiletime.* + + transparent inline def summonFirst0[T]: Any = + inline erasedValue[T] match + case _: (a *: b) => summonFrom { + case instance: `a` => instance + case _ => summonFirst0[b] + } +} From 1e6d50dcc18d134ab0e2a3f1fa210170669cf3ac Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 29 Mar 2022 17:49:32 +0200 Subject: [PATCH 3/4] Handle SummonFrom in reflect TreeMap * Add SummonFrom case * Fix bug with PackageClause case * Complete ClassDef case --- library/src/scala/quoted/Quotes.scala | 9 +++++++-- tests/run-custom-args/tasty-inspector/i14789.scala | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 7b3193d55369..293ffb91fa76 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -4664,7 +4664,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => def transformTree(tree: Tree)(owner: Symbol): Tree = { tree match { case tree: PackageClause => - PackageClause.copy(tree)(transformTerm(tree.pid).asInstanceOf[Ref], transformTrees(tree.stats)(tree.symbol)) + PackageClause.copy(tree)(transformTerm(tree.pid)(owner).asInstanceOf[Ref], transformTrees(tree.stats)(tree.symbol)) case tree: Import => Import.copy(tree)(transformTerm(tree.expr)(owner), tree.selectors) case tree: Export => @@ -4712,7 +4712,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => val owner = tree.symbol TypeDef.copy(tree)(tree.name, transformTree(tree.rhs)(owner)) case tree: ClassDef => - ClassDef.copy(tree)(tree.name, tree.constructor, tree.parents, tree.self, tree.body) + val constructor @ DefDef(_, _, _, _) = transformStatement(tree.constructor)(tree.symbol) + val parents = tree.parents.map(transformTree(_)(tree.symbol)) + val body = tree.body.map(transformStatement(_)(tree.symbol)) + ClassDef.copy(tree)(tree.name, constructor, parents, tree.self, body) case tree: Import => Import.copy(tree)(transformTerm(tree.expr)(owner), tree.selectors) case tree: Export => @@ -4764,6 +4767,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => Repeated.copy(tree)(transformTerms(elems)(owner), transformTypeTree(elemtpt)(owner)) case Inlined(call, bindings, expansion) => Inlined.copy(tree)(call, transformSubTrees(bindings)(owner), transformTerm(expansion)(owner)) + case SummonFrom(cases) => + SummonFrom.copy(tree)(transformCaseDefs(cases)(owner)) case _ => throw MatchError(tree.show(using Printer.TreeStructure)) } diff --git a/tests/run-custom-args/tasty-inspector/i14789.scala b/tests/run-custom-args/tasty-inspector/i14789.scala index a78f19750346..72e773a8df16 100644 --- a/tests/run-custom-args/tasty-inspector/i14789.scala +++ b/tests/run-custom-args/tasty-inspector/i14789.scala @@ -23,8 +23,10 @@ import scala.tasty.inspector.* } } } + val mapper = new TreeMap { } tastys.foreach{ tasty => traverser.traverseTree(tasty.ast)(tasty.ast.symbol) + mapper.transformTree(tasty.ast)(tasty.ast.symbol) } } } From 1d58335cb48b12bd64e8a5e7bcf66b774fa3e284 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 30 Mar 2022 13:20:28 +0200 Subject: [PATCH 4/4] Transform self in ClassDef --- library/src/scala/quoted/Quotes.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 293ffb91fa76..86b007446f91 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -4714,8 +4714,12 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => case tree: ClassDef => val constructor @ DefDef(_, _, _, _) = transformStatement(tree.constructor)(tree.symbol) val parents = tree.parents.map(transformTree(_)(tree.symbol)) + val self = tree.self.map { slf => + transformStatement(slf)(tree.symbol) match + case self: ValDef => self + } val body = tree.body.map(transformStatement(_)(tree.symbol)) - ClassDef.copy(tree)(tree.name, constructor, parents, tree.self, body) + ClassDef.copy(tree)(tree.name, constructor, parents, self, body) case tree: Import => Import.copy(tree)(transformTerm(tree.expr)(owner), tree.selectors) case tree: Export =>