Skip to content

Commit 8721213

Browse files
committed
Change parameter names, add tests
1 parent 7397cf2 commit 8721213

File tree

15 files changed

+225
-58
lines changed

15 files changed

+225
-58
lines changed

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

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -249,15 +249,21 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
249249
else
250250
paramSym.map(ValDef(_, None))
251251
}
252+
def throwError() =
253+
throw new RuntimeException(
254+
"Symbols necessary for creation of the ClassDef tree could not be found."
255+
)
252256
val paramsAccessDefs: List[untpd.ParamClause] =
253257
cls.primaryConstructor.paramSymss.map { paramSym =>
254258
if paramSym.headOption.map(_.isType).getOrElse(false) then
255259
paramSym.map { symm =>
256-
TypeDef(cls.typeMember(symm.name.toString()))
260+
def isParamAccessor(memberSym: Symbol) = memberSym.flags.is(Flags.Param) && memberSym.name == symm.name
261+
TypeDef(cls.typeMembers.find(isParamAccessor).getOrElse(throwError()))
257262
}
258263
else
259264
paramSym.map { symm =>
260-
ValDef(cls.fieldMember(symm.name.toString()), None)// TODO I don't like the toString here
265+
def isParam(memberSym: Symbol) = memberSym.flags.is(Flags.ParamAccessor) && memberSym.name == symm.name
266+
ValDef(cls.fieldMembers.find(isParam).getOrElse(throwError()), None)
261267
}
262268
}
263269

@@ -2645,13 +2651,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26452651
parents: Symbol => List[TypeRepr],
26462652
decls: Symbol => List[Symbol],
26472653
selfType: Option[TypeRepr],
2648-
paramNames: List[String],
2649-
paramTypes: List[TypeRepr],
26502654
clsFlags: Flags,
2651-
clsPrivateWithin: Symbol
2655+
clsPrivateWithin: Symbol,
2656+
conParamNames: List[String],
2657+
conParamTypes: List[TypeRepr],
26522658
): Symbol =
2653-
checkValidFlags(clsFlags.toTermFlags, Flags.validClassFlags)
2654-
assert(paramNames.length == paramTypes.length, "paramNames and paramTypes must have the same length")
2659+
checkValidFlags(clsFlags, Flags.validClassFlags)
2660+
assert(conParamNames.length == conParamTypes.length, "paramNames and paramTypes must have the same length")
26552661
assert(!clsPrivateWithin.exists || clsPrivateWithin.isType, "clsPrivateWithin must be a type symbol or `Symbol.noSymbol`")
26562662
val cls = dotc.core.Symbols.newNormalizedClassSymbolUsingClassSymbolinParents(
26572663
owner,
@@ -2660,8 +2666,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26602666
parents,
26612667
selfType.getOrElse(Types.NoType),
26622668
clsPrivateWithin)
2663-
cls.enter(dotc.core.Symbols.newConstructor(cls, dotc.core.Flags.Synthetic, paramNames.map(_.toTermName), paramTypes))
2664-
for (name, tpe) <- paramNames.zip(paramTypes) do
2669+
cls.enter(dotc.core.Symbols.newConstructor(cls, dotc.core.Flags.Synthetic, conParamNames.map(_.toTermName), conParamTypes))
2670+
for (name, tpe) <- conParamNames.zip(conParamTypes) do
26652671
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor, tpe, Symbol.noSymbol))
26662672
for sym <- decls(cls) do cls.enter(sym)
26672673
cls
@@ -2672,39 +2678,39 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26722678
parents: Symbol => List[TypeRepr],
26732679
decls: Symbol => List[Symbol],
26742680
selfType: Option[TypeRepr],
2675-
constructorMethodType: TypeRepr => MethodOrPoly,
26762681
clsFlags: Flags,
26772682
clsPrivateWithin: Symbol,
2678-
consFlags: Flags,
2679-
consPrivateWithin: Symbol,
2680-
consParamFlags: List[List[Flags]]
2683+
conMethodType: TypeRepr => MethodOrPoly,
2684+
conFlags: Flags,
2685+
conPrivateWithin: Symbol,
2686+
conParamFlags: List[List[Flags]]
26812687
) =
26822688
assert(!clsPrivateWithin.exists || clsPrivateWithin.isType, "clsPrivateWithin must be a type symbol or `Symbol.noSymbol`")
2683-
assert(!consPrivateWithin.exists || consPrivateWithin.isType, "consPrivateWithin must be a type symbol or `Symbol.noSymbol`")
2684-
checkValidFlags(clsFlags.toTermFlags, Flags.validClassFlags)
2689+
assert(!conPrivateWithin.exists || conPrivateWithin.isType, "consPrivateWithin must be a type symbol or `Symbol.noSymbol`")
2690+
checkValidFlags(clsFlags.toTypeFlags, Flags.validClassFlags)
26852691
val cls = dotc.core.Symbols.newNormalizedClassSymbolUsingClassSymbolinParents(
26862692
owner,
26872693
name.toTypeName,
26882694
clsFlags,
26892695
parents,
26902696
selfType.getOrElse(Types.NoType),
26912697
clsPrivateWithin)
2692-
val methodType: MethodOrPoly = constructorMethodType(cls.typeRef)
2693-
def throwShapeException() = throw new Exception("Shapes of constructorMethodType and consParamFlags differ.")
2698+
val methodType: MethodOrPoly = conMethodType(cls.typeRef)
2699+
def throwShapeException() = throw new Exception("Shapes of conMethodType and conParamFlags differ.")
26942700
def checkMethodOrPolyShape(checkedMethodType: TypeRepr, clauseIdx: Int): Unit =
26952701
checkedMethodType match
26962702
case PolyType(params, _, res) if clauseIdx == 0 =>
2697-
if (consParamFlags.length < clauseIdx) throwShapeException()
2698-
if (consParamFlags(clauseIdx).length != params.length) throwShapeException()
2703+
if (conParamFlags.length < clauseIdx) throwShapeException()
2704+
if (conParamFlags(clauseIdx).length != params.length) throwShapeException()
26992705
checkMethodOrPolyShape(res, clauseIdx + 1)
27002706
case PolyType(_, _, _) => throw new Exception("Clause interleaving not supported for constructors")
27012707
case MethodType(params, _, res) =>
2702-
if (consParamFlags.length < clauseIdx) throwShapeException()
2703-
if (consParamFlags(clauseIdx).length != params.length) throwShapeException()
2708+
if (conParamFlags.length <= clauseIdx) throwShapeException()
2709+
if (conParamFlags(clauseIdx).length != params.length) throwShapeException()
27042710
checkMethodOrPolyShape(res, clauseIdx + 1)
27052711
case _ =>
27062712
checkMethodOrPolyShape(methodType, clauseIdx = 0)
2707-
cls.enter(dotc.core.Symbols.newSymbol(cls, nme.CONSTRUCTOR, Flags.Synthetic | Flags.Method | consFlags, methodType, consPrivateWithin, dotty.tools.dotc.util.Spans.NoCoord)) // constructor flags
2713+
cls.enter(dotc.core.Symbols.newSymbol(cls, nme.CONSTRUCTOR, Flags.Synthetic | Flags.Method | conFlags, methodType, conPrivateWithin, dotty.tools.dotc.util.Spans.NoCoord))
27082714
def getParamAccessors(methodType: TypeRepr, clauseIdx: Int): List[((String, TypeRepr, Boolean, Int), Int)] =
27092715
methodType match
27102716
case MethodType(paramInfosExp, resultTypeExp, res) =>
@@ -2723,17 +2729,16 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
27232729
}
27242730
for ((name, tpe, isType, clauseIdx), elementIdx) <- getParamAccessors(methodType, 0) do
27252731
if isType then
2726-
val symbol = dotc.core.Symbols.newSymbol(cls, name.toTypeName, Flags.Param | Flags.Deferred | consParamFlags(clauseIdx)(elementIdx), tpe, Symbol.noSymbol)
2732+
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)
27272733
paramRefMap.addOne(elementIdx, symbol)
27282734
cls.enter(symbol)
27292735
else
27302736
val fixedType = paramRefRemapper(tpe)
2731-
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | consParamFlags(clauseIdx)(elementIdx), fixedType, Symbol.noSymbol)) // add other flags (local, private, privatelocal) and set privateWithin
2737+
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | conParamFlags(clauseIdx)(elementIdx), fixedType, Symbol.noSymbol)) // set privateWithin
27322738
for sym <- decls(cls) do cls.enter(sym)
27332739
cls
27342740

27352741
def newModule(owner: Symbol, name: String, modFlags: Flags, clsFlags: Flags, parents: Symbol => List[TypeRepr], decls: Symbol => List[Symbol], privateWithin: Symbol): Symbol =
2736-
// assert(parents.nonEmpty && !parents.head.typeSymbol.is(dotc.core.Flags.Trait), "First parent must be a class")
27372742
assert(!privateWithin.exists || privateWithin.isType, "privateWithin must be a type symbol or `Symbol.noSymbol`")
27382743
val mod = dotc.core.Symbols.newNormalizedModuleSymbolUsingClassSymbolInParents(
27392744
owner,
@@ -3141,7 +3146,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
31413146
private[QuotesImpl] def validTypeAliasFlags: Flags = Private | Protected | Override | Final | Infix | Local
31423147

31433148
// Keep: aligned with Quotes's `newClass`
3144-
private[QuotesImpl] def validClassFlags: Flags = Private | Protected | Final // Abstract, AbsOverride Local OPen ? PrivateLocal Protected ?
3149+
private[QuotesImpl] def validClassFlags: Flags = Private | Protected | PrivateLocal | Local | Final | Trait | Abstract // AbsOverride, Open
31453150

31463151
end Flags
31473152

library/src/scala/quoted/Quotes.scala

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3846,10 +3846,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38463846
* @param name The name of the class
38473847
* @param parents Function returning the parent classes of the class. The first parent must not be a trait.
38483848
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
3849-
* @param paramNames constructor parameter names.
3850-
* @param paramTypes constructor parameter types.
38513849
* @param clsFlags extra flags with which the class symbol should be constructed.
38523850
* @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol.
3851+
* @param conParamNames constructor parameter names.
3852+
* @param conParamTypes constructor parameter types.
38533853
*
38543854
* Parameters can be obtained via classSymbol.memberField
38553855
*/
@@ -3858,28 +3858,28 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38583858
name: String,
38593859
parents: Symbol => List[TypeRepr],
38603860
decls: Symbol => List[Symbol], selfType: Option[TypeRepr],
3861-
paramNames: List[String],
3862-
paramTypes: List[TypeRepr],
38633861
clsFlags: Flags,
3864-
clsPrivateWithin: Symbol
3862+
clsPrivateWithin: Symbol,
3863+
conParamNames: List[String],
3864+
conParamTypes: List[TypeRepr]
38653865
): Symbol
38663866

38673867
/**
38683868
*
38693869
*
38703870
* @param owner The owner of the class
38713871
* @param name The name of the class
3872-
* @param parents Function returning the parent classes of the class. The first parent must not be a trait.
3872+
* @param parents Function returning the parent classes of the class. The first parent must not be a trait
38733873
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
38743874
* @param decls The member declarations of the class provided the symbol of this class
38753875
* @param selfType The self type of the class if it has one
3876-
* @param constructorMethodType The MethodOrPoly type representing the type of the constructor.
3877-
* PolyType may only represent only the first clause of the constructor.
3878-
* @param clsFlags extra flags with which the class symbol should be constructed.
3876+
* @param clsFlags extra flags with which the class symbol should be constructed
38793877
* @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol
3880-
* @param consFlags extra flags with which the constructor symbol should be constructed.
3881-
* @param consPrivateWithin the symbol within which the constructor for this new class symbol should be private. May be noSymbol
3882-
* @param conParamFlags extra flags with which the constructor parameter symbols should be constructed. Must match the shape of @param constructorMethodType
3878+
* @param conMethodType The MethodOrPoly type representing the type of the constructor.
3879+
* PolyType may only represent the first clause of the constructor.
3880+
* @param conFlags extra flags with which the constructor symbol should be constructed
3881+
* @param conPrivateWithin the symbol within which the constructor for this new class symbol should be private. May be noSymbol.
3882+
* @param conParamFlags extra flags with which the constructor parameter symbols should be constructed. Must match the shape of `conMethodType`.
38833883
*
38843884
*/
38853885
@experimental def newClass(
@@ -3888,11 +3888,11 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38883888
parents: Symbol => List[TypeRepr],
38893889
decls: Symbol => List[Symbol],
38903890
selfType: Option[TypeRepr],
3891-
constructorMethodType: TypeRepr => MethodOrPoly,
38923891
clsFlags: Flags,
38933892
clsPrivateWithin: Symbol,
3894-
consFlags: Flags,
3895-
consPrivateWithin: Symbol,
3893+
conMethodType: TypeRepr => MethodOrPoly,
3894+
conFlags: Flags,
3895+
conPrivateWithin: Symbol,
38963896
conParamFlags: List[List[Flags]]
38973897
): Symbol
38983898

tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala

Lines changed: 1 addition & 1 deletion
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, List("idx"), List(TypeRepr.of[Int]), Flags.EmptyFlags, Symbol.noSymbol)
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]))
1414

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

tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala

Lines changed: 1 addition & 1 deletion
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, paramNames = Nil, paramTypes = Nil, Flags.EmptyFlags, Symbol.noSymbol)
16+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents, decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, conParamNames = Nil, conParamTypes = Nil)
1717

1818
val parentsWithSym =
1919
cls.typeRef.asType match
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class Main_2$package$foo$1
2+
22
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class JavaClass<T> {
2+
T value;
3+
public JavaClass(T value) {
4+
this.value = value;
5+
}
6+
public T getT() {
7+
return value;
8+
}
9+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//> using options -experimental
2+
3+
import scala.quoted.*
4+
5+
transparent inline def makeClass(inline name: String): JavaClass[Int] = ${ makeClassExpr('name) }
6+
private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[JavaClass[Int]] = {
7+
import quotes.reflect.*
8+
9+
val name = nameExpr.valueOrAbort
10+
val parents = List(TypeTree.of[JavaClass[Int]])
11+
def decls(cls: Symbol): List[Symbol] = Nil
12+
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]))
14+
15+
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")))))
16+
val clsDef = ClassDef(cls, parentsWithSym, body = Nil)
17+
val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), List(Literal(IntConstant(22)))), TypeTree.of[JavaClass[Int]])
18+
19+
Block(List(clsDef), newCls).asExprOf[JavaClass[Int]]
20+
// '{
21+
// class `name`(idx: Int) extends JavaClass[Int](idx)
22+
// new `name`(22)
23+
// }
24+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//> using options -experimental
2+
3+
@main def Test: Unit = {
4+
val cls = makeClass("foo")
5+
println(cls.getClass)
6+
println(cls.getT())
7+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Foo method call with (10, test)
1+
Foo method call with (10, test)

tests/run-macros/newClassParams/Macro_1.scala

Lines changed: 1 addition & 2 deletions
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, List("idx", "str"), List(TypeRepr.of[Int], TypeRepr.of[String]), Flags.EmptyFlags, Symbol.noSymbol)
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]))
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))
@@ -25,4 +25,3 @@ private def makeClassAndCallExpr(nameExpr: Expr[String], idxExpr: Expr[Int], str
2525
// new `name`(`idx`, `str`)
2626
// }
2727
}
28-

0 commit comments

Comments
 (0)