Skip to content
Draft
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
9 changes: 8 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ excludeLintKeys in Global ++= Set(ideSkipProject)
val commonSettings = commonSmlBuildSettings ++ ossPublishSettings ++ Seq(
organization := "com.softwaremill.quicklens",
updateDocs := UpdateVersionInDocs(sLog.value, organization.value, version.value, List(file("README.md"))),
scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked"), // useful for debugging macros: "-Ycheck:all", "-Xcheck-macros"
scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked"),
scalacOptions ++= {
val sv = (Compile / scalaVersion).value
CrossVersion.partialVersion(sv) match {
case Some((3, _)) => List("-Xcheck-macros")
case _ => Nil
}
},
ideSkipProject := (scalaVersion.value != scalaIdeaVersion)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ object QuicklensMacros {
def poorMansLUB: TypeRepr = tpe match {
case AndType(l, r) if l <:< r => l
case AndType(l, r) if r <:< l => r
case AndType(_, _) =>
report.errorAndAbort(s"Implementation limitation: Cannot modify an & type with unrelated types.")
case _ => tpe
}

Expand All @@ -176,6 +178,10 @@ object QuicklensMacros {
extension (term: Term)
def appliedToIfNeeded(args: List[Term]): Term =
if args.isEmpty then term else term.appliedToArgs(args)
def appliedToTypesIfNeeded(args: List[TypeRepr]): Term =
if term.symbol.paramSymss.headOption.toList.flatten.filter(_.isType).nonEmpty then
term.appliedToTypes(args)
else term

def symbolAccessorByNameOrError(obj: Term, name: String): Term = {
val objTpe = obj.tpe.widenAll
Expand Down Expand Up @@ -251,7 +257,7 @@ object QuicklensMacros {
val methodSymbol = methodSymbolByNameOrError(objSymbol, copy.name + "$default$" + i.toString)
// default values in extension methods take the extension receiver as the first parameter
val defaultMethodArgs = argsMap.dropRight(1).flatMap(_.values)
obj.select(methodSymbol).appliedToIfNeeded(defaultMethodArgs)
obj.select(methodSymbol).appliedToTypesIfNeeded(typeParams).appliedToIfNeeded(defaultMethodArgs)
n -> v.getOrElse(defaultMethod)
}.toMap

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ object ModifyAndTypeTest {
case class A(a: Int) extends B
trait B {
def a: Int
def b: Int = 0
}

case class A1(a: Int)
Expand All @@ -26,6 +27,7 @@ class ModifyAndTypeTest extends AnyFlatSpec with Matchers {

val modified = ab.modify(_.a).setTo(1)

modified.b shouldBe 0
modified.a shouldBe 1
}

Expand All @@ -34,22 +36,7 @@ class ModifyAndTypeTest extends AnyFlatSpec with Matchers {

val modified = ab.modify(_.a).setTo(1)

modified.a shouldBe 1
}

it should "modify an & type object 2" in {
val ab: B & A1 = new A1(0) with B

val modified = ab.modify(_.a).setTo(1)

modified.a shouldBe 1
}

it should "modify an & type object 3" in {
val ab: A1 & B = new A1(0) with B

val modified = ab.modify(_.a).setTo(1)

modified.b shouldBe 0
modified.a shouldBe 1
}

Expand Down
Loading