|  | 
| 1 | 1 | package mill.define | 
| 2 | 2 | 
 | 
| 3 |  | -// import sourcecode.Compat.Context | 
| 4 |  | -// import language.experimental.macros | 
|  | 3 | +import scala.quoted.* | 
| 5 | 4 | 
 | 
| 6 | 5 | case class EnclosingClass(value: Class[_]) | 
| 7 | 6 | object EnclosingClass { | 
| 8 | 7 |   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 | +  } | 
| 15 | 55 | } | 
0 commit comments