Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce number of Symbol.tree dependencies in macros. #525

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ lazy val test = (projectMatrix in file("test"))
.settings(commonSettings)
.settings(
name := "magnolia-test",
scalacOptions += "-Yretain-trees",
projectDependencies ++= Seq(
"org.scalameta" %%% "munit" % "1.0.0-M6"
),
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/magnolia1/interface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ object CaseClass:
*/
def deref(param: Type): PType

/** Requires compilation with `-Yretain-trees` on.
/** Recommended compilation with `-Yretain-trees` on.
* @return
* default argument value, if any
*/
Expand Down
77 changes: 44 additions & 33 deletions core/src/main/scala/magnolia1/macro.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,24 @@ object Macro:
.zipWithIndex
.map { case (field, i) =>
exprOfOption {
val defaultMethodName = s"$$lessinit$$greater$$default$$${i + 1}"
Expr(field.name) -> tpe.companionClass
.declaredMethod(s"$$lessinit$$greater$$default$$${i + 1}")
.declaredMethod(defaultMethodName)
.headOption
.flatMap(_.tree.asInstanceOf[DefDef].rhs)
.map { defaultMethod =>
val callDefault = {
val base = Ident(tpe.companionModule.termRef).select(defaultMethod)
val tParams = defaultMethod.paramSymss.headOption.filter(_.forall(_.isType))
tParams match
case Some(tParams) => TypeApply(base, tParams.map(TypeTree.ref))
case _ => base
}

defaultMethod.tree match {
case tree: DefDef => tree.rhs.getOrElse(callDefault)
case _ => callDefault
}
}
.map(_.asExprOf[Any])
}
}
Expand All @@ -87,14 +101,10 @@ object Macro:
case _ => Nil

Expr.ofList {
TypeRepr
.of[T]
.typeSymbol
.caseFields
val typeRepr = TypeRepr.of[T]
typeRepr.typeSymbol.caseFields
.map { field =>
val tpeRepr = field.tree match
case v: ValDef => v.tpt.tpe
case d: DefDef => d.returnTpt.tpe
val tpeRepr = typeRepr.memberType(field)

Expr(field.name) -> getAnnotations(tpeRepr)
.filter { a =>
Expand All @@ -110,25 +120,20 @@ object Macro:
def repeated[T: Type](using Quotes): Expr[List[(String, Boolean)]] =
import quotes.reflect.*

def isRepeated[T](tpeRepr: TypeRepr): Boolean = tpeRepr match
case a: AnnotatedType =>
a.annotation.tpe match
case tr: TypeRef => tr.name == "Repeated"
case _ => false
case _ => false

val tpe = TypeRepr.of[T]
val symbol: Option[Symbol] =
if tpe.typeSymbol.isNoSymbol then None else Some(tpe.typeSymbol)
val constr: Option[DefDef] =
symbol.map(_.primaryConstructor.tree.asInstanceOf[DefDef])

val areRepeated = constr.toList
.flatMap(_.paramss)
.flatMap(_.params.flatMap {
case ValDef(name, tpeTree, _) => Some(name -> isRepeated(tpeTree.tpe))
case _ => None
})
val areRepeated =
if tpe.typeSymbol.isNoSymbol then Nil
else {
val symbol = tpe.typeSymbol
val ctor = symbol.primaryConstructor
for param <- ctor.paramSymss.flatten
yield
val isRepeated = tpe.memberType(param) match {
case AnnotatedType(_, annot) => annot.tpe.typeSymbol == defn.RepeatedAnnot
case _ => false
}
param.name -> isRepeated
}

Expr(areRepeated)

Expand Down Expand Up @@ -209,7 +214,13 @@ object Macro:
.filter(filterAnnotation)
.map(_.asExpr.asInstanceOf[Expr[Any]])
case _ =>
List.empty
// Best effort in case whe -Yretain-trees is not used
// Does not support class parent annotations (in the extends clouse)
tpe.baseClasses
.map(tpe.baseType(_))
.flatMap(getAnnotations(_))
.filter(filterAnnotation)
.map(_.asExpr)
}
}
}
Expand Down Expand Up @@ -247,11 +258,11 @@ object Macro:
private def fromDeclarations(
from: Symbol
): List[(String, List[Expr[Any]])] =
from.declarations.collect {
case field: Symbol if field.tree.isInstanceOf[ValDef] =>
field.name -> field.annotations
.filter(filterAnnotation)
.map(_.asExpr.asInstanceOf[Expr[Any]])
from.fieldMembers.collect { case field: Symbol =>
val annotations = field.annotations ::: field.allOverriddenSymbols.flatMap(_.annotations).toList
field.name -> annotations
.filter(filterAnnotation)
.map(_.asExpr.asInstanceOf[Expr[Any]])
}

private def groupByParamName(anns: List[(String, List[Expr[Any]])]) =
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ be automatically available for consideration during contextual search.
If you don't want to make the automatic derivation available in the given scope, consider using the `Derivation` trait which provides semi-auto derivation with `derived` method, but also brings some additional limitations.
## Limitations

Accessing default values for case class parameters requires compilation with `-Yretain-trees` on.
For accessing default values for case class parameters we recommend compilation with `-Yretain-trees` on.

For a recursive structures it is required to assign the derived value to an implicit variable e.g.
```Scala
Expand Down
Loading