Skip to content

Commit 164e407

Browse files
committed
Check flags for method, val and bind symbols
1 parent b2ef655 commit 164e407

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

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

Lines changed: 32 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,28 @@ 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+
import Flags.*
2490+
// TODO: missing AbsOverride
2491+
checkValidFlags(flags.toTermFlags, Private | Protected | Override | Deferred | Final | Method | Implicit | Given | Local | JavaStatic) // Synthetic | ExtensionMethod | Exported | Erased | Infix | Invisible
24872492
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Method, tpe, privateWithin)
24882493
def newVal(owner: Symbol, name: String, tpe: TypeRepr, flags: Flags, privateWithin: Symbol): Symbol =
2494+
import Flags.*
2495+
// TODO: missing AbsOverride
2496+
checkValidFlags(flags.toTermFlags, Private | Protected | Override | Deferred | Final | Param | Implicit | Lazy | Mutable | Local | ParamAccessor | Module | Package | Case | CaseAccessor | Given | Enum | JavaStatic) // Synthetic | Erased | Invisible
24892497
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags, tpe, privateWithin)
24902498
def newBind(owner: Symbol, name: String, flags: Flags, tpe: TypeRepr): Symbol =
2491-
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | Case, tpe)
2499+
import Flags.*
2500+
checkValidFlags(flags.toTermFlags, Case) // | Implicit | Given | Erased
2501+
dotc.core.Symbols.newSymbol(owner, name.toTermName, flags | dotc.core.Flags.Case, tpe)
24922502
def noSymbol: Symbol = dotc.core.Symbols.NoSymbol
24932503

2504+
private inline def checkValidFlags(inline flags: Flags, inline valid: Flags): Unit =
2505+
xCheckMacroAssert(
2506+
flags <= valid,
2507+
s"Received invalid flags. Expected flags ${flags.show} to only contain a subset of ${valid.show}."
2508+
)
2509+
2510+
24942511
def freshName(prefix: String): String =
24952512
NameKinds.MacroNames.fresh(prefix.toTermName).toString
24962513
end Symbol
@@ -2563,7 +2580,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
25632580
self.isTerm && !self.is(dotc.core.Flags.Method) && !self.is(dotc.core.Flags.Case/*, FIXME add this check and fix sourcecode butNot = Enum | Module*/)
25642581
def isDefDef: Boolean = self.is(dotc.core.Flags.Method)
25652582
def isBind: Boolean =
2566-
self.is(dotc.core.Flags.Case, butNot = Enum | Module) && !self.isClass
2583+
self.is(dotc.core.Flags.Case, butNot = dotc.core.Flags.Enum | dotc.core.Flags.Module) && !self.isClass
25672584
def isNoSymbol: Boolean = self == Symbol.noSymbol
25682585
def exists: Boolean = self != Symbol.noSymbol
25692586

@@ -2919,7 +2936,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
29192936
/** Checks that all definitions in this tree have the expected owner.
29202937
* Nested definitions are ignored and assumed to be correct by construction.
29212938
*/
2922-
private def xCheckMacroedOwners(tree: Option[Tree], owner: Symbol): tree.type =
2939+
private def xCheckedMacroOwners(tree: Option[Tree], owner: Symbol): tree.type =
29232940
if xCheckMacro then
29242941
tree match
29252942
case Some(tree) =>
@@ -2930,7 +2947,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
29302947
/** Checks that all definitions in this tree have the expected owner.
29312948
* Nested definitions are ignored and assumed to be correct by construction.
29322949
*/
2933-
private def xCheckMacroedOwners(tree: Tree, owner: Symbol): tree.type =
2950+
private def xCheckedMacroOwners(tree: Tree, owner: Symbol): tree.type =
29342951
if xCheckMacro then
29352952
xCheckMacroOwners(tree, owner)
29362953
tree
@@ -3001,6 +3018,9 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
30013018
"Reference to a method must be eta-expanded before it is used as an expression: " + term.show)
30023019
term
30033020

3021+
private inline def xCheckMacroAssert(inline cond: Boolean, inline msg: String): Unit =
3022+
assert(!xCheckMacro || cond, msg)
3023+
30043024
object Printer extends PrinterModule:
30053025

30063026
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)