Skip to content

Commit 09cf574

Browse files
committed
Check flags for method, val and bind symbols
1 parent a1e4e42 commit 09cf574

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import dotty.tools.dotc.ast.untpd
99
import dotty.tools.dotc.core.Annotations
1010
import dotty.tools.dotc.core.Contexts._
1111
import dotty.tools.dotc.core.Types
12-
import dotty.tools.dotc.core.Flags._
1312
import dotty.tools.dotc.core.NameKinds
1413
import dotty.tools.dotc.core.StdNames._
1514
import dotty.tools.dotc.quoted.reflect._
@@ -267,12 +266,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
267266

268267
object DefDef extends DefDefModule:
269268
def apply(symbol: Symbol, rhsFn: List[List[Tree]] => Option[Term]): DefDef =
270-
assert(symbol.isTerm, s"expected a term symbol but received $symbol")
269+
xCheckMacroAssert(symbol.isTerm, s"expected a term symbol but received $symbol")
270+
xCheckMacroAssert(symbol.flags.is(Flags.Method), "expected a symbol with `Method` flag set")
271271
withDefaultPos(tpd.DefDef(symbol.asTerm, prefss =>
272-
xCheckMacroedOwners(xCheckMacroValidExpr(rhsFn(prefss)), symbol).getOrElse(tpd.EmptyTree)
272+
xCheckedMacroOwners(xCheckMacroValidExpr(rhsFn(prefss)), symbol).getOrElse(tpd.EmptyTree)
273273
))
274274
def copy(original: Tree)(name: String, paramss: List[ParamClause], tpt: TypeTree, rhs: Option[Term]): DefDef =
275-
tpd.cpy.DefDef(original)(name.toTermName, paramss, tpt, xCheckMacroedOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
275+
tpd.cpy.DefDef(original)(name.toTermName, paramss, tpt, xCheckedMacroOwners(rhs, original.symbol).getOrElse(tpd.EmptyTree))
276276
def unapply(ddef: DefDef): (String, List[ParamClause], TypeTree, Option[Term]) =
277277
(ddef.name.toString, ddef.paramss, ddef.tpt, optional(ddef.rhs))
278278
end DefDef
@@ -298,9 +298,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
298298

299299
object ValDef extends ValDefModule:
300300
def apply(symbol: Symbol, rhs: Option[Term]): ValDef =
301-
tpd.ValDef(symbol.asTerm, xCheckMacroedOwners(xCheckMacroValidExpr(rhs), symbol).getOrElse(tpd.EmptyTree))
301+
xCheckMacroAssert(!symbol.flags.is(Flags.Method), "expected a symbol without `Method` flag set")
302+
tpd.ValDef(symbol.asTerm, xCheckedMacroOwners(xCheckMacroValidExpr(rhs), symbol).getOrElse(tpd.EmptyTree))
302303
def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef =
303-
tpd.cpy.ValDef(original)(name.toTermName, tpt, xCheckMacroedOwners(xCheckMacroValidExpr(rhs), original.symbol).getOrElse(tpd.EmptyTree))
304+
tpd.cpy.ValDef(original)(name.toTermName, tpt, xCheckedMacroOwners(xCheckMacroValidExpr(rhs), original.symbol).getOrElse(tpd.EmptyTree))
304305
def unapply(vdef: ValDef): (String, TypeTree, Option[Term]) =
305306
(vdef.name.toString, vdef.tpt, optional(vdef.rhs))
306307

@@ -390,7 +391,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
390391
def etaExpand(owner: Symbol): Term = self.tpe.widen match {
391392
case mtpe: Types.MethodType if !mtpe.isParamDependent =>
392393
val closureResType = mtpe.resType match {
393-
case t: Types.MethodType => t.toFunctionType(isJava = self.symbol.is(JavaDefined))
394+
case t: Types.MethodType => t.toFunctionType(isJava = self.symbol.is(dotc.core.Flags.JavaDefined))
394395
case t => t
395396
}
396397
val closureTpe = Types.MethodType(mtpe.paramNames, mtpe.paramInfos, closureResType)
@@ -803,7 +804,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
803804
object Lambda extends LambdaModule:
804805
def apply(owner: Symbol, tpe: MethodType, rhsFn: (Symbol, List[Tree]) => Tree): Block =
805806
val meth = dotc.core.Symbols.newAnonFun(owner, tpe)
806-
withDefaultPos(tpd.Closure(meth, tss => xCheckMacroedOwners(xCheckMacroValidExpr(rhsFn(meth, tss.head.map(withDefaultPos))), meth)))
807+
withDefaultPos(tpd.Closure(meth, tss => xCheckedMacroOwners(xCheckMacroValidExpr(rhsFn(meth, tss.head.map(withDefaultPos))), meth)))
807808

808809
def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match {
809810
case Block((ddef @ DefDef(_, tpd.ValDefs(params) :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
@@ -1474,6 +1475,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14741475

14751476
object Bind extends BindModule:
14761477
def apply(sym: Symbol, pattern: Tree): Bind =
1478+
xCheckMacroAssert(sym.flags.is(Flags.Case), "expected a symbol with `Case` flag set")
14771479
tpd.Bind(sym, pattern)
14781480
def copy(original: Tree)(name: String, pattern: Tree): Bind =
14791481
withDefaultPos(tpd.cpy.Bind(original)(name.toTermName, pattern))
@@ -2484,13 +2486,22 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
24842486
def newMethod(owner: Symbol, name: String, tpe: TypeRepr): Symbol =
24852487
newMethod(owner, name, tpe, Flags.EmptyFlags, noSymbol)
24862488
def newMethod(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =
2489+
checkValidFlags(flags.toTermFlags, Flags.validMethodFlags)
24872490
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin)
24882491
def newVal(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =
2492+
checkValidFlags(flags.toTermFlags, Flags.validValFlags)
24892493
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags, tpe, privateWithin)
24902494
def newBind(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol =
2491-
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | Case, tpe)
2495+
checkValidFlags(flags.toTermFlags, Flags.validBindFlags)
2496+
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Case, tpe)
24922497
def noSymbol: Symbol = dotc.core.Symbols.NoSymbol
24932498

2499+
private inline def checkValidFlags(inline flags: Flags, inline valid: Flags): Unit =
2500+
xCheckMacroAssert(
2501+
flags <= valid,
2502+
s"Received invalid flags. Expected flags ${flags.show} to only contain a subset of ${valid.show}."
2503+
)
2504+
24942505
def freshName(prefix: String): String =
24952506
NameKinds.MacroNames.fresh(prefix.toTermName).toString
24962507
end Symbol
@@ -2563,7 +2574,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
25632574
self.isTerm && !self.is(dotc.core.Flags.Method) && !self.is(dotc.core.Flags.Case/*, FIXME add this check and fix sourcecode butNot = Enum | Module*/)
25642575
def isDefDef: Boolean = self.is(dotc.core.Flags.Method)
25652576
def isBind: Boolean =
2566-
self.is(dotc.core.Flags.Case, butNot = Enum | Module) && !self.isClass
2577+
self.is(dotc.core.Flags.Case, butNot = dotc.core.Flags.Enum | dotc.core.Flags.Module) && !self.isClass
25672578
def isNoSymbol: Boolean = self == Symbol.noSymbol
25682579
def exists: Boolean = self != Symbol.noSymbol
25692580

@@ -2799,6 +2810,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
27992810
def Synthetic: Flags = dotc.core.Flags.Synthetic
28002811
def Trait: Flags = dotc.core.Flags.Trait
28012812
def Transparent: Flags = dotc.core.Flags.Transparent
2813+
2814+
private[QuotesImpl] def validMethodFlags: Flags = Private | Protected | Override | Deferred | Final | Method | Implicit | Given | Local | JavaStatic | AbsOverride // Synthetic | ExtensionMethod | Exported | Erased | Infix | Invisible
2815+
private[QuotesImpl] def validValFlags: Flags = Private | Protected | Override | Deferred | Final | Param | Implicit | Lazy | Mutable | Local | ParamAccessor | Module | Package | Case | CaseAccessor | Given | Enum | JavaStatic | AbsOverride // Synthetic | Erased | Invisible
2816+
private[QuotesImpl] def validBindFlags: Flags = Case // | Implicit | Given | Erased
28022817
end Flags
28032818

28042819
given FlagsMethods: FlagsMethods with
@@ -2919,7 +2934,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
29192934
/** Checks that all definitions in this tree have the expected owner.
29202935
* Nested definitions are ignored and assumed to be correct by construction.
29212936
*/
2922-
private def xCheckMacroedOwners(tree: Option[Tree], owner: Symbol): tree.type =
2937+
private def xCheckedMacroOwners(tree: Option[Tree], owner: Symbol): tree.type =
29232938
if xCheckMacro then
29242939
tree match
29252940
case Some(tree) =>
@@ -2930,7 +2945,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
29302945
/** Checks that all definitions in this tree have the expected owner.
29312946
* Nested definitions are ignored and assumed to be correct by construction.
29322947
*/
2933-
private def xCheckMacroedOwners(tree: Tree, owner: Symbol): tree.type =
2948+
private def xCheckedMacroOwners(tree: Tree, owner: Symbol): tree.type =
29342949
if xCheckMacro then
29352950
xCheckMacroOwners(tree, owner)
29362951
tree
@@ -3001,6 +3016,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
30013016
"Reference to a method must be eta-expanded before it is used as an expression: " + term.show)
30023017
term
30033018

3019+
private inline def xCheckMacroAssert(inline cond: Boolean, inline msg: String): Unit =
3020+
assert(!xCheckMacro || cond, msg)
3021+
30043022
object Printer extends PrinterModule:
30053023

30063024
lazy val TreeCode: Printer[Tree] = new Printer[Tree]:

library/src/scala/quoted/Quotes.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3664,7 +3664,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36643664
* @param parent The owner of the method
36653665
* @param name The name of the method
36663666
* @param tpe The type of the method (MethodType, PolyType, ByNameType)
3667-
* @param flags extra flags to with which the symbol should be constructed
3667+
* @param flags extra flags to with which the symbol should be constructed. `Method` flag will be added. Can be `Private | Protected | Override | Deferred | Final | Method | Implicit | Given | Local | JavaStatic`
36683668
* @param privateWithin the symbol within which this new method symbol should be private. May be noSymbol.
36693669
*/
36703670
def newMethod(parent: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol
@@ -3680,7 +3680,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36803680
* @param parent The owner of the val/var/lazy val
36813681
* @param name The name of the val/var/lazy val
36823682
* @param tpe The type of the val/var/lazy val
3683-
* @param flags extra flags to with which the symbol should be constructed
3683+
* @param flags extra flags to with which the symbol should be constructed. Can be `Private | Protected | Override | Deferred | Final | Param | Implicit | Lazy | Mutable | Local | ParamAccessor | Module | Package | Case | CaseAccessor | Given | Enum | JavaStatic`
36843684
* @param privateWithin the symbol within which this new method symbol should be private. May be noSymbol.
36853685
* @note As a macro can only splice code into the point at which it is expanded, all generated symbols must be
36863686
* direct or indirect children of the reflection context's owner.
@@ -3695,7 +3695,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
36953695
*
36963696
* @param parent The owner of the binding
36973697
* @param name The name of the binding
3698-
* @param flags extra flags to with which the symbol should be constructed
3698+
* @param flags extra flags to with which the symbol should be constructed. `Case` flag will be added. Can be `Case`
36993699
* @param tpe The type of the binding
37003700
* @note As a macro can only splice code into the point at which it is expanded, all generated symbols must be
37013701
* direct or indirect children of the reflection context's owner.

0 commit comments

Comments
 (0)