Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When accessing current values of fields, try the field symbol first before the method symbol #246

Merged
merged 1 commit into from
Sep 17, 2024
Merged
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
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()))
}

}
Loading