Skip to content

Commit e488e10

Browse files
committed
Add reflect Symbol.newModule
1 parent 4167e54 commit e488e10

File tree

12 files changed

+156
-13
lines changed

12 files changed

+156
-13
lines changed

compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class MacroAnnotations(thisPhase: DenotTransformer):
127127
report.error(i"macro annotation $annot added $sym with an inconsistent owner. Expected it to be owned by ${annotated.owner} but was owned by ${sym.owner}.", annot.tree)
128128
else if annotated.isClass && annotated.owner.is(Package) /*&& !sym.isClass*/ then
129129
report.error(i"macro annotation can not add top-level ${sym.showKind}. $annot tried to add $sym.", annot.tree)
130-
else
130+
else if !sym.is(Module) then // To avoid entering it twice
131131
sym.enteredAfter(thisPhase)
132132

133133
object MacroAnnotations:

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

+21-5
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ import dotty.tools.dotc.ast.tpd
88
import dotty.tools.dotc.ast.untpd
99
import dotty.tools.dotc.core.Annotations
1010
import dotty.tools.dotc.core.Contexts._
11-
import dotty.tools.dotc.core.Types
11+
import dotty.tools.dotc.core.Decorators._
1212
import dotty.tools.dotc.core.Flags._
1313
import dotty.tools.dotc.core.NameKinds
14+
import dotty.tools.dotc.core.NameOps._
1415
import dotty.tools.dotc.core.StdNames._
15-
import dotty.tools.dotc.quoted.reflect._
16-
import dotty.tools.dotc.core.Decorators._
16+
import dotty.tools.dotc.core.Types
1717
import dotty.tools.dotc.NoCompilationUnit
18-
19-
import dotty.tools.dotc.quoted.{MacroExpansion, PickledQuotes}
18+
import dotty.tools.dotc.quoted.MacroExpansion
19+
import dotty.tools.dotc.quoted.PickledQuotes
20+
import dotty.tools.dotc.quoted.reflect._
2021

2122
import scala.quoted.runtime.{QuoteUnpickler, QuoteMatching}
2223
import scala.quoted.runtime.impl.printers._
@@ -2481,6 +2482,21 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
24812482
for sym <- decls(cls) do cls.enter(sym)
24822483
cls
24832484

2485+
def newModule(owner: Symbol, name: String, modFlags: Flags, clsFlags: Flags, parents: List[TypeRepr], decls: Symbol => List[Symbol], privateWithin: Symbol): Symbol =
2486+
assert(parents.nonEmpty && !parents.head.typeSymbol.is(dotc.core.Flags.Trait), "First parent must be a class")
2487+
val mod = dotc.core.Symbols.newCompleteModuleSymbol(
2488+
owner,
2489+
name.toTermName,
2490+
modFlags | Flags.Final | Flags.Lazy | Flags.Module,
2491+
clsFlags | Flags.Final | Flags.Module,
2492+
parents.asInstanceOf, // FIXME
2493+
dotc.core.Scopes.newScope,
2494+
privateWithin)
2495+
val cls = mod.moduleClass.asClass
2496+
cls.enter(dotc.core.Symbols.newConstructor(cls, dotc.core.Flags.Synthetic, Nil, Nil))
2497+
for sym <- decls(cls) do cls.enter(sym)
2498+
mod
2499+
24842500
def newMethod(owner: Symbol, name: String, tpe: TypeRepr): Symbol =
24852501
newMethod(owner, name, tpe, Flags.EmptyFlags, noSymbol)
24862502
def newMethod(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =

library/src/scala/quoted/Quotes.scala

+3
Original file line numberDiff line numberDiff line change
@@ -3641,6 +3641,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36413641
// TODO: add flags and privateWithin
36423642
@experimental def newClass(parent: Symbol, name: String, parents: List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr]): Symbol
36433643

3644+
// TODO docs
3645+
@experimental def newModule(owner: Symbol, name: String, modFlags: Flags, clsFlags: Flags, parents: List[TypeRepr], decls: Symbol => List[Symbol], privateWithin: Symbol): Symbol
3646+
36443647
/** Generates a new method symbol with the given parent, name and type.
36453648
*
36463649
* To define a member method of a class, use the `newMethod` within the `decls` function of `newClass`.

tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ val experimentalDefinitionInLibrary = Set(
7474
// Need experimental annotation macros to check that design works.
7575
"scala.quoted.Quotes.reflectModule.ClassDefModule.apply",
7676
"scala.quoted.Quotes.reflectModule.SymbolModule.newClass",
77+
"scala.quoted.Quotes.reflectModule.SymbolModule.newModule",
7778
"scala.quoted.Quotes.reflectModule.SymbolModule.freshName",
7879
"scala.quoted.Quotes.reflectModule.SymbolMethods.info",
7980

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
macro generated main
2+
executed in: Test_2$package$Bar$macro$1$
3+
macro generated main
4+
executed in: Test_2$package$Bar$macro$2$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import scala.annotation.{experimental, MacroAnnotation}
2+
import scala.quoted._
3+
import scala.collection.mutable
4+
5+
@experimental
6+
class addClass extends MacroAnnotation:
7+
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
8+
import quotes.reflect._
9+
tree match
10+
case DefDef(name, List(TermParamClause(Nil)), tpt, Some(rhs)) =>
11+
val parents = List(TypeTree.of[Object])
12+
def decls(cls: Symbol): List[Symbol] =
13+
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
14+
15+
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
16+
val cls = mod.moduleClass
17+
18+
val runSym = cls.declaredMethod("run").head
19+
20+
val runDef = DefDef(runSym, _ => Some(rhs))
21+
22+
val clsDef = ClassDef(cls, parents, body = List(runDef))
23+
24+
val newCls = Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil)
25+
val modVal = ValDef(mod, Some(newCls))
26+
27+
val newDef = DefDef.copy(tree)(name, List(TermParamClause(Nil)), tpt, Some(Apply(Select(Ref(mod), runSym), Nil)))
28+
List(modVal, clsDef, newDef)
29+
case _ =>
30+
report.error("Annotation only supports `def` with one argument")
31+
List(tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@addClass def foo(): Unit =
2+
println("macro generated main")
3+
println("executed in: " + (new Throwable().getStackTrace().head.getClassName))
4+
//> object Baz$macro$1 {
5+
//> def run() =
6+
//> println("macro generated main")
7+
//> println("executed in: " + getClass.getName)
8+
//> }
9+
//> def foo(): Unit =
10+
//> Baz$macro$1.run
11+
12+
@addClass def bar(): Unit =
13+
println("macro generated main")
14+
println("executed in: " + (new Throwable().getStackTrace().head.getClassName))
15+
//> object Baz$macro$2 {
16+
//> def run() =
17+
//> println("macro generated main")
18+
//> println("executed in: " + getClass.getName)
19+
//> }
20+
//> def foo(): Unit =
21+
//> Baz$macro$2.run
22+
23+
object Bar:
24+
def run() = ()
25+
26+
@main def Test(): Unit =
27+
foo()
28+
bar()
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
macro generated main
2-
executed in: Test_2$package$Baz$2
2+
executed in: Test_2$package$Baz$2$
33
macro generated main
4-
executed in: Test_2$package$Baz$4
4+
executed in: Test_2$package$Baz$4$

tests/run-macros/annot-add-local-object/Macro_1.scala

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ class addClass extends MacroAnnotation:
1010
case DefDef(name, List(TermParamClause(Nil)), tpt, Some(rhs)) =>
1111
val parents = List(TypeTree.of[Object])
1212
def decls(cls: Symbol): List[Symbol] =
13-
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.Static, Symbol.noSymbol))
13+
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
14+
15+
val mod = Symbol.newModule(Symbol.spliceOwner, "Baz", Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
16+
val cls = mod.moduleClass
1417

15-
// FIXME: missing flags: Final | Module
16-
// FIXME: how to set the self type?
17-
val cls = Symbol.newClass(Symbol.spliceOwner, "Baz", parents = parents.map(_.tpe), decls, selfType = None)
18-
val mod = Symbol.newVal(Symbol.spliceOwner, "Baz", cls.typeRef, Flags.Module | Flags.Lazy | Flags.Final, Symbol.noSymbol)
1918
val runSym = cls.declaredMethod("run").head
2019

2120
val runDef = DefDef(runSym, _ => Some(rhs))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
macro generated main
2+
executed in: Foo$Bar$macro$1$
3+
macro generated main
4+
executed in: Foo$Bar$macro$2$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import scala.annotation.{experimental, MacroAnnotation}
2+
import scala.quoted._
3+
import scala.collection.mutable
4+
5+
@experimental
6+
class addClass extends MacroAnnotation:
7+
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
8+
import quotes.reflect._
9+
tree match
10+
case DefDef(name, List(TermParamClause(Nil)), tpt, Some(rhs)) =>
11+
val parents = List(TypeTree.of[Object])
12+
def decls(cls: Symbol): List[Symbol] =
13+
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
14+
15+
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
16+
val cls = mod.moduleClass
17+
18+
val runSym = cls.declaredMethod("run").head
19+
20+
val runDef = DefDef(runSym, _ => Some(rhs))
21+
22+
val clsDef = ClassDef(cls, parents, body = List(runDef))
23+
24+
val newCls = Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil)
25+
val modVal = ValDef(mod, Some(newCls))
26+
27+
val newDef = DefDef.copy(tree)(name, List(TermParamClause(Nil)), tpt, Some(Apply(Select(Ref(mod), runSym), Nil)))
28+
List(modVal, clsDef, newDef)
29+
case _ =>
30+
report.error("Annotation only supports `def` with one argument")
31+
List(tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class Foo():
2+
@addClass def foo(): Unit =
3+
println("macro generated main")
4+
println("executed in: " + (new Throwable().getStackTrace().head.getClassName))
5+
//> object Baz$macro$1 {
6+
//> def run() =
7+
//> println("macro generated main")
8+
//> println("executed in: " + getClass.getName)
9+
//> }
10+
//> def foo(): Unit =
11+
//> Baz$macro$1.run
12+
13+
@addClass def bar(): Unit =
14+
println("macro generated main")
15+
println("executed in: " + (new Throwable().getStackTrace().head.getClassName))
16+
//> object Baz$macro$2 {
17+
//> def run() =
18+
//> println("macro generated main")
19+
//> println("executed in: " + getClass.getName)
20+
//> }
21+
//> def foo(): Unit =
22+
//> Baz$macro$2.run
23+
24+
@main def Test(): Unit =
25+
new Foo().foo()
26+
new Foo().bar()

0 commit comments

Comments
 (0)