Skip to content

Commit 78663bc

Browse files
committed
More efficient codec derivation with Scala 3
1 parent e5f2ae7 commit 78663bc

File tree

1 file changed

+41
-39
lines changed
  • jsoniter-scala-macros/shared/src/main/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros

1 file changed

+41
-39
lines changed

jsoniter-scala-macros/shared/src/main/scala-3/com/github/plokhotnyuk/jsoniter_scala/macros/JsonCodecMaker.scala

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
831831
}
832832
}
833833

834+
private val stringTpe = defn.StringClass.typeRef
834835
private val booleanTpe = defn.BooleanClass.typeRef
835836
private val byteTpe = defn.ByteClass.typeRef
836837
private val shortTpe = defn.ShortClass.typeRef
@@ -842,20 +843,21 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
842843
private val anyRefTpe = defn.AnyRefClass.typeRef
843844
private val anyValTpe = defn.AnyValClass.typeRef
844845
private val unitTpe = defn.UnitClass.typeRef
846+
private val nullTpe = defn.NullClass.typeRef
845847
private val anyTpe = defn.AnyClass.typeRef
848+
private val wildcardBounds = TypeBounds(defn.NothingClass.typeRef, anyTpe)
849+
private val optionOfWildcardTpe = defn.OptionClass.typeRef.appliedTo(wildcardBounds)
850+
private val arrayOfWildcardTpe = defn.ArrayClass.typeRef.appliedTo(wildcardBounds)
846851
private val arrayOfAnyTpe = defn.ArrayClass.typeRef.appliedTo(anyTpe)
847-
private val stringTpe = TypeRepr.of[String]
848-
private val optionTpe = TypeRepr.of[Option[?]]
849-
private val tupleTpe = TypeRepr.of[Tuple]
850-
private val iterableTpe = TypeRepr.of[Iterable[?]]
851-
private val iteratorTpe = TypeRepr.of[Iterator[?]]
852-
private val arrayTpe = TypeRepr.of[Array[?]]
852+
private val iterableOfWildcardTpe = Symbol.requiredClass("scala.collection.Iterable").typeRef.appliedTo(wildcardBounds)
853+
private val iteratorOfWildcardTpe = Symbol.requiredClass("scala.collection.Iterator").typeRef.appliedTo(wildcardBounds)
854+
private val tupleTpe = Symbol.requiredClass("scala.Tuple").typeRef
853855
private val iArrayOfAnyRefTpe = TypeRepr.of[IArray[AnyRef]]
854-
private val namedTpe = TypeRepr.of[named]
855-
private val stringifiedTpe = TypeRepr.of[stringified]
856-
private val transientTpe = TypeRepr.of[transient]
857-
private val jsonKeyCodecTpe = TypeRepr.of[JsonKeyCodec]
858-
private val jsonValueCodecTpe = TypeRepr.of[JsonValueCodec]
856+
private val namedTpe = Symbol.requiredClass("com.github.plokhotnyuk.jsoniter_scala.macros.named").typeRef
857+
private val stringifiedTpe = Symbol.requiredClass("com.github.plokhotnyuk.jsoniter_scala.macros.stringified").typeRef
858+
private val transientTpe = Symbol.requiredClass("com.github.plokhotnyuk.jsoniter_scala.macros.transient").typeRef
859+
private val jsonKeyCodecTpe = Symbol.requiredClass("com.github.plokhotnyuk.jsoniter_scala.core.JsonKeyCodec").typeRef
860+
private val jsonValueCodecTpe = Symbol.requiredClass("com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec").typeRef
859861
private val newArray = Select(New(TypeIdent(defn.ArrayClass)), defn.ArrayClass.primaryConstructor)
860862
private val newArrayOfAny = TypeApply(newArray, List(Inferred(anyTpe)))
861863
private val fromIArrayMethod = Select.unique(Ref(Symbol.requiredModule("scala.runtime.TupleXXL")), "fromIArray")
@@ -964,17 +966,17 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
964966
else tpe.typeSymbol.companionModule
965967
}
966968

967-
private def isOption(tpe: TypeRepr, types: List[TypeRepr]): Boolean = tpe <:< optionTpe &&
968-
(cfg.skipNestedOptionValues || !types.headOption.exists(_ <:< optionTpe))
969+
private def isOption(tpe: TypeRepr, types: List[TypeRepr]): Boolean = tpe <:< optionOfWildcardTpe &&
970+
(cfg.skipNestedOptionValues || !types.headOption.exists(_ <:< optionOfWildcardTpe))
969971

970972
private def isNullable(tpe: TypeRepr): Boolean = tpe match
971973
case OrType(left, right) => isNullable(right) || isNullable(left)
972-
case _ => tpe =:= TypeRepr.of[Null]
974+
case _ => tpe =:= nullTpe
973975

974976
private def isIArray(tpe: TypeRepr): Boolean = tpe.typeSymbol.fullName == "scala.IArray$package$.IArray"
975977

976978
private def isCollection(tpe: TypeRepr): Boolean =
977-
tpe <:< iterableTpe || tpe <:< iteratorTpe || tpe <:< arrayTpe || isIArray(tpe)
979+
tpe <:< arrayOfWildcardTpe || isIArray(tpe) || tpe <:< iterableOfWildcardTpe || tpe <:< iteratorOfWildcardTpe
978980

979981
private def isJavaEnum(tpe: TypeRepr): Boolean = tpe <:< TypeRepr.of[java.lang.Enum[?]]
980982

@@ -1274,7 +1276,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
12741276
case AnnotatedType(AppliedType(base, _), annot) => AnnotatedType(base.appliedTo(ctArgs), annot)
12751277
case _ => polyRes.appliedTo(ctArgs)
12761278
case other => fail(s"Primary constructor for '${tpe.show}' is not 'MethodType' or 'PolyType' but '$other''")
1277-
} else if (sym.isTerm) Ref(sym).tpe
1279+
} else if (sym.isTerm) sym.termRef
12781280
else fail("Only concrete (no free type parameters) Scala classes & objects are supported for ADT leaf classes. " +
12791281
s"Please consider using of them for ADT with base '${tpe.show}' or provide a custom implicitly accessible codec for the ADT base.")
12801282
}
@@ -1746,7 +1748,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
17461748
val sym = Symbol.newMethod(Symbol.spliceOwner, s"f${fieldIndexAccessors.size}",
17471749
MethodType(List("i"))(_ => intTpe :: Nil, _ => stringTpe))
17481750
DefDef(sym, params => {
1749-
val List(List(param)) = params
1751+
val param = params.head.head
17501752
val cases = f.map {
17511753
var i = -1
17521754
n =>
@@ -1763,14 +1765,14 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
17631765
val sym = Symbol.newMethod(Symbol.spliceOwner, s"q${equalsMethods.size}",
17641766
MethodType("x1" :: "x2" :: Nil)(_ => tpe :: tpe :: Nil, _ => booleanTpe))
17651767
DefDef(sym, params => {
1766-
val List(List(x1, x2)) = params
1768+
val List(x1, x2) = params.head
17671769
new Some(f(x1.asExpr.asInstanceOf[Expr[T]], x2.asExpr.asInstanceOf[Expr[T]]).asTerm.changeOwner(sym))
17681770
})
17691771
}).symbol), List(arg1.asTerm, arg2.asTerm)).asExpr.asInstanceOf[Expr[Boolean]]
17701772

17711773
private def genArrayEquals[T: Type](tpe: TypeRepr, x1t: Expr[T], x2t: Expr[T]): Expr[Boolean] =
17721774
val tpe1 = typeArg1(tpe)
1773-
if (tpe1 <:< TypeRepr.of[Array[?]]) {
1775+
if (tpe1 <:< arrayOfWildcardTpe) {
17741776
tpe1.asType match
17751777
case '[t1] =>
17761778
val x1 = x1t.asInstanceOf[Expr[Array[t1]]]
@@ -1856,7 +1858,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
18561858
val ref = Ref(sym)
18571859
decodeMethodRefs.update(methodKey, ref)
18581860
decodeMethodDefs.addOne(DefDef(sym, params => {
1859-
val List(List(in, default)) = params
1861+
val List(in, default) = params.head
18601862
new Some(f(in.asExpr.asInstanceOf[Expr[JsonReader]], default.asExpr.asInstanceOf[Expr[T]]).asTerm.changeOwner(sym))
18611863
}))
18621864
ref
@@ -1870,7 +1872,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
18701872
val ref = Ref(sym)
18711873
encodeMethodRefs.update(methodKey, ref)
18721874
encodeMethodDefs.addOne(DefDef(sym, params => {
1873-
val List(List(x, out)) = params
1875+
val List(x, out) = params.head
18741876
new Some(f(out.asExpr.asInstanceOf[Expr[JsonWriter]], x.asExpr.asInstanceOf[Expr[T]]).asTerm.changeOwner(sym))
18751877
}))
18761878
ref
@@ -1905,7 +1907,11 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
19051907
val tpe1 = valueClassValueType(tpe)
19061908
tpe1.asType match { case'[t1] => getClassInfo(tpe).genNew(List(List(genNullValue[t1](tpe1 :: types).asTerm))).asExpr }
19071909
} else if (isCollection(tpe)) {
1908-
if (tpe <:< TypeRepr.of[mutable.BitSet]) '{ new mutable.BitSet }
1910+
if (tpe <:< arrayOfWildcardTpe) withNullValueFor(tpe) {
1911+
typeArg1(tpe).asType match { case '[t1] => genNewArray[t1](Expr(0)) }
1912+
} else if (isIArray(tpe)) withNullValueFor(tpe) {
1913+
typeArg1(tpe).asType match { case '[t1] => '{ IArray.unsafeFromArray(${genNewArray[t1](Expr(0))}) } }
1914+
} else if (tpe <:< TypeRepr.of[mutable.BitSet]) '{ new mutable.BitSet }
19091915
else if (tpe <:< TypeRepr.of[collection.BitSet]) withNullValueFor(tpe)('{ immutable.BitSet.empty })
19101916
else if (tpe <:< TypeRepr.of[::[?]]) Literal(NullConstant()).asExpr
19111917
else if (tpe <:< TypeRepr.of[List[?]] || tpe.typeSymbol == TypeRepr.of[Seq[?]].typeSymbol) '{ Nil }
@@ -1931,15 +1937,11 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
19311937
scalaMapEmpty(tpe, typeArg1(tpe), typeArg2(tpe)).asExpr
19321938
} else if (tpe <:< TypeRepr.of[collection.Map[?, ?]]) {
19331939
scalaMapEmpty(tpe, typeArg1(tpe), typeArg2(tpe)).asExpr
1934-
} else if (tpe <:< TypeRepr.of[Iterable[?]] || tpe <:< TypeRepr.of[Iterator[?]]) {
1940+
} else if (tpe <:< iterableOfWildcardTpe || tpe <:< iteratorOfWildcardTpe) {
19351941
scalaCollectionEmpty(tpe, typeArg1(tpe)).asExpr
1936-
} else if (tpe <:< TypeRepr.of[Array[?]]) withNullValueFor(tpe) {
1937-
typeArg1(tpe).asType match { case '[t1] => genNewArray[t1](Expr(0)) }
1938-
} else if (isIArray(tpe)) withNullValueFor(tpe) {
1939-
typeArg1(tpe).asType match { case '[t1] => '{ IArray.unsafeFromArray(${genNewArray[t1](Expr(0))}) } }
19401942
} else '{ null.asInstanceOf[T] }
19411943
} else if (isEnumOrModuleValue(tpe)) enumOrModuleValueRef(tpe).asExpr
1942-
else if (TypeRepr.of[Null] <:< tpe) Literal(NullConstant()).asExpr
1944+
else if (nullTpe <:< tpe) Literal(NullConstant()).asExpr
19431945
else if (isOpaque(tpe) && !isNamedTuple(tpe)) {
19441946
val sTpe = opaqueDealias(tpe)
19451947
sTpe.asType match { case '[st] => '{ ${genNullValue[st](sTpe :: types.tail)}.asInstanceOf[T] } }
@@ -2382,7 +2384,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
23822384
val isColl = isCollection(tpe)
23832385
val methodKey = new DecoderMethodKey(tpe, isColl & isStringified, useDiscriminator)
23842386
if (isColl) {
2385-
if (tpe <:< TypeRepr.of[Array[?]] || tpe <:< TypeRepr.of[immutable.ArraySeq[?]] || isIArray(tpe) ||
2387+
if (tpe <:< arrayOfWildcardTpe || isIArray(tpe) || tpe <:< TypeRepr.of[immutable.ArraySeq[?]] ||
23862388
tpe <:< TypeRepr.of[mutable.ArraySeq[?]]) withDecoderFor(methodKey, default, in) { (in, default) =>
23872389
val tpe1 = typeArg1(tpe)
23882390
val types1 = tpe1 :: types
@@ -2672,7 +2674,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
26722674
else $emptyCollection
26732675
}.asInstanceOf[Expr[T & mutable.Growable[t1]]],
26742676
x => genReadValForGrowable(tpe1 :: types, isStringified, x, in), default, identity, in).asInstanceOf[Expr[T]]
2675-
} else if (tpe <:< TypeRepr.of[Iterable[?]] || tpe <:< TypeRepr.of[Iterator[?]]) withDecoderFor(methodKey, default, in) { (in, default) =>
2677+
} else if (tpe <:< iterableOfWildcardTpe || tpe <:< iteratorOfWildcardTpe) withDecoderFor(methodKey, default, in) { (in, default) =>
26762678
val tpe1 = typeArg1(tpe)
26772679
tpe1.asType match
26782680
case '[t1] =>
@@ -2842,13 +2844,13 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
28422844
(fTpe.asType match { case '[ft] =>
28432845
fDefault match {
28442846
case Some(d) =>
2845-
if (cfg.transientEmpty && fTpe <:< TypeRepr.of[Iterable[?]]) '{
2847+
if (cfg.transientEmpty && fTpe <:< iterableOfWildcardTpe) '{
28462848
val v = ${getter.asInstanceOf[Expr[ft & Iterable[?]]]}
28472849
if (!v.isEmpty && v != ${d.asExpr.asInstanceOf[Expr[ft]]}) {
28482850
${genWriteConstantKey(fieldInfo.mappedName, out)}
28492851
${genWriteVal('v, allTypes, fieldInfo.isStringified, None, out)}
28502852
}
2851-
} else if (cfg.transientEmpty && fTpe <:< TypeRepr.of[Iterator[?]]) '{
2853+
} else if (cfg.transientEmpty && fTpe <:< iteratorOfWildcardTpe) '{
28522854
val v = ${getter.asInstanceOf[Expr[ft & Iterator[?]]]}
28532855
if (v.hasNext && v != ${d.asExpr.asInstanceOf[Expr[ft]]}) {
28542856
${genWriteConstantKey(fieldInfo.mappedName, out)}
@@ -2870,7 +2872,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
28702872
${genWriteConstantKey(fieldInfo.mappedName, out)}
28712873
${genWriteVal('v, allTypes, fieldInfo.isStringified, None, out)}
28722874
}
2873-
} else if (fTpe <:< TypeRepr.of[Array[?]]) {
2875+
} else if (fTpe <:< arrayOfWildcardTpe) {
28742876
def cond(v: Expr[Array[?]])(using Quotes): Expr[Boolean] =
28752877
val da = d.asExpr.asInstanceOf[Expr[Array[?]]]
28762878
if (cfg.transientEmpty) '{ $v.length != 0 && !${withEqualsFor(fTpe, v, da)((x1, x2) => genArrayEquals(fTpe, x1, x2))} }
@@ -2907,13 +2909,13 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
29072909
}
29082910
}
29092911
case None =>
2910-
if (cfg.transientEmpty && fTpe <:< TypeRepr.of[Iterable[?]]) '{
2912+
if (cfg.transientEmpty && fTpe <:< iterableOfWildcardTpe) '{
29112913
val v = ${getter.asInstanceOf[Expr[ft & Iterable[?]]]}
29122914
if (!v.isEmpty) {
29132915
${genWriteConstantKey(fieldInfo.mappedName, out)}
29142916
${genWriteVal('v, allTypes, fieldInfo.isStringified, None, out)}
29152917
}
2916-
} else if (cfg.transientEmpty && fTpe <:< TypeRepr.of[Iterator[?]]) '{
2918+
} else if (cfg.transientEmpty && fTpe <:< iteratorOfWildcardTpe) '{
29172919
val v = ${getter.asInstanceOf[Expr[ft & Iterator[?]]]}
29182920
if (v.hasNext) {
29192921
${genWriteConstantKey(fieldInfo.mappedName, out)}
@@ -2935,7 +2937,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
29352937
${genWriteConstantKey(fieldInfo.mappedName, out)}
29362938
${genWriteVal('v, allTypes, fieldInfo.isStringified, None, out)}
29372939
}
2938-
} else if (cfg.transientEmpty && fTpe <:< TypeRepr.of[Array[?]]) '{
2940+
} else if (cfg.transientEmpty && fTpe <:< arrayOfWildcardTpe) '{
29392941
val v = ${getter.asInstanceOf[Expr[ft & Array[?]]]}
29402942
if (v.length != 0) {
29412943
${genWriteConstantKey(fieldInfo.mappedName, out)}
@@ -3084,7 +3086,7 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
30843086
val isColl = isCollection(tpe)
30853087
val methodKey = new EncoderMethodKey(tpe, isColl & isStringified, optWriteDiscriminator.map(x => (x.fieldName, x.fieldValue)))
30863088
if (isColl) {
3087-
if (tpe <:< TypeRepr.of[Array[?]] || tpe <:< TypeRepr.of[immutable.ArraySeq[?]] || isIArray(tpe) ||
3089+
if (tpe <:< arrayOfWildcardTpe || isIArray(tpe) || tpe <:< TypeRepr.of[immutable.ArraySeq[?]]||
30883090
tpe <:< TypeRepr.of[mutable.ArraySeq[?]]) withEncoderFor(methodKey, m, out) { (out, x) =>
30893091
val tpe1 = typeArg1(tpe)
30903092
tpe1.asType match
@@ -3222,13 +3224,13 @@ private class JsonCodecMakerInstance(cfg: CodecMakerConfig)(using Quotes) {
32223224
} else $tx.foreach(x => ${genWriteVal('x, types1, isStringified, None, out)})
32233225
$out.writeArrayEnd()
32243226
}
3225-
} else if (tpe <:< TypeRepr.of[Iterable[?]]) withEncoderFor(methodKey, m, out) { (out, x) =>
3227+
} else if (tpe <:< iterableOfWildcardTpe) withEncoderFor(methodKey, m, out) { (out, x) =>
32263228
val tpe1 = typeArg1(tpe)
32273229
tpe1.asType match
32283230
case '[t1] =>
32293231
genWriteArray(x.asInstanceOf[Expr[Iterable[t1]]],
32303232
(out, x1) => genWriteVal(x1, tpe1 :: types, isStringified, None, out), out)
3231-
} else if (tpe <:< TypeRepr.of[Iterator[?]]) withEncoderFor(methodKey, m, out) { (out, x) =>
3233+
} else if (tpe <:< iteratorOfWildcardTpe) withEncoderFor(methodKey, m, out) { (out, x) =>
32323234
val tpe1 = typeArg1(tpe)
32333235
tpe1.asType match
32343236
case'[t1] =>

0 commit comments

Comments
 (0)