Skip to content

Commit 99b24d7

Browse files
authored
Add missing version of ValDef.let which also accepts flags to Quotes API (#23388)
2 parents cc459d6 + e0a5bb6 commit 99b24d7

File tree

7 files changed

+48
-5
lines changed

7 files changed

+48
-5
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,12 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
369369
def unapply(vdef: ValDef): (String, TypeTree, Option[Term]) =
370370
(vdef.name.toString, vdef.tpt, optional(vdef.rhs))
371371

372+
def let(owner: Symbol, name: String, rhs: Term, flags: Flags)(body: Ref => Term): Term =
373+
Symbol.checkValidFlags(flags.toTermFlags, Flags.validValInLetFlags)
374+
val vdef = tpd.SyntheticValDef(name.toTermName, rhs, flags)(using ctx.withOwner(owner))
375+
val ref = tpd.ref(vdef.symbol).asInstanceOf[Ref]
376+
Block(List(vdef), body(ref))
377+
372378
def let(owner: Symbol, name: String, rhs: Term)(body: Ref => Term): Term =
373379
val vdef = tpd.SyntheticValDef(name.toTermName, rhs)(using ctx.withOwner(owner))
374380
val ref = tpd.ref(vdef.symbol).asInstanceOf[Ref]
@@ -2863,7 +2869,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
28632869

28642870
def noSymbol: Symbol = dotc.core.Symbols.NoSymbol
28652871

2866-
private inline def checkValidFlags(inline flags: Flags, inline valid: Flags): Unit =
2872+
private[QuotesImpl] inline def checkValidFlags(inline flags: Flags, inline valid: Flags): Unit =
28672873
xCheckMacroAssert(
28682874
flags <= valid,
28692875
s"Received invalid flags. Expected flags ${flags.show} to only contain a subset of ${valid.show}."
@@ -3250,7 +3256,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
32503256
private[QuotesImpl] def validMethodFlags: Flags = Private | Protected | Override | Deferred | Final | Method | Implicit | Given | Local | AbsOverride | JavaStatic | Synthetic | Artifact // Flags that could be allowed: Synthetic | ExtensionMethod | Exported | Erased | Infix | Invisible
32513257
// Keep: aligned with Quotes's `newVal` doc
32523258
private[QuotesImpl] def validValFlags: Flags = Private | Protected | Override | Deferred | Final | Param | Implicit | Lazy | Mutable | Local | ParamAccessor | Module | Package | Case | CaseAccessor | Given | Enum | AbsOverride | JavaStatic | Synthetic | Artifact // Flags that could be added: Synthetic | Erased | Invisible
3253-
3259+
// Keep: aligned with Quotes's `let` doc
3260+
private[QuotesImpl] def validValInLetFlags: Flags = Final | Implicit | Lazy | Mutable | Given | Synthetic
32543261
// Keep: aligned with Quotes's `newBind` doc
32553262
private[QuotesImpl] def validBindFlags: Flags = Case // Flags that could be allowed: Implicit | Given | Erased
32563263

library/src/scala/quoted/Quotes.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,22 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
682682
def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef
683683
def unapply(vdef: ValDef): (String, TypeTree, Option[Term])
684684

685+
/** Creates a block `{ val <name> = <rhs: Term>; <body(x): Term> }`
686+
*
687+
* Usage:
688+
* ```
689+
* ValDef.let(owner, "x", rhs1, Flags.Lazy) { x =>
690+
* ValDef.let(x.symbol.owner, "y", rhs2, Flags.Mutable) { y =>
691+
* // use `x` and `y`
692+
* }
693+
* }
694+
* ```
695+
*
696+
* @param flags extra flags to with which the symbol should be constructed. Can be `Final | Implicit | Lazy | Mutable | Given | Synthetic`
697+
*/
698+
// Keep: `flags` doc aligned with QuotesImpl's `validValInLetFlags`
699+
def let(owner: Symbol, name: String, rhs: Term, flags: Flags)(body: Ref => Term): Term
700+
685701
/** Creates a block `{ val <name> = <rhs: Term>; <body(x): Term> }`
686702
*
687703
* Usage:

project/MiMaFilters.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ object MiMaFilters {
2222

2323
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.Conversion.underlying"),
2424
ProblemFilters.exclude[MissingClassProblem]("scala.Conversion$"),
25-
25+
2626
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.stableNull"),
27+
28+
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ValDefModule.let"),
2729
),
2830

2931
// Additions since last LTS
@@ -129,6 +131,7 @@ object MiMaFilters {
129131
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#MethodTypeMethods.methodTypeKind"),
130132
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#MethodTypeMethods.isContextual"),
131133
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ImplicitsModule.searchIgnoring"),
134+
ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#ValDefModule.let"),
132135
// Change `experimental` annotation to a final class
133136
ProblemFilters.exclude[FinalClassProblem]("scala.annotation.experimental"),
134137
),

tests/neg-macros/i23008.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
| Exception occurred while executing macro expansion.
66
| java.lang.IllegalArgumentException: requirement failed: value of StringConstant cannot be `null`
77
| at scala.Predef$.require(Predef.scala:337)
8-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2534)
9-
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2533)
8+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2540)
9+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$StringConstant$.apply(QuotesImpl.scala:2539)
1010
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:80)
1111
| at scala.quoted.ToExpr$StringToExpr.apply(ToExpr.scala:78)
1212
| at scala.quoted.Expr$.apply(Expr.scala:70)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x: 1, y: string
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.quoted._
2+
3+
object Macro:
4+
inline def makeBlock(): Unit = ${makeBlockImpl}
5+
def makeBlockImpl(using Quotes): Expr[Unit] = {
6+
import quotes.reflect._
7+
ValDef.let(Symbol.spliceOwner, "x", '{0}.asTerm, Flags.Mutable) { x =>
8+
ValDef.let(Symbol.spliceOwner, "y", '{"string"}.asTerm, Flags.Lazy) { y =>
9+
'{
10+
${Assign(x, '{1}.asTerm).asExpr}
11+
println("x: " + ${x.asExprOf[Int]} + ", y: " + ${y.asExprOf[String]})
12+
}.asTerm
13+
}
14+
}.asExprOf[Unit]
15+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@main def Test = Macro.makeBlock()

0 commit comments

Comments
 (0)