Skip to content

Commit c2d8e84

Browse files
authored
Fix regression #23969: Add ensureApplied to the quotes reflect API (#24160)
Fixes #23969 The regression would not appear on main (only after release on the nightly version of the compiler, as explained [here](#23969 (comment))), so I've adjusted the test to be more general.
2 parents ec60015 + b145f7d commit c2d8e84

File tree

7 files changed

+55
-8
lines changed

7 files changed

+55
-8
lines changed

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
484484
argss.foldLeft(self: Term)(Apply(_, _))
485485
def appliedToNone: Apply =
486486
self.appliedToArgs(Nil)
487+
def ensureApplied: Term =
488+
def isParameterless(tpe: TypeRepr): Boolean = !tpe.isInstanceOf[MethodType]
489+
if (isParameterless(self.tpe.widen)) self else self.appliedToNone
487490
def appliedToType(targ: TypeRepr): Term =
488491
self.appliedToTypes(targ :: Nil)
489492
def appliedToTypes(targs: List[TypeRepr]): Term =

library/src/scala/quoted/Quotes.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
890890
/** The current tree applied to (): `tree()` */
891891
def appliedToNone: Apply
892892

893+
/** The current tree applied to `()` unless the tree's widened type is parameterless or expects type parameters */
894+
def ensureApplied: Term
895+
893896
/** The current tree applied to given type argument: `tree[targ]` */
894897
def appliedToType(targ: TypeRepr): Term
895898

project/MiMaFilters.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ object MiMaFilters {
140140
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ValDefModule.let"),
141141
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolModule.newClass"),
142142
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolModule.newModule"),
143+
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#TermMethods.ensureApplied"),
143144

144145
// Changes to lazy vals (added static constructors)
145146
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Tuple.<clinit>"),

tests/neg-macros/i23008.check

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,6 @@
33
| ^^^^^^^^^^^^^^^^^^
44
| Exception occurred while executing macro expansion.
55
| java.lang.IllegalArgumentException: requirement failed: value of StringConstant cannot be `null`
6-
| at scala.Predef$.require(Predef.scala:394)
7-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2542)
8-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2541)
9-
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:82)
10-
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:80)
11-
| at scala.quoted.Expr$.apply(Expr.scala:72)
12-
| at Macros$.buildStringCode(Macro_1.scala:9)
136
|
147
|---------------------------------------------------------------------------------------------------------------------
158
|Inline stack trace

tests/neg-macros/i23008/Macro_1.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ object Macros {
66
def buildStringCode(using Quotes): Expr[String] = {
77
import quotes.reflect.*
88
val str: String = null
9-
Expr(str)
9+
try
10+
Expr(str)
11+
catch
12+
case error: java.lang.IllegalArgumentException =>
13+
error.setStackTrace(Array[StackTraceElement]())
14+
throw error
1015
}
1116
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
import scala.quoted._
3+
4+
object TestMethods:
5+
def a1 = ()
6+
def a2() = ()
7+
def a3[T] = ()
8+
def a4[T]() = ()
9+
10+
transparent inline def runMacro() = ${runMacroImpl}
11+
def runMacroImpl(using Quotes): Expr[Any] =
12+
import quotes.reflect._
13+
14+
// ensureApplied test
15+
Select.unique('{TestMethods}.asTerm, "a1").ensureApplied match
16+
case Select(_, _) =>
17+
case _ => assert(false)
18+
Select.unique('{TestMethods}.asTerm, "a2").ensureApplied match
19+
case Apply(_, _) =>
20+
case _ => assert(false)
21+
Select.unique('{TestMethods}.asTerm, "a3").ensureApplied match
22+
case Select(_, _) =>
23+
case other => assert(false)
24+
Select.unique('{TestMethods}.asTerm, "a4").ensureApplied match
25+
case Select(_, _) =>
26+
case other => assert(false)
27+
28+
TypeApply(Select.unique('{TestMethods}.asTerm, "a3"), List(TypeTree.of[Nothing])).ensureApplied match
29+
case TypeApply(_, _) =>
30+
case other => assert(false)
31+
TypeApply(Select.unique('{TestMethods}.asTerm, "a4"), List(TypeTree.of[Nothing])).ensureApplied match
32+
case Apply(_, _) =>
33+
case other => assert(false)
34+
35+
// regression test
36+
val Inlined(_, _, generated) = '{BigDecimal(0).toString()}.asTerm : @unchecked
37+
val Inlined(_, _, bigDecimal) = '{BigDecimal(0)}.asTerm : @unchecked
38+
val custom = Select.unique(bigDecimal, "toString").ensureApplied
39+
// ensure both have the same shape
40+
assert(custom.toString == generated.toString)
41+
custom.asExpr

tests/pos-macros/i23969/Main.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@main def Test() = runMacro()

0 commit comments

Comments
 (0)