From c11f7f023aa4ca2479cc93acc30da88fe13b3b01 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Thu, 30 Jan 2025 18:43:20 +0100 Subject: [PATCH] Improve api, documentation and add conParamsPrivateWithin --- .../quoted/runtime/impl/QuotesImpl.scala | 20 ++--- library/src/scala/quoted/Quotes.scala | 82 +++++++++++++++++-- tests/neg-macros/i19842-a.check | 4 +- tests/neg-macros/i19842-b.check | 4 +- .../Macro_1.scala | 2 +- .../Macro_1.scala | 2 +- .../newClassAnnotation/Macro_1.scala | 3 +- .../newClassExtendsJavaClass/Macro_1.scala | 2 +- tests/run-macros/newClassParams/Macro_1.scala | 2 +- .../Macro_1.scala | 2 +- .../newClassTraitAndAbstract/Macro_1.scala | 8 +- tests/run-macros/newClassTypeParamDoc.check | 2 + .../newClassTypeParamDoc/Macro_1.scala | 63 ++++++++++++++ .../newClassTypeParamDoc/Test_2.scala | 5 ++ .../newClassTypeParams/Macro_1.scala | 4 +- 15 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 tests/run-macros/newClassTypeParamDoc.check create mode 100644 tests/run-macros/newClassTypeParamDoc/Macro_1.scala create mode 100644 tests/run-macros/newClassTypeParamDoc/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 99d6afb199ed..cb7cedb0f6cb 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2653,10 +2653,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler selfType: Option[TypeRepr], clsFlags: Flags, clsPrivateWithin: Symbol, - conParamNames: List[String], - conParamTypes: List[TypeRepr], + conParams: List[(String, TypeRepr)] ): Symbol = - assert(conParamNames.length == conParamTypes.length, "Lengths of conParamNames and conParamTypes must be equal") + val (conParamNames, conParamTypes) = conParams.unzip() newClass( owner, name, @@ -2669,7 +2668,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler conMethodType = res => MethodType(conParamNames)(_ => conParamTypes, _ => res), conFlags = Flags.EmptyFlags, conPrivateWithin = Symbol.noSymbol, - conParamFlags = List(for i <- conParamNames yield Flags.EmptyFlags) + conParamFlags = List(for i <- conParamNames yield Flags.EmptyFlags), + conParamPrivateWithins = List(for i <- conParamNames yield Symbol.noSymbol) ) def newClass( @@ -2684,7 +2684,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler conMethodType: TypeRepr => MethodOrPoly, conFlags: Flags, conPrivateWithin: Symbol, - conParamFlags: List[List[Flags]] + conParamFlags: List[List[Flags]], + conParamPrivateWithins: List[List[Symbol]] ) = assert(!clsPrivateWithin.exists || clsPrivateWithin.isType, "clsPrivateWithin must be a type symbol or `Symbol.noSymbol`") 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 paramNames.zip(paramBounds).map(_ :* true :* clauseIdx).zipWithIndex ++ getParamAccessors(res, clauseIdx + 1) case result => List() - // Maps PolyType indexes to type symbols + // Maps PolyType indexes to type parameter symbols val paramRefMap = collection.mutable.HashMap[Int, Symbol]() val paramRefRemapper = new Types.TypeMap { def apply(tp: Types.Type) = tp match { @@ -2734,13 +2735,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler for ((name, tpe, isType, clauseIdx), elementIdx) <- getParamAccessors(methodType, 0) do if isType then checkValidFlags(conParamFlags(clauseIdx)(elementIdx), Flags.validClassTypeParamFlags) - 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) + 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)) paramRefMap.addOne(elementIdx, symbol) cls.enter(symbol) else checkValidFlags(conParamFlags(clauseIdx)(elementIdx), Flags.validClassTermParamFlags) val fixedType = paramRefRemapper(tpe) - cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | conParamFlags(clauseIdx)(elementIdx), fixedType, Symbol.noSymbol)) // TODO set privateWithin? + cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor | conParamFlags(clauseIdx)(elementIdx), fixedType, conParamPrivateWithins(clauseIdx)(elementIdx))) for sym <- decls(cls) do cls.enter(sym) cls @@ -3152,10 +3153,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler private[QuotesImpl] def validTypeAliasFlags: Flags = Private | Protected | Override | Final | Infix | Local // Keep: aligned with Quotes's `newClass` - private[QuotesImpl] def validClassFlags: Flags = Private | Protected | PrivateLocal | Local | Final | Trait | Abstract // AbsOverride, Open + private[QuotesImpl] def validClassFlags: Flags = Private | Protected | PrivateLocal | Local | Final | Trait | Abstract | Open // Keep: aligned with Quote's 'newClass' - // Private constructor would be currently useless, but if we decide to add a way to register companions in the future it might be useful private[QuotesImpl] def validClassConstructorFlags: Flags = Synthetic | Method | Private | Protected | PrivateLocal | Local // Keep: aligned with Quotes's `newClass` diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 88e9f374ad97..0918f8c06b20 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3847,8 +3847,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => * Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors. * @param clsFlags extra flags with which the class symbol should be constructed. * @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol. - * @param conParamNames constructor parameter names. - * @param conParamTypes constructor parameter types. + * @param conParams constructor parameter pairs of names and types. * * Parameters assigned by the constructor can be obtained via `classSymbol.memberField`. * This symbol starts without an accompanying definition. @@ -3862,15 +3861,74 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => owner: Symbol, name: String, parents: Symbol => List[TypeRepr], - decls: Symbol => List[Symbol], selfType: Option[TypeRepr], + decls: Symbol => List[Symbol], + selfType: Option[TypeRepr], clsFlags: Flags, clsPrivateWithin: Symbol, - conParamNames: List[String], - conParamTypes: List[TypeRepr] + conParams: List[(String, TypeRepr)] ): Symbol /** Generates a new class symbol with a constructor of the shape signified by a passed PolyOrMethod parameter. - * TODO example with PolyType + * + * Example usage: + * ``` + * val name = "myClass" + * def decls(cls: Symbol): List[Symbol] = + * List(Symbol.newMethod(cls, "getParam", MethodType(Nil)(_ => Nil, _ => cls.typeMember("T").typeRef))) + * val conMethodType = + * (classType: TypeRepr) => PolyType(List("T"))(_ => List(TypeBounds.empty), polyType => + * MethodType(List("param"))((_: MethodType) => List(polyType.param(0)), (_: MethodType) => + * classType + * ) + * ) + * val cls = Symbol.newClass( + * Symbol.spliceOwner, + * name, + * parents = _ => List(TypeRepr.of[Object]), + * decls, + * selfType = None, + * clsFlags = Flags.EmptyFlags, + * clsPrivateWithin = Symbol.noSymbol, + * clsAnnotations = Nil, + * conMethodType, + * conFlags = Flags.EmptyFlags, + * conPrivateWithin = Symbol.noSymbol, + * conParamFlags = List(List(Flags.EmptyFlags), List(Flags.EmptyFlags)), + * conParamPrivateWithins = List(List(Symbol.noSymbol), List(Symbol.noSymbol)) + * ) + * + * val getParamSym = cls.declaredMethod("getParam").head + * def getParamRhs(): Option[Term] = + * val paramValue = This(cls).select(cls.fieldMember("param")).asExpr + * Some('{ println("Calling getParam"); $paramValue }.asTerm) + * val getParamDef = DefDef(getParamSym, _ => getParamRhs()) + * + * val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = List(getParamDef)) + * val newCls = + * Apply( + * Select( + * Apply( + * TypeApply(Select(New(TypeIdent(cls)), cls.primaryConstructor), List(TypeTree.of[String])), + * List(Expr("test").asTerm) + * ), + * cls.methodMember("getParam").head + * ), + * Nil + * ) + * + * Block(List(clsDef), newCls).asExpr + * ``` + * constructs the equivalent to + * ``` + * '{ + * class myClass[T](val param: T) { + * def getParam: T = + * println("Calling getParam") + * param + * } + * new myClass[String]("test").getParam() + * } + * ``` * * @param owner The owner of the class * @param name The name of the class @@ -3878,15 +3936,18 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => * Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors. * @param decls The member declarations of the class provided the symbol of this class * @param selfType The self type of the class if it has one - * @param clsFlags extra flags with which the class symbol should be constructed + * @param clsFlags extra flags with which the class symbol should be constructed. Can be `Private` | `Protected` | `PrivateLocal` | `Local` | `Final` | `Trait` | `Abstract` | `Open` * @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol * @param clsAnnotations annotations of the class * @param conMethodType Function returning MethodOrPoly type representing the type of the constructor. * Takes the result type as parameter which must be returned from the innermost MethodOrPoly. * PolyType may only represent the first clause of the constructor. - * @param conFlags extra flags with which the constructor symbol should be constructed + * @param conFlags extra flags with which the constructor symbol should be constructed. Can be `Synthetic` | `Method` | `Private` | `Protected` | `PrivateLocal` | `Local` * @param conPrivateWithin the symbol within which the constructor for this new class symbol should be private. May be noSymbol. * @param conParamFlags extra flags with which the constructor parameter symbols should be constructed. Must match the shape of `conMethodType`. + * For type parameters those can be `Param` | `Deferred` | `Private` | `PrivateLocal` | `Local`. + * For term parameters those can be `ParamAccessor` | `Private` | `Protected` | `PrivateLocal` | `Local` + * @param conParamPrivateWithins the symbols within which the constructor parameters should be private. Must match the shape of `conMethodType`. Can consist of noSymbol. * * Term and type parameters assigned by the constructor can be obtained via `classSymbol.memberField`/`classSymbol.memberType`. * This symbol starts without an accompanying definition. @@ -3896,6 +3957,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => * @note As a macro can only splice code into the point at which it is expanded, all generated symbols must be * direct or indirect children of the reflection context's owner. */ + // Keep doc aligned with QuotesImpl's validFlags: `clsFlags` with `validClassFlags`, `conFlags` with `validClassConstructorFlags`, + // conParamFlags with `validClassTypeParamFlags` and `validClassTermParamFlags` @experimental def newClass( owner: Symbol, name: String, @@ -3908,7 +3971,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => conMethodType: TypeRepr => MethodOrPoly, conFlags: Flags, conPrivateWithin: Symbol, - conParamFlags: List[List[Flags]] + conParamFlags: List[List[Flags]], + conParamPrivateWithins: List[List[Symbol]] ): Symbol /** Generates a new module symbol with an associated module class symbol, diff --git a/tests/neg-macros/i19842-a.check b/tests/neg-macros/i19842-a.check index cdf0921f1087..49dd95b6e09f 100644 --- a/tests/neg-macros/i19842-a.check +++ b/tests/neg-macros/i19842-a.check @@ -9,8 +9,8 @@ | | at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8) | at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:210) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:278) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:277) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:284) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:283) | at Macros$.makeSerializer(Macro.scala:25) | |--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i19842-b.check b/tests/neg-macros/i19842-b.check index 8039f278d2af..b93df5c05035 100644 --- a/tests/neg-macros/i19842-b.check +++ b/tests/neg-macros/i19842-b.check @@ -9,8 +9,8 @@ | | at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8) | at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:210) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:278) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:277) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:284) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:283) | at Macros$.makeSerializer(Macro.scala:27) | |--------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala b/tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala index 41dd9bcdda34..a0ee5a899e62 100644 --- a/tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala +++ b/tests/neg-macros/newClassParamsMissingArgument/Macro_1.scala @@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Object] = val parents = List(TypeTree.of[Object]) def decls(cls: Symbol): List[Symbol] = Nil - val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int])) + val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int]))) val clsDef = ClassDef(cls, parents, body = Nil) val newCls = Typed(Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil), TypeTree.of[Object]) diff --git a/tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala b/tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala index c1483ac8f182..569d8e0c25be 100644 --- a/tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala +++ b/tests/pos-macros/newClassExtendsWithSymbolInParent/Macro_1.scala @@ -13,7 +13,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Foo[_]] = List(AppliedType(TypeRepr.typeConstructorOf(Class.forName("Foo")), List(TypeIdent(cls).tpe))) def decls(cls: Symbol): List[Symbol] = Nil - val cls = Symbol.newClass(Symbol.spliceOwner, name, parents, decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, conParamNames = Nil, conParamTypes = Nil) + val cls = Symbol.newClass(Symbol.spliceOwner, name, parents, decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, conParams = Nil) val parentsWithSym = cls.typeRef.asType match diff --git a/tests/run-macros/newClassAnnotation/Macro_1.scala b/tests/run-macros/newClassAnnotation/Macro_1.scala index 4192a5c61dd5..c7631317675b 100644 --- a/tests/run-macros/newClassAnnotation/Macro_1.scala +++ b/tests/run-macros/newClassAnnotation/Macro_1.scala @@ -31,7 +31,8 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Any] = { conMethodType, conFlags = Flags.EmptyFlags, conPrivateWithin = Symbol.noSymbol, - conParamFlags = List(List()) + conParamFlags = List(List()), + conParamPrivateWithins = List(List()) ) val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = Nil) diff --git a/tests/run-macros/newClassExtendsJavaClass/Macro_1.scala b/tests/run-macros/newClassExtendsJavaClass/Macro_1.scala index b19210d092ab..c342c78da796 100644 --- a/tests/run-macros/newClassExtendsJavaClass/Macro_1.scala +++ b/tests/run-macros/newClassExtendsJavaClass/Macro_1.scala @@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[JavaClass[ val parents = List(TypeTree.of[JavaClass[Int]]) def decls(cls: Symbol): List[Symbol] = Nil - val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int])) + val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int]))) 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"))))) val clsDef = ClassDef(cls, parentsWithSym, body = Nil) diff --git a/tests/run-macros/newClassParams/Macro_1.scala b/tests/run-macros/newClassParams/Macro_1.scala index 3e3b9d1e0894..5090fd7a0116 100644 --- a/tests/run-macros/newClassParams/Macro_1.scala +++ b/tests/run-macros/newClassParams/Macro_1.scala @@ -10,7 +10,7 @@ private def makeClassAndCallExpr(nameExpr: Expr[String], idxExpr: Expr[Int], str def decls(cls: Symbol): List[Symbol] = List(Symbol.newMethod(cls, "foo", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]))) val parents = List(TypeTree.of[Object]) - 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])) + 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]))) 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)) val clsDef = ClassDef(cls, parents, body = List(fooDef)) diff --git a/tests/run-macros/newClassParamsExtendsClassParams/Macro_1.scala b/tests/run-macros/newClassParamsExtendsClassParams/Macro_1.scala index 1cf0110c7936..de35a4dfa206 100644 --- a/tests/run-macros/newClassParamsExtendsClassParams/Macro_1.scala +++ b/tests/run-macros/newClassParamsExtendsClassParams/Macro_1.scala @@ -10,7 +10,7 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Foo] = { val parents = List('{ new Foo(1) }.asTerm) def decls(cls: Symbol): List[Symbol] = Nil - val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List("idx"), List(TypeRepr.of[Int])) + val cls = Symbol.newClass(Symbol.spliceOwner, name, parents = _ => parents.map(_.tpe), decls, selfType = None, Flags.EmptyFlags, Symbol.noSymbol, List(("idx", TypeRepr.of[Int]))) val parentsWithSym = List(Apply(Select(New(TypeTree.of[Foo]), TypeRepr.of[Foo].typeSymbol.primaryConstructor), List(Ref(cls.fieldMember("idx"))))) val clsDef = ClassDef(cls, parentsWithSym, body = Nil) diff --git a/tests/run-macros/newClassTraitAndAbstract/Macro_1.scala b/tests/run-macros/newClassTraitAndAbstract/Macro_1.scala index e92b40a4045b..3a285c7e22dc 100644 --- a/tests/run-macros/newClassTraitAndAbstract/Macro_1.scala +++ b/tests/run-macros/newClassTraitAndAbstract/Macro_1.scala @@ -44,10 +44,12 @@ private def makeClassExpr(using Quotes)( selfType = None, clsFlags, clsPrivateWithin = Symbol.noSymbol, + clsAnnotations = Nil, conMethodType, conFlags = Flags.EmptyFlags, conPrivateWithin = Symbol.noSymbol, - conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags)) + conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags)), + conParamPrivateWithins = List(List(Symbol.noSymbol, Symbol.noSymbol), List(Symbol.noSymbol, Symbol.noSymbol)) ) val traitDef = ClassDef(traitSymbol, List(TypeTree.of[Object]), body = Nil) @@ -60,10 +62,12 @@ private def makeClassExpr(using Quotes)( selfType = None, clsFlags = Flags.EmptyFlags, clsPrivateWithin = Symbol.noSymbol, + clsAnnotations = Nil, conMethodType = (classType: TypeRepr) => MethodType(Nil)(_ => Nil, _ => classType), conFlags = Flags.EmptyFlags, conPrivateWithin = Symbol.noSymbol, - conParamFlags = List(List()) + conParamFlags = List(List()), + conParamPrivateWithins = List(List(Symbol.noSymbol, Symbol.noSymbol), List(Symbol.noSymbol, Symbol.noSymbol)) ) val obj = '{new java.lang.Object()}.asTerm match case Inlined(_, _, term) => term diff --git a/tests/run-macros/newClassTypeParamDoc.check b/tests/run-macros/newClassTypeParamDoc.check new file mode 100644 index 000000000000..5d3b08bf509c --- /dev/null +++ b/tests/run-macros/newClassTypeParamDoc.check @@ -0,0 +1,2 @@ +Calling getParam +test diff --git a/tests/run-macros/newClassTypeParamDoc/Macro_1.scala b/tests/run-macros/newClassTypeParamDoc/Macro_1.scala new file mode 100644 index 000000000000..e3186f6b2e18 --- /dev/null +++ b/tests/run-macros/newClassTypeParamDoc/Macro_1.scala @@ -0,0 +1,63 @@ +//> using options -experimental + +import scala.quoted.* + +transparent inline def makeClass(): Any = ${ makeClassExpr } +private def makeClassExpr(using Quotes): Expr[Any] = { + import quotes.reflect.* + + val name = "myClass" + def decls(cls: Symbol): List[Symbol] = + List(Symbol.newMethod(cls, "getParam", MethodType(Nil)(_ => Nil, _ => cls.typeMember("T").typeRef))) + val conMethodType = + (classType: TypeRepr) => PolyType(List("T"))(_ => List(TypeBounds.empty), polyType => + MethodType(List("param"))((_: MethodType) => List(polyType.param(0)), (_: MethodType) => + classType + ) + ) + val cls = Symbol.newClass( + Symbol.spliceOwner, + name, + parents = _ => List(TypeRepr.of[Object]), + decls, + selfType = None, + clsFlags = Flags.EmptyFlags, + clsPrivateWithin = Symbol.noSymbol, + clsAnnotations = Nil, + conMethodType, + conFlags = Flags.EmptyFlags, + conPrivateWithin = Symbol.noSymbol, + conParamFlags = List(List(Flags.EmptyFlags), List(Flags.EmptyFlags)), + conParamPrivateWithins = List(List(Symbol.noSymbol), List(Symbol.noSymbol)) + ) + + val getParamSym = cls.declaredMethod("getParam").head + def getParamRhs(): Option[Term] = + val paramValue = This(cls).select(cls.fieldMember("param")).asExpr + Some('{ println("Calling getParam"); $paramValue }.asTerm) + val getParamDef = DefDef(getParamSym, _ => getParamRhs()) + + val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = List(getParamDef)) + val newCls = + Apply( + Select( + Apply( + TypeApply(Select(New(TypeIdent(cls)), cls.primaryConstructor), List(TypeTree.of[String])), + List(Expr("test").asTerm) + ), + cls.methodMember("getParam").head + ), + Nil + ) + + Block(List(clsDef), newCls).asExpr + + // '{ + // class myClass[T](val param: T) { + // def getParam: T = + // println("Calling getParam") + // param + // } + // new myClass[String]("test").getParam() + // } +} diff --git a/tests/run-macros/newClassTypeParamDoc/Test_2.scala b/tests/run-macros/newClassTypeParamDoc/Test_2.scala new file mode 100644 index 000000000000..318db32242fc --- /dev/null +++ b/tests/run-macros/newClassTypeParamDoc/Test_2.scala @@ -0,0 +1,5 @@ +//> using options -experimental + +@main def Test: Unit = { + println(makeClass()) +} diff --git a/tests/run-macros/newClassTypeParams/Macro_1.scala b/tests/run-macros/newClassTypeParams/Macro_1.scala index c843511d7eda..3d0a9b61bf7e 100644 --- a/tests/run-macros/newClassTypeParams/Macro_1.scala +++ b/tests/run-macros/newClassTypeParams/Macro_1.scala @@ -22,10 +22,12 @@ private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Any] = { selfType = None, clsFlags = Flags.EmptyFlags, clsPrivateWithin = Symbol.noSymbol, + clsAnnotations = Nil, conMethodType, conFlags = Flags.EmptyFlags, conPrivateWithin = Symbol.noSymbol, - conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags)) + conParamFlags = List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags)), + conParamPrivateWithins = List(List(Symbol.noSymbol, Symbol.noSymbol), List(Symbol.noSymbol, Symbol.noSymbol)) ) val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = Nil)