diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 1501b07c6bde..64ae02f2c3ee 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -266,6 +266,21 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end extension end ClassDefMethods + type ValOrDefDef = tpd.ValOrDefDef + + object ValOrDefDefTypeTest extends TypeTest[Tree, ValOrDefDef]: + def unapply(x: Tree): Option[ValOrDefDef & x.type] = x match + case x: (tpd.ValOrDefDef & x.type) => Some(x) + case _ => None + end ValOrDefDefTypeTest + + given ValOrDefDefMethods: ValOrDefDefMethods with + extension (self: ValOrDefDef) + def tpt: TypeTree = self.tpt + def rhs: Option[Term] = optional(self.rhs) + end extension + end ValOrDefDefMethods + type DefDef = tpd.DefDef object DefDefTypeTest extends TypeTest[Tree, DefDef]: diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 321725d4e84c..0ca8765a785b 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -116,8 +116,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => * | +- Export * | +- Definition --+- ClassDef * | | +- TypeDef - * | | +- DefDef - * | | +- ValDef + * | | +- ValOrDefDef -+- DefDef + * | | +- ValDef * | | * | +- Term --------+- Ref -+- Ident -+- Wildcard * | | +- Select @@ -532,10 +532,33 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => end extension end ClassDefMethods + // ValOrDefDef + + /** Tree representing a value or method definition in the source code. + * This includes `def`, `val`, `lazy val`, `var`, `object` and parameter definitions. + */ + type ValOrDefDef <: Definition + + /** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `ValOrDefDef` */ + given ValOrDefDefTypeTest: TypeTest[Tree, ValOrDefDef] + + /** Makes extension methods on `ValOrDefDef` available without any imports */ + given ValOrDefDefMethods: ValOrDefDefMethods + + /** Extension methods of `ValOrDefDef` */ + trait ValOrDefDefMethods: + extension (self: ValOrDefDef) + /** The type tree of this `val` or `def` definition */ + def tpt: TypeTree + /** The right-hand side of this `val` or `def` definition */ + def rhs: Option[Term] + end extension + end ValOrDefDefMethods + // DefDef /** Tree representing a method definition in the source code */ - type DefDef <: Definition + type DefDef <: ValOrDefDef /** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `DefDef` */ given DefDefTypeTest: TypeTest[Tree, DefDef] @@ -611,8 +634,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => // ValDef - /** Tree representing a value definition in the source code This includes `val`, `lazy val`, `var`, `object` and parameter definitions. */ - type ValDef <: Definition + /** Tree representing a value definition in the source code. This includes `val`, `lazy val`, `var`, `object` and parameter definitions. */ + type ValDef <: ValOrDefDef /** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `ValDef` */ given ValDefTypeTest: TypeTest[Tree, ValDef] diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 8af2de7058ee..55b498f5bcbb 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -26,6 +26,14 @@ object MiMaFilters { ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language#experimental.into"), ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$experimental$into$"), // end of New experimental features in 3.3.X + + // New API in 3.4.X + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.ValOrDefDefTypeTest"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.ValOrDefDefMethods"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule.ValOrDefDefTypeTest"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule.ValOrDefDefMethods"), + ProblemFilters.exclude[MissingClassProblem]("scala.quoted.Quotes$reflectModule$ValOrDefDefMethods"), + // New API in 3.4.X ) val TastyCore: Seq[ProblemFilter] = Seq( ProblemFilters.exclude[DirectMissingMethodProblem]("dotty.tools.tasty.TastyBuffer.reset"), diff --git a/tests/pos-macros/i16960/Macro_1.scala b/tests/pos-macros/i16960/Macro_1.scala new file mode 100644 index 000000000000..664623a82c41 --- /dev/null +++ b/tests/pos-macros/i16960/Macro_1.scala @@ -0,0 +1,29 @@ +import scala.quoted.* + +inline def myMacro = ${ myMacroImpl } +def myMacroImpl(using Quotes) = + import quotes.reflect.* + + val valSym = Symbol.newVal(Symbol.spliceOwner, "foo", TypeRepr.of[Int], Flags.EmptyFlags, Symbol.noSymbol) + val vdef = ValDef(valSym, None) + vdef match + case _: ValDef => + assert(vdef.tpt.tpe =:= TypeRepr.of[Int]) + assert(vdef.rhs == None) + vdef match + case vdef: ValOrDefDef => + assert(vdef.tpt.tpe =:= TypeRepr.of[Int]) + assert(vdef.rhs == None) + + val methSym = Symbol.newMethod(Symbol.spliceOwner, "bar", ByNameType(TypeRepr.of[Int])) + val ddef = DefDef(methSym, _ => None) + ddef match + case _: DefDef => + assert(ddef.tpt.tpe =:= TypeRepr.of[Int]) + assert(ddef.rhs == None) + ddef match + case ddef: ValOrDefDef => + assert(ddef.tpt.tpe =:= TypeRepr.of[Int]) + assert(ddef.rhs == None) + + '{} diff --git a/tests/pos-macros/i16960/Test_2.scala b/tests/pos-macros/i16960/Test_2.scala new file mode 100644 index 000000000000..76a9e17659db --- /dev/null +++ b/tests/pos-macros/i16960/Test_2.scala @@ -0,0 +1 @@ +def test = myMacro