Skip to content

Commit

Permalink
Merge pull request #246 from softwaremill/fix-i245
Browse files Browse the repository at this point in the history
When accessing current values of fields, try the field symbol first before the method symbol
  • Loading branch information
adamw authored Sep 17, 2024
2 parents b0ef525 + 25d8c0e commit cf9df42
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,13 @@ object QuicklensMacros {
def symbolAccessorByNameOrError(sym: Symbol, name: String): Symbol = {
val mem = sym.fieldMember(name)
if mem != Symbol.noSymbol then mem
else report.errorAndAbort(noSuchMember(sym.name, name))
else symbolMethodByNameOrError(sym, name)
}

def symbolMethodByNameOrError(sym: Symbol, name: String): Symbol = {
sym.methodMember(name) match
case List(m) => m
case Nil => symbolAccessorByNameOrError(sym, name)
case Nil => report.errorAndAbort(noSuchMember(sym.name, name))
case _ => report.errorAndAbort(multipleMatchingMethods(sym.name, name))
}

Expand Down Expand Up @@ -202,9 +202,10 @@ object QuicklensMacros {
obj: Term,
fields: Seq[(PathSymbol.Field, Seq[PathTree])]
): Term = {
val objSymbol = obj.tpe.widenAll.matchingTypeSymbol
val objTpe = obj.tpe.widenAll
val objSymbol = objTpe.matchingTypeSymbol
if isSum(objSymbol) then {
obj.tpe.widenAll match {
objTpe match {
case AndType(_, _) =>
report.errorAndAbort(
s"Implementation limitation: Cannot modify sealed hierarchies mixed with & types. Try providing a more specific type."
Expand Down Expand Up @@ -235,15 +236,15 @@ object QuicklensMacros {
} else if isProduct(objSymbol) || isProductLike(objSymbol) then {
val copy = symbolMethodByNameOrError(objSymbol, "copy")
val argsMap: Map[String, Term] = fields.map { (field, trees) =>
val fieldMethod = symbolMethodByNameOrError(objSymbol, field.name)
val fieldMethod = symbolAccessorByNameOrError(objSymbol, field.name)
val resTerm: Term = trees.foldLeft[Term](Select(obj, fieldMethod)) { (term, tree) =>
mapToCopy(owner, mod, term, tree)
}
val namedArg = NamedArg(field.name, resTerm)
field.name -> namedArg
}.toMap

val typeParams = obj.tpe.widenAll match {
val typeParams = objTpe match {
case AppliedType(_, typeParams) => Some(typeParams)
case _ => None
}
Expand Down Expand Up @@ -272,7 +273,7 @@ object QuicklensMacros {
case _ => Apply(Select(obj, copy), args)
}
} else
report.errorAndAbort(s"Unsupported source object: must be a case class or sealed trait, but got: $objSymbol")
report.errorAndAbort(s"Unsupported source object: must be a case class or sealed trait, but got: $objSymbol of type ${objTpe.show} (${obj.show})")
}

def applyFunctionDelegate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,18 @@ class ExplicitCopyTest extends AnyFlatSpec with Matchers {
modified.show shouldEqual expected.show
}

it should "modify a class that has a method with the same name as a field" in {
final case class PathItem()
final case class Paths(
pathItems: Map[String, PathItem] = Map.empty
)
final case class Docs(
paths: Paths = Paths()
) {
def paths(paths: Paths): Docs = copy(paths = paths)
}
val docs = Docs()
docs.modify(_.paths.pathItems).using(m => m + ("a" -> PathItem()))
}

}

0 comments on commit cf9df42

Please sign in to comment.