diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 81fadb6baa89..ab763fbf47e5 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2613,6 +2613,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def newBind(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol = checkValidFlags(flags.toTermFlags, Flags.validBindFlags) dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Case, tpe) + + def newType(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr, privateWithin: Symbol): Symbol = + checkValidFlags(flags.toTypeFlags, Flags.validTypeFlags) + dotc.core.Symbols.newSymbol(owner, name.toTypeName, flags | dotc.core.Flags.Deferred, tpe, privateWithin) + def noSymbol: Symbol = dotc.core.Symbols.NoSymbol private inline def checkValidFlags(inline flags: Flags, inline valid: Flags): Unit = @@ -2953,6 +2958,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler // Keep: aligned with Quotes's `newBind` doc private[QuotesImpl] def validBindFlags: Flags = Case // Flags that could be allowed: Implicit | Given | Erased + + private[QuotesImpl] def validTypeFlags: Flags = Private | Protected | Override | Deferred | Final | Infix | Local + end Flags given FlagsMethods: FlagsMethods with diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 2c2d35d6cf44..e0715a0a921d 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3915,6 +3915,23 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => // Keep: `flags` doc aligned with QuotesImpl's `validBindFlags` def newBind(parent: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol + /** Generate a new type symbol with the given parent, name and type + * + * This symbol starts without an accompanying definition. + * It is the meta-programmer's responsibility to provide exactly one corresponding definition by passing + * this symbol to the TypeDef constructor. + * + * @param parent The owner of the type + * @param name The name of the type + * @param flags extra flags to with which symbol can be constructed. `Deferred` flag will be added. Can be `Private` | `Protected` | `Override` | `Deferred` | `Final` | `Infix` | `Local` + * @param tpe The rhs or bounds of the type + * @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. + */ + @experimental + // Keep: `flags` doc aligned with QuotesImpl's `validTypeFlags` + def newType(parent: Symbol, name: String, flags: Flags, tpe: TypeRepr, privateWithin: Symbol): Symbol + /** Definition not available */ def noSymbol: Symbol diff --git a/tests/pos-macros/quoted-sym-newtype/Macro_1.scala b/tests/pos-macros/quoted-sym-newtype/Macro_1.scala new file mode 100644 index 000000000000..bb41c82553d6 --- /dev/null +++ b/tests/pos-macros/quoted-sym-newtype/Macro_1.scala @@ -0,0 +1,10 @@ +import scala.quoted.* + +inline def testMacro = ${ testImpl } + +def testImpl(using Quotes): Expr[Unit] = { + import quotes.reflect.* + val sym = Symbol.newType(Symbol.spliceOwner, "mytype", Flags.EmptyFlags, TypeRepr.of[String], Symbol.noSymbol) + assert(TypeDef(sym).show == "type mytype = java.lang.String") + '{ () } +} \ No newline at end of file diff --git a/tests/pos-macros/quoted-sym-newtype/Test_2.scala b/tests/pos-macros/quoted-sym-newtype/Test_2.scala new file mode 100644 index 000000000000..506f836ab4a5 --- /dev/null +++ b/tests/pos-macros/quoted-sym-newtype/Test_2.scala @@ -0,0 +1,2 @@ + +def test = testMacro \ No newline at end of file