Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi committed Jul 11, 2024
1 parent f9c5015 commit 9f606f2
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,11 @@ object Macros {
).decodedName.toString
)

q"${c.prefix}.annotate($derived, $tagKey, $tagValue, $shortTagValue)"
val tagKeyExpr = tagKey match {
case Some(v) => q"$v"
case None => q"${c.prefix}.tagName"
}
q"${c.prefix}.annotate($derived, $tagKeyExpr, $tagValue, $shortTagValue)"
}
}

Expand Down
8 changes: 4 additions & 4 deletions upickle/implicits/src-3/upickle/implicits/Readers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ trait ReadersVersionSpecific
inline if macros.isSingleton[T] then
annotate[T](
SingletonReader[T](macros.getSingleton[T]),
macros.tagKey[T],
macros.tagKey[T](outerThis),
macros.tagName[T],
macros.shortTagName[T]
)
else if macros.isMemberOfSealedHierarchy[T] then
annotate[T](
reader,
macros.tagKey[T],
macros.tagKey[T](outerThis),
macros.tagName[T],
macros.shortTagName[T],
)
Expand All @@ -97,7 +97,7 @@ trait ReadersVersionSpecific
.toList
.asInstanceOf[List[Reader[_ <: T]]]

Reader.merge[T](macros.tagKey[T], readers: _*)
Reader.merge[T](macros.tagKey[T](outerThis), readers: _*)
}

inline def macroRAll[T](using m: Mirror.Of[T]): Reader[T] = inline m match {
Expand All @@ -109,7 +109,7 @@ trait ReadersVersionSpecific
inline given superTypeReader[T: Mirror.ProductOf, V >: T : Reader : Mirror.SumOf]
(using NotGiven[CurrentlyDeriving[V]]): Reader[T] = {
val actual = implicitly[Reader[V]].asInstanceOf[TaggedReader[T]]
val tagKey = macros.tagKey[T]
val tagKey = macros.tagKey[T](outerThis)
val tagName = macros.tagName[T]
val shortTagName = macros.shortTagName[T]
new TaggedReader.Leaf(tagKey, tagName, shortTagName, actual.findReader(tagName))
Expand Down
5 changes: 2 additions & 3 deletions upickle/implicits/src-3/upickle/implicits/Writers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ trait WritersVersionSpecific
with Annotator
with CaseClassReadWriters:

val outerThis = this
inline def macroW[T: ClassTag](using m: Mirror.Of[T]): Writer[T] = inline m match {
case m: Mirror.ProductOf[T] =>

Expand Down Expand Up @@ -46,15 +45,15 @@ trait WritersVersionSpecific
inline if macros.isSingleton[T] then
annotate[T](
SingletonWriter[T](null.asInstanceOf[T]),
macros.tagKey[T],
macros.tagKey[T](outerThis),
macros.tagName[T],
macros.shortTagName[T],
Annotator.Checker.Val(macros.getSingleton[T]),
)
else if macros.isMemberOfSealedHierarchy[T] then
annotate[T](
writer,
macros.tagKey[T],
macros.tagKey[T](outerThis),
macros.tagName[T],
macros.shortTagName[T],
Annotator.Checker.Cls(implicitly[ClassTag[T]].runtimeClass),
Expand Down
12 changes: 7 additions & 5 deletions upickle/implicits/src-3/upickle/implicits/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,23 @@ inline def isMemberOfSealedHierarchy[T]: Boolean = ${ isMemberOfSealedHierarchyI
def isMemberOfSealedHierarchyImpl[T](using Quotes, Type[T]): Expr[Boolean] =
Expr(sealedHierarchyParents[T].nonEmpty)

inline def tagKey[T]: String = ${ tagKeyImpl[T] }
def tagKeyImpl[T](using Quotes, Type[T]): Expr[String] =
inline def tagKey[T](inline thisOuter: upickle.core.Types with upickle.implicits.MacrosCommon): String = ${ tagKeyImpl[T]('thisOuter) }
def tagKeyImpl[T](using Quotes, Type[T])(thisOuter: Expr[upickle.core.Types with upickle.implicits.MacrosCommon]): Expr[String] =
import quotes.reflect._

// `case object`s extend from `Mirror`, which is `sealed` and will never have a `@key` annotation
// so we need to filter it out to ensure it doesn't trigger an error in `tagKeyFromParents`
val mirrorType = Symbol.requiredClass("scala.deriving.Mirror")

Expr(MacrosCommon.tagKeyFromParents(
MacrosCommon.tagKeyFromParents(
Type.show[T],
sealedHierarchyParents[T].filterNot(_ == mirrorType),
extractKey,
(_: Symbol).name,
report.errorAndAbort,
))
) match{
case Some(v) => Expr(v)
case None => '{${thisOuter}.tagName}
}

inline def tagName[T]: String = ${ tagNameImpl[T] }
def tagNameImpl[T](using Quotes, Type[T]): Expr[String] =
Expand Down
10 changes: 6 additions & 4 deletions upickle/implicits/src/upickle/implicits/MacrosCommon.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package upickle.implicits

trait MacrosCommon extends upickle.core.Config
trait MacrosCommon extends upickle.core.Config with upickle.core.Types{
val outerThis = this
}

object MacrosCommon {
def tagKeyFromParents[P](
Expand All @@ -9,16 +11,16 @@ object MacrosCommon {
getKey: P => Option[String],
getName: P => String,
fail: String => Nothing,
): String =
): Option[String] =
/**
* Valid cases are:
*
* 1. None of the parents have a `@key` annotation
* 2. All of the parents have the same `@key` annotation
*/
sealedParents.flatMap(getKey(_)) match {
case Nil => upickle.core.Annotator.defaultTagKey
case keys @ (key :: _) if keys.length == sealedParents.length && keys.distinct.length == 1 => key
case Nil => None
case keys @ (key :: _) if keys.length == sealedParents.length && keys.distinct.length == 1 => Some(key)
case keys =>
fail(
s"Type $typeName inherits from multiple parent types with different discriminator keys:\n\n" +
Expand Down
23 changes: 23 additions & 0 deletions upickle/test/src/upickle/MacroTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@ object UnknownKeys{
override def allowUnknownKeys = false
}
}

object TagName{
object TagNamePickler extends upickle.AttributeTagged {
override def tagName = "_tag"
}

sealed trait Foo
case class Bar(x: Int) extends Foo
case class Qux(s: String) extends Foo

implicit val barRw: TagNamePickler.ReadWriter[Bar] = TagNamePickler.macroRW
implicit val quxRw: TagNamePickler.ReadWriter[Qux] = TagNamePickler.macroRW
implicit val fooRw: TagNamePickler.ReadWriter[Foo] = TagNamePickler.macroRW
}
object MacroTests extends TestSuite {

// Doesn't work :(
Expand Down Expand Up @@ -849,5 +863,14 @@ object MacroTests extends TestSuite {
)

}

test("tagName"){
val customPicklerTest = new TestUtil(TagName.TagNamePickler)
customPicklerTest.rw(
TagName.Bar(123),
"""{"_tag": "Bar", "x": 123}"""
)

}
}
}

0 comments on commit 9f606f2

Please sign in to comment.