From 98df6a94159e26bc3ad08cd544273a227e717d08 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 11 Feb 2022 00:57:38 +0100 Subject: [PATCH 1/2] Add test case for sealed abstract case class modification --- .../quicklens/test/ModitySealedAbstractClass.scala | 13 +++++++++++++ .../scala/com/softwaremill/quicklens/TestData.scala | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 quicklens/src/test/scala-3/com/softwaremill/quicklens/test/ModitySealedAbstractClass.scala diff --git a/quicklens/src/test/scala-3/com/softwaremill/quicklens/test/ModitySealedAbstractClass.scala b/quicklens/src/test/scala-3/com/softwaremill/quicklens/test/ModitySealedAbstractClass.scala new file mode 100644 index 0000000..89136cd --- /dev/null +++ b/quicklens/src/test/scala-3/com/softwaremill/quicklens/test/ModitySealedAbstractClass.scala @@ -0,0 +1,13 @@ +package com.softwaremill.quicklens.test + +import com.softwaremill.quicklens.TestData._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import com.softwaremill.quicklens._ + +class ModitySealedAbstractClass extends AnyFlatSpec with Matchers { + it should "Modify abstract class hierarchy" in { + invInt.modify(_.typ).setTo(Type("Long")) should be(invLong) + } +} diff --git a/quicklens/src/test/scala/com/softwaremill/quicklens/TestData.scala b/quicklens/src/test/scala/com/softwaremill/quicklens/TestData.scala index 7defdf6..47529ad 100644 --- a/quicklens/src/test/scala/com/softwaremill/quicklens/TestData.scala +++ b/quicklens/src/test/scala/com/softwaremill/quicklens/TestData.scala @@ -78,4 +78,15 @@ object TestData { val ms1 = collection.immutable.SortedMap("K1" -> A4(A5("d1")), "K2" -> A4(A5("d2")), "K3" -> A4(A5("d3"))) val mh1 = collection.immutable.HashMap("K1" -> A4(A5("d1")), "K2" -> A4(A5("d2")), "K3" -> A4(A5("d3"))) val ml1 = collection.immutable.ListMap("K1" -> A4(A5("d1")), "K2" -> A4(A5("d2")), "K3" -> A4(A5("d3"))) + + case class Type(name: String) + sealed abstract class Variance { + val typ: Type + } + case class Covariance(typ: Type) extends Variance + case class Contravariance(typ: Type) extends Variance + case class Invariance(typ: Type) extends Variance + + val invInt: Variance = Invariance(Type("Int")) + val invLong: Variance = Invariance(Type("Long")) } From ffd23ae095852a65a195732d690a78e6ce185fe5 Mon Sep 17 00:00:00 2001 From: Kacper Korban Date: Fri, 11 Feb 2022 01:18:32 +0100 Subject: [PATCH 2/2] Fix supporting sealed abstract classes --- .../com/softwaremill/quicklens/QuicklensMacros.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/quicklens/src/main/scala-3/com/softwaremill/quicklens/QuicklensMacros.scala b/quicklens/src/main/scala-3/com/softwaremill/quicklens/QuicklensMacros.scala index d80b383..5b7700e 100644 --- a/quicklens/src/main/scala-3/com/softwaremill/quicklens/QuicklensMacros.scala +++ b/quicklens/src/main/scala-3/com/softwaremill/quicklens/QuicklensMacros.scala @@ -118,11 +118,10 @@ object QuicklensMacros { case AppliedType(_, typeParams) => Apply(TypeApply(Select(obj, copy), typeParams.map(Inferred(_))), args) case _ => Apply(Select(obj, copy), args) } - else if (objSymbol.flags.is(Flags.Sealed) && objSymbol.flags.is(Flags.Trait)) || objSymbol.flags.is( - Flags.Enum - ) + else if objSymbol.flags.is(Flags.Enum) || + (objSymbol.flags.is(Flags.Sealed) && (objSymbol.flags.is(Flags.Trait) || objSymbol.flags.is(Flags.Abstract))) then - // if the source is a sealed trait / enum, generating a if-then-else with a .copy for each child (implementing case class) + // if the source is a sealed trait / sealed abstract class / enum, generating a if-then-else with a .copy for each child (implementing case class) val cases = obj.tpe.typeSymbol.children.map { child => val subtype = TypeIdent(child) val bind = Symbol.newBind(owner, "c", Flags.EmptyFlags, subtype.tpe)