-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make Ref.apply() return trees usable in the largest scope possible
Previously for symbols contained in objects (prefixed by, let's say, 'pre'), we would return: * an Ident if pre contained only static object and packages; * Select(This(moduleClassSymbol), sym) if a prefix contained a class. However, this meant that in the second case, the generated tree would require the macro to be expanded inside of the object, even though it should be enough to just expand inside of the innermost class. This was unexpected and confusing, so it was changed to not return innermost module classes wrapped with This().
- Loading branch information
Showing
8 changed files
with
105 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import scala.quoted.* | ||
|
||
object Macros { | ||
def valuesImpl[A: Type](using Quotes): Expr[Any] = { | ||
import quotes.reflect.* | ||
val symbol = TypeRepr.of[A].typeSymbol.fieldMember("value") | ||
Ref(symbol).asExprOf[Any] | ||
} | ||
|
||
transparent inline def values[A]: Any = ${ valuesImpl[A] } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
class Cls{ | ||
object a { | ||
object domain { | ||
val value = "" | ||
} | ||
} | ||
Macros.values[a.domain.type] | ||
} | ||
|
||
object Test { | ||
lazy val script = new Cls() | ||
def main(args: Array[String]): Unit = | ||
val _ = script.hashCode() | ||
??? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import scala.quoted.* | ||
|
||
object Macros { | ||
|
||
|
||
def valuesImpl[A: Type](using quotes: Quotes): Expr[List[A]] = { | ||
import quotes.*, quotes.reflect.* | ||
|
||
extension (sym: Symbol) | ||
def isPublic: Boolean = !sym.isNoSymbol && | ||
!(sym.flags.is(Flags.Private) || sym.flags.is(Flags.PrivateLocal) || sym.flags.is(Flags.Protected) || | ||
sym.privateWithin.isDefined || sym.protectedWithin.isDefined) | ||
|
||
def isSealed[A: Type]: Boolean = | ||
TypeRepr.of[A].typeSymbol.flags.is(Flags.Sealed) | ||
|
||
def extractSealedSubtypes[A: Type]: List[Type[?]] = { | ||
def extractRecursively(sym: Symbol): List[Symbol] = | ||
if sym.flags.is(Flags.Sealed) then sym.children.flatMap(extractRecursively) | ||
else if sym.flags.is(Flags.Enum) then List(sym.typeRef.typeSymbol) | ||
else if sym.flags.is(Flags.Module) then List(sym.typeRef.typeSymbol.moduleClass) | ||
else List(sym) | ||
|
||
extractRecursively(TypeRepr.of[A].typeSymbol).distinct.map(typeSymbol => | ||
typeSymbol.typeRef.asType | ||
) | ||
} | ||
|
||
if isSealed[A] then { | ||
val refs = extractSealedSubtypes[A].flatMap { tpe => | ||
val sym = TypeRepr.of(using tpe).typeSymbol | ||
val isCaseVal = sym.isPublic && sym.flags | ||
.is(Flags.Case | Flags.Enum) && (sym.flags.is(Flags.JavaStatic) || sym.flags.is(Flags.StableRealizable)) | ||
|
||
if (isCaseVal) then List(Ref(sym).asExprOf[A]) | ||
else Nil | ||
} | ||
Expr.ofList(refs) | ||
} else '{ Nil } | ||
} | ||
|
||
inline def values[A]: List[A] = ${ valuesImpl[A] } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
class Test { | ||
object domain { | ||
enum PaymentMethod: | ||
case PayPal(email: String) | ||
case Card(digits: Long, name: String) | ||
case Cash | ||
} | ||
println(Macros.values[domain.PaymentMethod]) | ||
} | ||
object Test { | ||
lazy val script = new Test() | ||
def main(args: Array[String]): Unit = | ||
val _ = script.hashCode() | ||
} |