Skip to content

Commit 81cea85

Browse files
committed
Allow to add type parameters to newClass
1 parent 8265c21 commit 81cea85

File tree

13 files changed

+220
-35
lines changed

13 files changed

+220
-35
lines changed

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

+99-16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import scala.quoted.runtime.impl.printers.*
2525
import scala.reflect.TypeTest
2626
import dotty.tools.dotc.core.NameKinds.ExceptionBinderName
2727
import dotty.tools.dotc.transform.TreeChecker
28+
import dotty.tools.dotc.core.Names
2829

2930
object QuotesImpl {
3031

@@ -243,15 +244,21 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
243244
def apply(cls: Symbol, parents: List[Tree], body: List[Statement]): ClassDef =
244245
val paramsDefs: List[untpd.ParamClause] =
245246
cls.primaryConstructor.paramSymss.map { paramSym =>
246-
paramSym.map( symm =>
247-
ValDef(symm, None)
248-
)
247+
if paramSym.headOption.map(_.isType).getOrElse(false) then
248+
paramSym.map(sym => TypeDef(sym))
249+
else
250+
paramSym.map(ValDef(_, None))
249251
}
250252
val paramsAccessDefs: List[untpd.ParamClause] =
251253
cls.primaryConstructor.paramSymss.map { paramSym =>
252-
paramSym.map( symm =>
253-
ValDef(cls.fieldMember(symm.name.toString()), None) // TODO I don't like the toString here
254-
)
254+
if paramSym.headOption.map(_.isType).getOrElse(false) then
255+
paramSym.map { symm =>
256+
TypeDef(cls.typeMember(symm.name.toString()))
257+
}
258+
else
259+
paramSym.map { symm =>
260+
ValDef(cls.fieldMember(symm.name.toString()), None)// TODO I don't like the toString here
261+
}
255262
}
256263

257264
val termSymbol: dotc.core.Symbols.TermSymbol = cls.primaryConstructor.asTerm
@@ -406,7 +413,6 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
406413
case x: (tpd.NamedArg & x.type) => Some(x)
407414
case x: (tpd.Typed & x.type) =>
408415
TypedTypeTest.unapply(x) // Matches `Typed` but not `TypedOrTest`
409-
case x: (tpd.TypeDef & x.type) => Some(x)
410416
case _ => if x.isTerm then Some(x) else None
411417
end TermTypeTest
412418

@@ -2620,10 +2626,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26202626
def requiredMethod(path: String): Symbol = dotc.core.Symbols.requiredMethod(path)
26212627
def classSymbol(fullName: String): Symbol = dotc.core.Symbols.requiredClass(fullName)
26222628

2623-
def newClass(parent: Symbol, name: String, parents: List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr]): Symbol =
2629+
def newClass(owner: Symbol, name: String, parents: List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr]): Symbol =
26242630
assert(parents.nonEmpty && !parents.head.typeSymbol.is(dotc.core.Flags.Trait), "First parent must be a class")
26252631
val cls = dotc.core.Symbols.newNormalizedClassSymbol(
2626-
parent,
2632+
owner,
26272633
name.toTypeName,
26282634
dotc.core.Flags.EmptyFlags,
26292635
parents,
@@ -2633,19 +2639,96 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
26332639
for sym <- decls(cls) do cls.enter(sym)
26342640
cls
26352641

2636-
def newClass(parent: Symbol, name: String, parents: Symbol => List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr], paramNames: List[String], paramTypes: List[TypeRepr], flags: Flags, privateWithin: Symbol): Symbol =
2637-
checkValidFlags(flags.toTermFlags, Flags.validClassFlags)
2638-
assert(!privateWithin.exists || privateWithin.isType, "privateWithin must be a type symbol or `Symbol.noSymbol`")
2642+
def newClass(
2643+
owner: Symbol,
2644+
name: String,
2645+
parents: Symbol => List[TypeRepr],
2646+
decls: Symbol => List[Symbol],
2647+
selfType: Option[TypeRepr],
2648+
paramNames: List[String],
2649+
paramTypes: List[TypeRepr],
2650+
clsFlags: Flags,
2651+
clsPrivateWithin: Symbol
2652+
): Symbol =
2653+
checkValidFlags(clsFlags.toTermFlags, Flags.validClassFlags)
2654+
assert(paramNames.length == paramTypes.length, "paramNames and paramTypes must have the same length")
2655+
assert(!clsPrivateWithin.exists || clsPrivateWithin.isType, "clsPrivateWithin must be a type symbol or `Symbol.noSymbol`")
26392656
val cls = dotc.core.Symbols.newNormalizedClassSymbolUsingClassSymbolinParents(
2640-
parent,
2657+
owner,
26412658
name.toTypeName,
2642-
flags,
2659+
clsFlags,
26432660
parents,
26442661
selfType.getOrElse(Types.NoType),
2645-
privateWithin)
2662+
clsPrivateWithin)
26462663
cls.enter(dotc.core.Symbols.newConstructor(cls, dotc.core.Flags.Synthetic, paramNames.map(_.toTermName), paramTypes))
26472664
for (name, tpe) <- paramNames.zip(paramTypes) do
2648-
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor, tpe, Symbol.noSymbol)) // add other flags (local, private, privatelocal) and set privateWithin
2665+
cls.enter(dotc.core.Symbols.newSymbol(cls, name.toTermName, Flags.ParamAccessor, tpe, Symbol.noSymbol))
2666+
for sym <- decls(cls) do cls.enter(sym)
2667+
cls
2668+
2669+
def newClass(
2670+
owner: Symbol,
2671+
name: String,
2672+
parents: Symbol => List[TypeRepr],
2673+
decls: Symbol => List[Symbol],
2674+
selfType: Option[TypeRepr],
2675+
constructorMethodType: TypeRepr => MethodOrPoly,
2676+
clsFlags: Flags,
2677+
clsPrivateWithin: Symbol,
2678+
consFlags: Flags,
2679+
consPrivateWithin: Symbol,
2680+
consParamFlags: List[List[Flags]]
2681+
) =
2682+
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)
2685+
val cls = dotc.core.Symbols.newNormalizedClassSymbolUsingClassSymbolinParents(
2686+
owner,
2687+
name.toTypeName,
2688+
clsFlags,
2689+
parents,
2690+
selfType.getOrElse(Types.NoType),
2691+
clsPrivateWithin)
2692+
val methodType: MethodOrPoly = constructorMethodType(cls.typeRef)
2693+
def throwShapeException() = throw new Exception("Shapes of constructorMethodType and consParamFlags differ.")
2694+
def checkMethodOrPolyShape(checkedMethodType: TypeRepr, clauseIdx: Int): Unit =
2695+
checkedMethodType match
2696+
case PolyType(params, _, res) if clauseIdx == 0 =>
2697+
if (consParamFlags.length < clauseIdx) throwShapeException()
2698+
if (consParamFlags(clauseIdx).length != params.length) throwShapeException()
2699+
checkMethodOrPolyShape(res, clauseIdx + 1)
2700+
case PolyType(_, _, _) => throw new Exception("Clause interleaving not supported for constructors")
2701+
case MethodType(params, _, res) =>
2702+
if (consParamFlags.length < clauseIdx) throwShapeException()
2703+
if (consParamFlags(clauseIdx).length != params.length) throwShapeException()
2704+
checkMethodOrPolyShape(res, clauseIdx + 1)
2705+
case _ =>
2706+
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
2708+
def getParamAccessors(methodType: TypeRepr, clauseIdx: Int): List[((String, TypeRepr, Boolean, Int), Int)] =
2709+
methodType match
2710+
case MethodType(paramInfosExp, resultTypeExp, res) =>
2711+
paramInfosExp.zip(resultTypeExp).map(_ :* false :* clauseIdx).zipWithIndex ++ getParamAccessors(res, clauseIdx + 1)
2712+
case pt @ PolyType(paramNames, paramBounds, res) =>
2713+
paramNames.zip(paramBounds).map(_ :* true :* clauseIdx).zipWithIndex ++ getParamAccessors(res, clauseIdx + 1)
2714+
case result =>
2715+
List()
2716+
// Maps PolyType indexes to type symbols
2717+
val paramRefMap = collection.mutable.HashMap[Int, Symbol]()
2718+
val paramRefRemapper = new Types.TypeMap {
2719+
def apply(tp: Types.Type) = tp match {
2720+
case pRef: ParamRef if pRef.binder == methodType => paramRefMap(pRef.paramNum).typeRef
2721+
case _ => mapOver(tp)
2722+
}
2723+
}
2724+
for ((name, tpe, isType, clauseIdx), elementIdx) <- getParamAccessors(methodType, 0) do
2725+
if isType then
2726+
val symbol = dotc.core.Symbols.newSymbol(cls, name.toTypeName, Flags.Param | Flags.Deferred | consParamFlags(clauseIdx)(elementIdx), tpe, Symbol.noSymbol)
2727+
paramRefMap.addOne(elementIdx, symbol)
2728+
cls.enter(symbol)
2729+
else
2730+
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
26492732
for sym <- decls(cls) do cls.enter(sym)
26502733
cls
26512734

Diff for: compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1379,13 +1379,13 @@ object SourceCode {
13791379
printTypeTree(bounds.low)
13801380
else
13811381
bounds.low match {
1382-
case Inferred() =>
1382+
case Inferred() if bounds.low.tpe.typeSymbol == TypeRepr.of[Nothing].typeSymbol =>
13831383
case low =>
13841384
this += " >: "
13851385
printTypeTree(low)
13861386
}
13871387
bounds.hi match {
1388-
case Inferred() => this
1388+
case Inferred() if bounds.hi.tpe.typeSymbol == TypeRepr.of[Any].typeSymbol => this
13891389
case hi =>
13901390
this += " <: "
13911391
printTypeTree(hi)

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

+52-8
Original file line numberDiff line numberDiff line change
@@ -3796,7 +3796,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
37963796
/** The class Symbol of a global class definition */
37973797
def classSymbol(fullName: String): Symbol
37983798

3799-
/** Generates a new class symbol for a class with a parameterless constructor.
3799+
/** Generates a new class symbol for a class with a public parameterless constructor.
38003800
*
38013801
* Example usage:
38023802
* ```
@@ -3824,7 +3824,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38243824
* }
38253825
* ```
38263826
*
3827-
* @param parent The owner of the class
3827+
* @param owner The owner of the class
38283828
* @param name The name of the class
38293829
* @param parents The parent classes of the class. The first parent must not be a trait.
38303830
* @param decls The member declarations of the class provided the symbol of this class
@@ -3840,17 +3840,61 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
38403840
// TODO: add flags and privateWithin
38413841
@experimental def newClass(owner: Symbol, name: String, parents: List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr]): Symbol
38423842

3843-
/**
3844-
* @param parent declerations of this class provided the symbol of this class.
3845-
* Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
3843+
/** Generates a new class symbol for a class with a public constructor.
3844+
*
3845+
* @param owner The owner of the class
3846+
* @param name The name of the class
3847+
* @param parents Function returning the parent classes of the class. The first parent must not be a trait.
3848+
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
38463849
* @param paramNames constructor parameter names.
38473850
* @param paramTypes constructor parameter types.
3848-
* @param flags extra flags with which the class symbol should be constructed.
3849-
* @param privateWithin the symbol within which this new method symbol should be private. May be noSymbol.
3851+
* @param clsFlags extra flags with which the class symbol should be constructed.
3852+
* @param clsPrivateWithin the symbol within which this new class symbol should be private. May be noSymbol.
38503853
*
38513854
* Parameters can be obtained via classSymbol.memberField
38523855
*/
3853-
@experimental def newClass(owner: Symbol, name: String, parents: Symbol => List[TypeRepr], decls: Symbol => List[Symbol], selfType: Option[TypeRepr], paramNames: List[String], paramTypes: List[TypeRepr], flags: Flags, privateWithin: Symbol): Symbol
3856+
@experimental def newClass(
3857+
owner: Symbol,
3858+
name: String,
3859+
parents: Symbol => List[TypeRepr],
3860+
decls: Symbol => List[Symbol], selfType: Option[TypeRepr],
3861+
paramNames: List[String],
3862+
paramTypes: List[TypeRepr],
3863+
clsFlags: Flags,
3864+
clsPrivateWithin: Symbol
3865+
): Symbol
3866+
3867+
/**
3868+
*
3869+
*
3870+
* @param owner The owner of the class
3871+
* @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.
3873+
* Takes the constructed class symbol as an argument. Calling `cls.typeRef.asType` as part of this function will lead to cyclic reference errors.
3874+
* @param decls The member declarations of the class provided the symbol of this class
3875+
* @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.
3879+
* @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
3883+
*
3884+
*/
3885+
@experimental def newClass(
3886+
owner: Symbol,
3887+
name: String,
3888+
parents: Symbol => List[TypeRepr],
3889+
decls: Symbol => List[Symbol],
3890+
selfType: Option[TypeRepr],
3891+
constructorMethodType: TypeRepr => MethodOrPoly,
3892+
clsFlags: Flags,
3893+
clsPrivateWithin: Symbol,
3894+
consFlags: Flags,
3895+
consPrivateWithin: Symbol,
3896+
conParamFlags: List[List[Flags]]
3897+
): Symbol
38543898

38553899
/** Generates a new module symbol with an associated module class symbol,
38563900
* this is equivalent to an `object` declaration in source code.

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:271)
13-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:270)
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)
1414
| at Macros$.makeSerializer(Macro.scala:25)
1515
|
1616
|---------------------------------------------------------------------------------------------------------------------

Diff for: tests/neg-macros/i19842-a/Macro.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object Macros {
1616
name,
1717
Flags.Implicit,
1818
Flags.EmptyFlags,
19-
List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
19+
_ => List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
2020
_ => Nil,
2121
Symbol.noSymbol
2222
)

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:271)
13-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:270)
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)
1414
| at Macros$.makeSerializer(Macro.scala:27)
1515
|
1616
|---------------------------------------------------------------------------------------------------------------------

Diff for: tests/neg-macros/i19842-b/Macro.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Macros {
1818
name,
1919
Flags.Implicit,
2020
Flags.EmptyFlags,
21-
List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
21+
_ => List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
2222
_ => Nil,
2323
Symbol.noSymbol
2424
)

Diff for: tests/run-macros/annot-add-global-object/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class addClass extends MacroAnnotation:
1414
def decls(cls: Symbol): List[Symbol] =
1515
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
1616

17-
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
17+
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, _ => parents.map(_.tpe), decls, Symbol.noSymbol)
1818
val cls = mod.moduleClass
1919

2020
val runSym = cls.declaredMethod("run").head

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class addClass extends MacroAnnotation:
1414
def decls(cls: Symbol): List[Symbol] =
1515
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
1616

17-
val mod = Symbol.newModule(Symbol.spliceOwner, "Baz", Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
17+
val mod = Symbol.newModule(Symbol.spliceOwner, "Baz", Flags.EmptyFlags, Flags.EmptyFlags, _ => parents.map(_.tpe), decls, Symbol.noSymbol)
1818
val cls = mod.moduleClass
1919

2020
val runSym = cls.declaredMethod("run").head

Diff for: tests/run-macros/annot-add-nested-object/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class addClass extends MacroAnnotation:
1414
def decls(cls: Symbol): List[Symbol] =
1515
List(Symbol.newMethod(cls, "run", MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Unit]), Flags.EmptyFlags, Symbol.noSymbol))
1616

17-
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, parents.map(_.tpe), decls, Symbol.noSymbol)
17+
val mod = Symbol.newModule(Symbol.spliceOwner, Symbol.freshName("Bar"), Flags.EmptyFlags, Flags.EmptyFlags, _ => parents.map(_.tpe), decls, Symbol.noSymbol)
1818
val cls = mod.moduleClass
1919

2020
val runSym = cls.declaredMethod("run").head

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

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Test_2$package$foo$1
2+
{
3+
class foo[A, B <: scala.Int](val param1: A, val param2: B) extends java.lang.Object
4+
5+
(new foo[java.lang.String, scala.Int]("test", 1): scala.Any)
6+
}

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

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//> using options -experimental
2+
3+
import scala.quoted.*
4+
5+
transparent inline def makeClass(inline name: String): Any = ${ makeClassExpr('name) }
6+
private def makeClassExpr(nameExpr: Expr[String])(using Quotes): Expr[Any] = {
7+
import quotes.reflect.*
8+
9+
val name = nameExpr.valueOrAbort
10+
def decls(cls: Symbol): List[Symbol] = Nil
11+
val constrType =
12+
(classType: TypeRepr) => PolyType(List("A", "B"))(
13+
_ => List(TypeBounds.empty, TypeBounds.upper(TypeRepr.of[Int])),
14+
polyType => MethodType(List("param1", "param2"))((_: MethodType) => List(polyType.param(0), polyType.param(1)), (_: MethodType) => classType)
15+
)
16+
17+
val cls = Symbol.newClass(
18+
Symbol.spliceOwner,
19+
name,
20+
parents = _ => List(TypeRepr.of[Object]),
21+
decls,
22+
selfType = None,
23+
constrType,
24+
Flags.EmptyFlags,
25+
Symbol.noSymbol,
26+
Flags.EmptyFlags,
27+
Symbol.noSymbol,
28+
List(List(Flags.EmptyFlags, Flags.EmptyFlags), List(Flags.EmptyFlags, Flags.EmptyFlags))
29+
)
30+
31+
val clsDef = ClassDef(cls, List(TypeTree.of[Object]), body = Nil)
32+
val newCls =
33+
cls.typeRef.asType match
34+
case '[t] =>
35+
Typed(Apply(TypeApply(Select(New(TypeIdent(cls)), cls.primaryConstructor), List(TypeTree.of[String], TypeTree.of[Int])), List(Expr("test").asTerm, Expr(1).asTerm)), TypeTree.of[Any])
36+
37+
val res = Block(List(clsDef), newCls).asExpr
38+
39+
Expr.ofTuple(res, Expr(res.show))
40+
41+
// '{
42+
// class `name`[A, B <: Int](param1: A, param2: B)
43+
// new `name`[String, Int]("a", 1)
44+
// }
45+
}

Diff for: tests/run-macros/newClassTypeParams/Test_2.scala

+7
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, show) = makeClass("foo")
5+
println(cls.getClass)
6+
println(show)
7+
}

0 commit comments

Comments
 (0)