Skip to content

Commit c4bef92

Browse files
committed
Add reflect newMethodOverride and newValOverride
Closes #15035
1 parent d5fcfcf commit c4bef92

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,8 +2485,20 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
24852485
newMethod(owner, name, tpe, Flags.EmptyFlags, noSymbol)
24862486
def newMethod(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =
24872487
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin)
2488+
2489+
def newMethodOverride(owner: Symbol, sym: Symbol): Symbol =
2490+
assert(isMethod(sym), "not a method symbol: " + sym) // TODO check that is is a member of a class
2491+
val flags = sym.flags &~ dotc.core.Flags.Deferred | dotc.core.Flags.Override
2492+
dotc.core.Symbols.newSymbol(owner, sym.name, flags, sym.info, dotc.core.Symbols.NoSymbol)
2493+
24882494
def newVal(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =
24892495
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags, tpe, privateWithin)
2496+
2497+
def newValOverride(owner: Symbol, sym: Symbol): Symbol =
2498+
assert(isField(sym) || isMethod(sym), "not a method or field symbol: " + sym) // TODO check that is is a member of a class
2499+
val flags = sym.flags &~ dotc.core.Flags.Deferred &~ dotc.core.Flags.Method | dotc.core.Flags.Override
2500+
dotc.core.Symbols.newSymbol(owner, sym.name, flags, sym.info, dotc.core.Symbols.NoSymbol)
2501+
24902502
def newBind(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol =
24912503
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | Case, tpe)
24922504
def noSymbol: Symbol = dotc.core.Symbols.NoSymbol
@@ -2661,13 +2673,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26612673
private def appliedTypeRef(sym: Symbol): TypeRepr =
26622674
sym.typeRef.appliedTo(sym.typeParams.map(_.typeRef))
26632675

2664-
private def isMethod(sym: Symbol): Boolean =
2665-
sym.isTerm && sym.is(dotc.core.Flags.Method) && !sym.isConstructor
2666-
2667-
private def isField(sym: Symbol): Boolean =
2668-
sym.isTerm && !sym.is(dotc.core.Flags.Method)
26692676
end SymbolMethods
26702677

2678+
private def isMethod(sym: Symbol): Boolean =
2679+
sym.isTerm && sym.is(dotc.core.Flags.Method) && !sym.isConstructor
2680+
2681+
private def isField(sym: Symbol): Boolean =
2682+
sym.isTerm && !sym.is(dotc.core.Flags.Method)
2683+
26712684
type Signature = dotc.core.Signature
26722685

26732686
object Signature extends SignatureModule:

library/src/scala/quoted/Quotes.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3673,6 +3673,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36733673
*/
36743674
def newMethod(parent: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol
36753675

3676+
/** TODO */
3677+
def newMethodOverride(parent: Symbol, sym: Symbol): Symbol
3678+
36763679
/** Generates a new val/var/lazy val symbol with the given parent, name and type.
36773680
*
36783681
* This symbol starts without an accompanying definition.
@@ -3691,6 +3694,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36913694
*/
36923695
def newVal(parent: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol
36933696

3697+
/** TODO */
3698+
def newValOverride(parent: Symbol, sym: Symbol): Symbol
3699+
36943700
/** Generates a pattern bind symbol with the given parent, name and type.
36953701
*
36963702
* This symbol starts without an accompanying definition.

tests/run-macros/i15035.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
1
2+
1
3+
1
4+
1
5+
3
6+
3
7+
3
8+
3

tests/run-macros/i15035/Macro_1.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import scala.quoted.*
2+
3+
inline def make[T](inline value: Int): T = ${impl[T]('value)}
4+
5+
def impl[T: Type](value: Expr[Int])(using Quotes): Expr[T] = {
6+
import quotes.reflect.*
7+
8+
val className = "Foo"
9+
val parents = List(TypeTree.of[Object], TypeTree.of[T])
10+
11+
val parentMethods = TypeRepr.of[T].typeSymbol.declaredMethods
12+
13+
def decls(cls: Symbol): List[Symbol] =
14+
TypeRepr.of[T].typeSymbol.declaredFields.map(field => Symbol.newValOverride(cls, field)) ++
15+
TypeRepr.of[T].typeSymbol.declaredMethods.map(method => Symbol.newMethodOverride(cls, method))
16+
17+
val cls = Symbol.newClass(Symbol.spliceOwner, className, parents = parents.map(_.tpe), decls, selfType = None)
18+
val body =
19+
cls.declaredFields.map { method => ValDef(method, Some(value.asTerm)) } ++
20+
cls.declaredMethods.map { method => DefDef(method, argss => Some(value.asTerm)) }
21+
val clsDef = ClassDef(cls, parents, body = body)
22+
val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), TypeTree.of[T])
23+
Block(List(clsDef), newCls).asExprOf[T]
24+
}

tests/run-macros/i15035/Test_2.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
trait A {
2+
val foo0: Int
3+
def foo1(): Int
4+
def foo2(foo: String): Int
5+
def foo3: Int
6+
}
7+
8+
trait B {
9+
val foo0: Int = 2
10+
def foo1(): Int = 2
11+
def foo2(foo: String): Int = 2
12+
def foo3: Int = 2
13+
}
14+
15+
16+
@main
17+
def Test = {
18+
val a: A = make[A](1)
19+
println(a.foo0)
20+
println(a.foo1())
21+
println(a.foo2("test"))
22+
println(a.foo3)
23+
24+
val b: B = make[B](3)
25+
println(b.foo0)
26+
println(b.foo1())
27+
println(b.foo2("test"))
28+
println(b.foo3)
29+
}

0 commit comments

Comments
 (0)