diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index a4c7058f3e66..995ce6dd1397 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1244,6 +1244,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end TypeProjectionTypeTest object TypeProjection extends TypeProjectionModule: + def apply(qualifier: TypeTree, name: String): TypeProjection = + withDefaultPos(tpd.Select(qualifier, name.toTypeName)) def copy(original: Tree)(qualifier: TypeTree, name: String): TypeProjection = tpd.cpy.Select(original)(qualifier, name.toTypeName) def unapply(x: TypeProjection): (TypeTree, String) = @@ -1289,6 +1291,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end RefinedTypeTest object Refined extends RefinedModule: + def apply(tpt: TypeTree, refinements: List[Definition], refineCls: Symbol): Refined = // Symbol of the class being refined, according to which the refinements are typed + assert(refineCls.isClass, "refineCls must be a class/trait/object") + withDefaultPos(tpd.RefinedTypeTree(tpt, refinements, refineCls.asClass).asInstanceOf[tpd.RefinedTypeTree]) def copy(original: Tree)(tpt: TypeTree, refinements: List[Definition]): Refined = tpd.cpy.RefinedTypeTree(original)(tpt, refinements) def unapply(x: Refined): (TypeTree, List[Definition]) = diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 61902c1842f0..544981a59e11 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -1969,6 +1969,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val TypeProjection` */ trait TypeProjectionModule { this: TypeProjection.type => + def apply(qualifier: TypeTree, name: String): TypeProjection def copy(original: Tree)(qualifier: TypeTree, name: String): TypeProjection def unapply(x: TypeProjection): (TypeTree, String) } @@ -2021,6 +2022,13 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val Refined` */ trait RefinedModule { this: Refined.type => + /** Creates and types a Refined AST node. + * @param tpt - parent type being refined + * @param refinements - List of definitions represesenting refinements + * @param refineCls - symbol of the class of which the refinement definitions originally come from + * @return + */ + def apply(tpt: TypeTree, refinements: List[Definition], refineCls: Symbol): Refined def copy(original: Tree)(tpt: TypeTree, refinements: List[Definition]): Refined def unapply(x: Refined): (TypeTree, List[Definition]) } diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index 7e97b1a3b8c4..659090689fb0 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -17,7 +17,7 @@ object MiMaFilters { ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Conversion.underlying"), ProblemFilters.exclude[MissingClassProblem]("scala.Conversion$"), - ProblemFilters.exclude[MissingClassProblem]("scala.annotation.internal.RuntimeChecked"), + ProblemFilters.exclude[MissingClassProblem]("scala.annotation.internal.RuntimeChecked"), ProblemFilters.exclude[MissingClassProblem]("scala.annotation.stableNull"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.NamedTuple.namedTupleOrdering"), @@ -138,6 +138,8 @@ object MiMaFilters { ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#MethodTypeMethods.isContextual"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ImplicitsModule.searchIgnoring"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ValDefModule.let"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#RefinedModule.apply"), + ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TypeProjectionModule.apply"), // Change `experimental` annotation to a final class ProblemFilters.exclude[FinalClassProblem]("scala.annotation.experimental"), ), diff --git a/tests/neg-macros/i23008.check b/tests/neg-macros/i23008.check index c44f7cccb52a..00b91fe94b54 100644 --- a/tests/neg-macros/i23008.check +++ b/tests/neg-macros/i23008.check @@ -5,8 +5,8 @@ | Exception occurred while executing macro expansion. | java.lang.IllegalArgumentException: requirement failed: value of StringConstant cannot be `null` | at scala.Predef$.require(Predef.scala:337) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2540) - | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2539) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2545) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2544) | at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:82) | at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:80) | at scala.quoted.Expr$.apply(Expr.scala:72) diff --git a/tests/pos-macros/typedProjectionApply/Macro_1.scala b/tests/pos-macros/typedProjectionApply/Macro_1.scala new file mode 100644 index 000000000000..c6ff00e60d51 --- /dev/null +++ b/tests/pos-macros/typedProjectionApply/Macro_1.scala @@ -0,0 +1,19 @@ +import scala.quoted._ +class Test {type test = Int } +object Macro: + inline def inlineCall(): Any = ${impl} + transparent inline def transparentInlineCall(): Any = ${impl} + + /* Returns: + * val value: Test#test = 0 : Test#test + * value: Test#test + */ + def impl(using Quotes): Expr[Any] = + import quotes.reflect._ + val typeTree = TypeProjection(TypeTree.of[Test], "test") + val typeRepr = TypeRepr.of[Test#test] + val sym = Symbol.newVal(Symbol.spliceOwner, "value", typeRepr, Flags.EmptyFlags, Symbol.noSymbol) + Block( + List(ValDef(sym, Some(Typed(Literal(IntConstant(0)), typeTree)))), + Typed(Ref(sym), typeTree) + ).asExpr diff --git a/tests/pos-macros/typedProjectionApply/Test_2.scala b/tests/pos-macros/typedProjectionApply/Test_2.scala new file mode 100644 index 000000000000..5a2c34d039f9 --- /dev/null +++ b/tests/pos-macros/typedProjectionApply/Test_2.scala @@ -0,0 +1,4 @@ +import scala.quoted._ +def test() = + Macro.transparentInlineCall() + Macro.inlineCall() diff --git a/tests/run-macros/refined-apply/Macro_1.scala b/tests/run-macros/refined-apply/Macro_1.scala new file mode 100644 index 000000000000..ca736d34aafd --- /dev/null +++ b/tests/run-macros/refined-apply/Macro_1.scala @@ -0,0 +1,30 @@ +//> using options -experimental +import scala.quoted._ +class Foo { type test1; val test2: List[Any] = List() } +object Macro: + inline def inlineCall(): Any = ${impl} + transparent inline def transparentInlineCall(): Any = ${impl} + + def impl(using Quotes): Expr[Any] = + import quotes.reflect._ + val tpt = TypeTree.of[Foo] + + val typeDefSym = Symbol.newTypeAlias(Symbol.spliceOwner, "test1", Flags.EmptyFlags, TypeRepr.of[Int], Symbol.noSymbol) + val valDefSym = Symbol.newVal(Symbol.spliceOwner, "test2", TypeRepr.of[List[Int]], Flags.EmptyFlags, Symbol.noSymbol) + + val defs = List( + TypeDef(typeDefSym), + ValDef(valDefSym, None) + ) + val typeTree = Refined(tpt, defs, TypeRepr.of[Foo].typeSymbol) + + // A little redundant, but we only want to see if Refined.apply() works, + // so we only replace the type with one we just constructed + val body = '{ + new Foo { type test1 = Int; override val test2: List[Int] = List(0) } + } + val blockWithNewTypeTree = body.asTerm match + case Inlined(_, _, Block(cDef : ClassDef, Typed(invocation, _))) => + Block(cDef, Typed(invocation, typeTree)) + + blockWithNewTypeTree.asExpr diff --git a/tests/run-macros/refined-apply/Main_2.scala b/tests/run-macros/refined-apply/Main_2.scala new file mode 100644 index 000000000000..79277a576810 --- /dev/null +++ b/tests/run-macros/refined-apply/Main_2.scala @@ -0,0 +1,9 @@ +//> using options -experimental + +import scala.quoted._ +def testInt(i: Int) = () +@main def Test(): Unit = + val withType = Macro.transparentInlineCall() + summon[withType.test1 <:< Int] + withType.test2.map(testInt) + Macro.inlineCall()