Skip to content

Commit d52335c

Browse files
committed
Part 6 - implement EnclosingClass, pass specific integration tests
1 parent 720a8ad commit d52335c

File tree

1 file changed

+48
-8
lines changed

1 file changed

+48
-8
lines changed
Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,55 @@
11
package mill.define
22

3-
// import sourcecode.Compat.Context
4-
// import language.experimental.macros
3+
import scala.quoted.*
54

65
case class EnclosingClass(value: Class[_])
76
object EnclosingClass {
87
def apply()(implicit c: EnclosingClass) = c.value
9-
implicit def generate: EnclosingClass = ??? // macro impl
10-
// def impl(c: Context): c.Tree = {
11-
// import c.universe._
12-
// // q"new _root_.mill.define.EnclosingClass(classOf[$cls])"
13-
// q"new _root_.mill.define.EnclosingClass(this.getClass)"
14-
// }
8+
inline given generate: EnclosingClass = ${ impl }
9+
10+
// TODO: copied from Task.scala
11+
private def withMacroOwner[T](using Quotes)(op: quotes.reflect.Symbol => T): T = {
12+
import quotes.reflect.*
13+
14+
// In Scala 3, the top level splice of a macro is owned by a symbol called "macro" with the macro flag set,
15+
// but not the method flag.
16+
def isMacroOwner(sym: Symbol)(using Quotes): Boolean =
17+
sym.name == "macro" && sym.flags.is(Flags.Macro | Flags.Synthetic) && !sym.flags.is(
18+
Flags.Method
19+
)
20+
21+
def loop(owner: Symbol): T =
22+
if owner.isPackageDef || owner == Symbol.noSymbol then
23+
report.errorAndAbort(
24+
"Cannot find the owner of the macro expansion",
25+
Position.ofMacroExpansion
26+
)
27+
else if isMacroOwner(owner) then op(owner.owner) // Skip the "macro" owner
28+
else loop(owner.owner)
29+
30+
loop(Symbol.spliceOwner)
31+
}
32+
33+
def impl(using Quotes): Expr[EnclosingClass] = withMacroOwner { owner =>
34+
import quotes.reflect.*
35+
36+
def enclosingClass(sym: Symbol): Symbol =
37+
if sym.isPackageDef || sym == Symbol.noSymbol then
38+
report.errorAndAbort(
39+
"Cannot find the enclosing class of the macro expansion",
40+
Position.ofMacroExpansion
41+
)
42+
else if sym.isClassDef then sym
43+
else enclosingClass(sym.owner)
44+
45+
if owner.flags.is(Flags.Method) then
46+
val cls = enclosingClass(owner)
47+
val ref = This(cls).asExprOf[Any]
48+
'{ new EnclosingClass($ref.getClass) }
49+
else
50+
report.errorAndAbort(
51+
"EnclosingClass.generate can only be used within a method",
52+
Position.ofMacroExpansion
53+
)
54+
}
1555
}

0 commit comments

Comments
 (0)