Skip to content

Commit 27d4fa2

Browse files
committed
Improve api, documentation and add conParamsPrivateWithin
1 parent d683839 commit 27d4fa2

File tree

15 files changed

+177
-32
lines changed

15 files changed

+177
-32
lines changed

Diff for: compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

+10-10
Original file line numberDiff line numberDiff line change
@@ -2653,10 +2653,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26532653
selfType: Option[TypeRepr],
26542654
clsFlags: Flags,
26552655
clsPrivateWithin: Symbol,
2656-
conParamNames: List[String],
2657-
conParamTypes: List[TypeRepr],
2656+
conParams: List[(String, TypeRepr)]
26582657
): Symbol =
2659-
assert(conParamNames.length == conParamTypes.length, "Lengths of conParamNames and conParamTypes must be equal")
2658+
val (conParamNames, conParamTypes) = conParams.unzip()
26602659
newClass(
26612660
owner,
26622661
name,
@@ -2669,7 +2668,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26692668
conMethodType = res => MethodType(conParamNames)(_ => conParamTypes, _ => res),
26702669
conFlags = Flags.EmptyFlags,
26712670
conPrivateWithin = Symbol.noSymbol,
2672-
conParamFlags = List(for i <- conParamNames yield Flags.EmptyFlags)
2671+
conParamFlags = List(for i <- conParamNames yield Flags.EmptyFlags),
2672+
conParamPrivateWithins = List(for i <- conParamNames yield Symbol.noSymbol)
26732673
)
26742674

26752675
def newClass(
@@ -2684,7 +2684,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26842684
conMethodType: TypeRepr => MethodOrPoly,
26852685
conFlags: Flags,
26862686
conPrivateWithin: Symbol,
2687-
conParamFlags: List[List[Flags]]
2687+
conParamFlags: List[List[Flags]],
2688+
conParamPrivateWithins: List[List[Symbol]]
26882689
) =
26892690
assert(!clsPrivateWithin.exists || clsPrivateWithin.isType, "clsPrivateWithin must be a type symbol or `Symbol.noSymbol`")
26902691
assert(!conPrivateWithin.exists || conPrivateWithin.isType, "consPrivateWithin must be a type symbol or `Symbol.noSymbol`")
@@ -2723,7 +2724,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
27232724
paramNames.zip(paramBounds).map(_ :* true :* clauseIdx).zipWithIndex ++ getParamAccessors(res, clauseIdx + 1)
27242725
case result =>
27252726
List()
2726-
// Maps PolyType indexes to type symbols
2727+
// Maps PolyType indexes to type parameter symbols
27272728
val paramRefMap = collection.mutable.HashMap[Int, Symbol]()
27282729
val paramRefRemapper = new Types.TypeMap {
27292730
def apply(tp: Types.Type) = tp match {
@@ -2734,13 +2735,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
27342735
for ((name, tpe, isType, clauseIdx), elementIdx) <- getParamAccessors(methodType, 0) do
27352736
if isType then
27362737
checkValidFlags(conParamFlags(clauseIdx)(elementIdx), Flags.validClassTypeParamFlags)
2737-
val symbol = dotc.core.Symbols.newSymbol(cls, name.toTypeName, Flags.Param | Flags.Deferred | Flags.Private | Flags.PrivateLocal | Flags.Local | conParamFlags(clauseIdx)(elementIdx), tpe, Symbol.noSymbol)
2738+
val symbol = dotc.core.Symbols.newSymbol(cls, name.toTypeName, Flags.Param | Flags.Deferred | Flags.Private | Flags.PrivateLocal | Flags.Local | conParamFlags(clauseIdx)(elementIdx), tpe, conParamPrivateWithins(clauseIdx)(elementIdx))
27382739
paramRefMap.addOne(elementIdx, symbol)
27392740
cls.enter(symbol)
27402741
else
27412742
checkValidFlags(conParamFlags(clauseIdx)(elementIdx), Flags.validClassTermParamFlags)
27422743
val fixedType = paramRefRemapper(tpe)
2743-
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | conParamFlags(clauseIdx)(elementIdx), fixedType, Symbol.noSymbol)) // TODO set privateWithin?
2744+
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | conParamFlags(clauseIdx)(elementIdx), fixedType, conParamPrivateWithins(clauseIdx)(elementIdx)))
27442745
for sym <- decls(cls) do cls.enter(sym)
27452746
cls
27462747

@@ -3152,10 +3153,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
31523153
private[QuotesImpl] def validTypeAliasFlags: Flags = Private | Protected | Override | Final | Infix | Local
31533154

31543155
// Keep: aligned with Quotes's `newClass`
3155-
private[QuotesImpl] def validClassFlags: Flags = Private | Protected | PrivateLocal | Local | Final | Trait | Abstract // AbsOverride, Open
3156+
private[QuotesImpl] def validClassFlags: Flags = Private | Protected | PrivateLocal | Local | Final | Trait | Abstract | Open
31563157

31573158
// Keep: aligned with Quote's 'newClass'
3158-
// Private constructor would be currently useless, but if we decide to add a way to register companions in the future it might be useful
31593159
private[QuotesImpl] def validClassConstructorFlags: Flags = Synthetic | Method | Private | Protected | PrivateLocal | Local
31603160

31613161
// Keep: aligned with Quotes's `newClass`

Diff for: library/src/scala/quoted/Quotes.scala

+73-9
Original file line numberDiff line numberDiff line change
@@ -3847,8 +3847,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38473847
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
38483848
* @param clsFlags extra flags with which the class symbol should be constructed.
38493849
* @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol.
3850-
* @param conParamNames constructor parameter names.
3851-
* @param conParamTypes constructor parameter types.
3850+
* @param conParams constructor parameter pairs of names and types.
38523851
*
38533852
* Parameters assigned by the constructor can be obtained via `classSymbol.memberField`.
38543853
* This symbol starts without an accompanying definition.
@@ -3862,31 +3861,93 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38623861
owner: Symbol,
38633862
name: String,
38643863
parents: Symbol => List[TypeRepr],
3865-
decls: Symbol => List[Symbol], selfType: Option[TypeRepr],
3864+
decls: Symbol => List[Symbol],
3865+
selfType: Option[TypeRepr],
38663866
clsFlags: Flags,
38673867
clsPrivateWithin: Symbol,
3868-
conParamNames: List[String],
3869-
conParamTypes: List[TypeRepr]
3868+
conParams: List[(String, TypeRepr)]
38703869
): Symbol
38713870

38723871
/** Generates a new class symbol with a constructor of the shape signified by a passed PolyOrMethod parameter.
3873-
* TODO example with PolyType
3872+
*
3873+
* Example usage:
3874+
* ```
3875+
* val name = "myClass"
3876+
* def decls(cls: Symbol): List[Symbol] =
3877+
* List(Symbol.newMethod(cls, "getParam", MethodType(Nil)(_ => Nil, _ => cls.typeMember("T").typeRef)))
3878+
* val conMethodType =
3879+
* (classType: TypeRepr) => PolyType(List("T"))(_ => List(TypeBounds.empty), polyType =>
3880+
* MethodType(List("param"))((_: MethodType) => List(polyType.param(0)), (_: MethodType) =>
3881+
* classType
3882+
* )
3883+
* )
3884+
* val cls = Symbol.newClass(
3885+
* Symbol.spliceOwner,
3886+
* name,
3887+
* parents = _ => List(TypeRepr.of[Object]),
3888+
* decls,
3889+
* selfType = None,
3890+
* clsFlags = Flags.EmptyFlags,
3891+
* clsPrivateWithin = Symbol.noSymbol,
3892+
* clsAnnotations = Nil,
3893+
* conMethodType,
3894+
* conFlags = Flags.EmptyFlags,
3895+
* conPrivateWithin = Symbol.noSymbol,
3896+
* conParamFlags = List(List(Flags.EmptyFlags), List(Flags.EmptyFlags)),
3897+
* conParamPrivateWithins = List(List(Symbol.noSymbol), List(Symbol.noSymbol))
3898+
* )
3899+
*
3900+
* val getParamSym = cls.declaredMethod("getParam").head
3901+
* def getParamRhs(): Option[Term] =
3902+
* val paramValue = This(cls).select(cls.fieldMember("param")).asExpr
3903+
* Some('{ println("Calling getParam"); $paramValue }.asTerm)
3904+
* val getParamDef = DefDef(getParamSym, _ => getParamRhs())
3905+
*
3906+
* val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = List(getParamDef))
3907+
* val newCls =
3908+
* Apply(
3909+
* Select(
3910+
* Apply(
3911+
* TypeApply(Select(New(TypeIdent(cls)), cls.primaryConstructor), List(TypeTree.of[String])),
3912+
* List(Expr("test").asTerm)
3913+
* ),
3914+
* cls.methodMember("getParam").head
3915+
* ),
3916+
* Nil
3917+
* )
3918+
*
3919+
* Block(List(clsDef), newCls).asExpr
3920+
* ```
3921+
* constructs the equivalent to
3922+
* ```
3923+
* '{
3924+
* class myClass[T](val param: T) {
3925+
* def getParam: T =
3926+
* println("Calling getParam")
3927+
* param
3928+
* }
3929+
* new myClass[String]("test").getParam()
3930+
* }
3931+
* ```
38743932
*
38753933
* @param owner The owner of the class
38763934
* @param name The name of the class
38773935
* @param parents Function returning the parent classes of the class. The first parent must not be a trait
38783936
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
38793937
* @param decls The member declarations of the class provided the symbol of this class
38803938
* @param selfType The self type of the class if it has one
3881-
* @param clsFlags extra flags with which the class symbol should be constructed
3939+
* @param clsFlags extra flags with which the class symbol should be constructed. Can be `Private` | `Protected` | `PrivateLocal` | `Local` | `Final` | `Trait` | `Abstract` | `Open`
38823940
* @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol
38833941
* @param clsAnnotations annotations of the class
38843942
* @param conMethodType Function returning MethodOrPoly type representing the type of the constructor.
38853943
* Takes the result type as parameter which must be returned from the innermost MethodOrPoly.
38863944
* PolyType may only represent the first clause of the constructor.
3887-
* @param conFlags extra flags with which the constructor symbol should be constructed
3945+
* @param conFlags extra flags with which the constructor symbol should be constructed. Can be `Synthetic` | `Method` | `Private` | `Protected` | `PrivateLocal` | `Local`
38883946
* @param conPrivateWithin the symbol within which the constructor for this new class symbol should be private. May be noSymbol.
38893947
* @param conParamFlags extra flags with which the constructor parameter symbols should be constructed. Must match the shape of `conMethodType`.
3948+
* For type parameters those can be `Param` | `Deferred` | `Private` | `PrivateLocal` | `Local`.
3949+
* For term parameters those can be `ParamAccessor` | `Private` | `Protected` | `PrivateLocal` | `Local`
3950+
* @param conParamPrivateWithins the symbols within which the constructor parameters should be private. Must match the shape of `conMethodType`. Can consist of noSymbol.
38903951
*
38913952
* Term and type parameters assigned by the constructor can be obtained via `classSymbol.memberField`/`classSymbol.memberType`.
38923953
* This symbol starts without an accompanying definition.
@@ -3896,6 +3957,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38963957
* @note As a macro can only splice code into the point at which it is expanded, all generated symbols must be
38973958
* direct or indirect children of the reflection context's owner.
38983959
*/
3960+
// Keep doc aligned with QuotesImpl's validFlags: `clsFlags` with `validClassFlags`, `conFlags` with `validClassConstructorFlags`,
3961+
// conParamFlags with `validClassTypeParamFlags` and `validClassTermParamFlags`
38993962
@experimental def newClass(
39003963
owner: Symbol,
39013964
name: String,
@@ -3908,7 +3971,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
39083971
conMethodType: TypeRepr => MethodOrPoly,
39093972
conFlags: Flags,
39103973
conPrivateWithin: Symbol,
3911-
conParamFlags: List[List[Flags]]
3974+
conParamFlags: List[List[Flags]],
3975+
conParamPrivateWithins: List[List[Symbol]]
39123976
): Symbol
39133977

39143978
/** Generates a new module symbol with an associated module class symbol,

Diff for: tests/neg-macros/i19842-a.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
|
1010
| at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
1111
| at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:210)
12-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:278)
13-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:277)
12+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:284)
13+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:283)
1414
| at Macros$.makeSerializer(Macro.scala:25)
1515
|
1616
|---------------------------------------------------------------------------------------------------------------------

Diff for: tests/neg-macros/i19842-b.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
|
1010
| at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
1111
| at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:210)
12-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:278)
13-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:277)
12+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:284)
13+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:283)
1414
| at Macros$.makeSerializer(Macro.scala:27)
1515
|
1616
|---------------------------------------------------------------------------------------------------------------------

Diff for: tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Object] =
1010
val parents = List(TypeTree.of[Object])
1111
def decls(cls: Symbol): List[Symbol] = Nil
1212

13-
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int]))
13+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int])))
1414

1515
val clsDef = ClassDef(cls, parents, body = Nil)
1616
val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), TypeTree.of[Object])

Diff for: tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Foo[_]] =
1313
List(AppliedType(TypeRepr.typeConstructorOf(Class.forName("Foo")), List(TypeIdent(cls).tpe)))
1414
def decls(cls: Symbol): List[Symbol] = Nil
1515

16-
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents, decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, conParamNames = Nil, conParamTypes = Nil)
16+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents, decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, conParams = Nil)
1717

1818
val parentsWithSym =
1919
cls.typeRef.asType match

Diff for: tests/run-macros/newClassAnnotation/Macro_1.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Any] = {
3131
conMethodType,
3232
conFlags = Flags.EmptyFlags,
3333
conPrivateWithin = Symbol.noSymbol,
34-
conParamFlags = List(List())
34+
conParamFlags = List(List()),
35+
conParamPrivateWithins = List(List())
3536
)
3637

3738
val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = Nil)

Diff for: tests/run-macros/newClassExtendsJavaClass/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[JavaClass[
1010
val parents = List(TypeTree.of[JavaClass[Int]])
1111
def decls(cls: Symbol): List[Symbol] = Nil
1212

13-
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int]))
13+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int])))
1414

1515
val parentsWithSym = List(Apply(TypeApply(Select(New(TypeTree.of[JavaClass[Int]]), TypeRepr.of[JavaClass].typeSymbol.primaryConstructor), List(TypeTree.of[Int])), List(Ref(cls.fieldMember("idx")))))
1616
val clsDef = ClassDef(cls, parentsWithSym, body = Nil)

Diff for: tests/run-macros/newClassParams/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private def makeClassAndCallExpr(nameExpr: Expr[String], idxExpr: Expr[Int], str
1010

1111
def decls(cls: Symbol): List[Symbol] = List(Symbol.newMethod(cls, "foo", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit])))
1212
val parents = List(TypeTree.of[Object])
13-
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx", "str"), List(TypeRepr.of[Int], TypeRepr.of[String]))
13+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int]), ("str", TypeRepr.of[String])))
1414

1515
val fooDef = DefDef(cls.methodMember("foo")(0), argss => Some('{println(s"Foo method call with (${${Ref(cls.fieldMember("idx")).asExpr}}, ${${Ref(cls.fieldMember("str")).asExpr}})")}.asTerm))
1616
val clsDef = ClassDef(cls, parents, body = List(fooDef))

Diff for: tests/run-macros/newClassParamsExtendsClassParams/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Foo] = {
1010
val parents = List('{ new Foo(1) }.asTerm)
1111
def decls(cls: Symbol): List[Symbol] = Nil
1212

13-
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int]))
13+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int])))
1414

1515
val parentsWithSym = List(Apply(Select(New(TypeTree.of[Foo]), TypeRepr.of[Foo].typeSymbol.primaryConstructor), List(Ref(cls.fieldMember("idx")))))
1616
val clsDef = ClassDef(cls, parentsWithSym, body = Nil)

Diff for: tests/run-macros/newClassTraitAndAbstract/Macro_1.scala

+6-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ private def makeClassExpr(using Quotes)(
4444
selfType = None,
4545
clsFlags,
4646
clsPrivateWithin = Symbol.noSymbol,
47+
clsAnnotations = Nil,
4748
conMethodType,
4849
conFlags = Flags.EmptyFlags,
4950
conPrivateWithin = Symbol.noSymbol,
50-
conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags))
51+
conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags)),
52+
conParamPrivateWithins = List(List(Symbol.noSymbol, Symbol.noSymbol), List(Symbol.noSymbol, Symbol.noSymbol))
5153
)
5254
val traitDef = ClassDef(traitSymbol, List(TypeTree.of[Object]), body = Nil)
5355

@@ -60,10 +62,12 @@ private def makeClassExpr(using Quotes)(
6062
selfType = None,
6163
clsFlags = Flags.EmptyFlags,
6264
clsPrivateWithin = Symbol.noSymbol,
65+
clsAnnotations = Nil,
6366
conMethodType = (classType: TypeRepr) => MethodType(Nil)(_ => Nil, _ => classType),
6467
conFlags = Flags.EmptyFlags,
6568
conPrivateWithin = Symbol.noSymbol,
66-
conParamFlags = List(List())
69+
conParamFlags = List(List()),
70+
conParamPrivateWithins = List(List(Symbol.noSymbol, Symbol.noSymbol), List(Symbol.noSymbol, Symbol.noSymbol))
6771
)
6872
val obj = '{new java.lang.Object()}.asTerm match
6973
case Inlined(_, _, term) => term

Diff for: tests/run-macros/newClassTypeParamDoc.check

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Calling getParam
2+
test

0 commit comments

Comments
 (0)