Skip to content

Commit 79c8e5d

Browse files
authored
Merge pull request #1256 from joroKr21/custom-unappy-backport
When case class has custom unapply, reference getters instead
2 parents afa492d + 5ca40dd commit 79c8e5d

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

core/src/main/scala/shapeless/generic.scala

+15-6
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,14 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
368368
* */
369369
def fieldsOf(tpe: Type): List[(TermName, Type)] = {
370370
val clazz = tpe.typeSymbol.asClass
371+
// Case class field names have an extra space at the end.
372+
val nameOf: TermSymbol => TermName =
373+
if (!clazz.isCaseClass) _.name
374+
else field => TermName(field.name.toString.dropRight(1))
371375
if (isCaseObjectLike(clazz) || isAnonOrRefinement(clazz)) Nil
372376
else tpe.decls.sorted.collect {
373-
case sym: TermSymbol if isCaseAccessorLike(sym) =>
374-
(sym.name, sym.typeSignatureIn(tpe).finalResultType)
377+
case field: TermSymbol if isCaseAccessorLike(field) =>
378+
nameOf(field) -> field.typeSignatureIn(tpe).finalResultType
375379
}
376380
}
377381

@@ -496,11 +500,14 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
496500
}
497501
}
498502

499-
def nameAsString(name: Name): String = name.decodedName.toString.trim
503+
def nameAsString(name: Name): String =
504+
name.decodedName.toString
500505

501-
def nameAsValue(name: Name): Constant = Constant(nameAsString(name))
506+
def nameAsValue(name: Name): Constant =
507+
Constant(nameAsString(name))
502508

503-
def nameOf(tpe: Type) = tpe.typeSymbol.name
509+
def nameOf(tpe: Type): Name =
510+
tpe.typeSymbol.name
504511

505512
def mkHListValue(elems: List[Tree]): Tree = {
506513
val cons = objectRef[::.type]
@@ -1030,8 +1037,10 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
10301037
(const(singleton), const(objectRef[HNil.type]))
10311038
// case 3: case class
10321039
case tpe if tpe.typeSymbol.asClass.isCaseClass =>
1040+
val companion = patchedCompanionSymbolOf(tpe.typeSymbol)
1041+
val unapply = companion.typeSignature.member(TermName("unapply"))
10331042
val fields = fieldsOf(tpe)
1034-
(fromApply(fields), toUnapply(fields))
1043+
(fromApply(fields), if (unapply.isSynthetic) toUnapply(fields) else toGetters(fields))
10351044
// case 4: exactly one matching public apply/unapply
10361045
case HasApplyUnapply(args) =>
10371046
(fromApply(args), toUnapply(args))
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package shapeless
22

3-
import shapeless.test.illTyped
3+
import org.junit.Assert.assertEquals
4+
import org.junit.Test
5+
import shapeless.test.{illTyped, typed}
6+
import shapeless.testutil.assertTypedEquals
47

58
object GenericTests213 {
69
case class WrongApplySignature private(value: String)
@@ -9,5 +12,26 @@ object GenericTests213 {
912
def apply(v: String): Either[String, WrongApplySignature] = Left("No ways")
1013
}
1114

15+
case class CCWithCustomUnapply(x: Int, y: String)
16+
object CCWithCustomUnapply {
17+
def unapply(cc: CCWithCustomUnapply): Option[(Int, String, String)] = None
18+
}
19+
}
20+
21+
class GenericTests213 {
22+
import GenericTests213._
23+
1224
illTyped("Generic[WrongApplySignature]")
25+
26+
@Test
27+
def testCCWithCustomUnapply(): Unit = {
28+
val cc = CCWithCustomUnapply(23, "foo")
29+
val gen = Generic[CCWithCustomUnapply]
30+
val r = gen.to(cc)
31+
val f = gen.from(13 :: "bar" :: HNil)
32+
assertTypedEquals[Int :: String :: HNil](23 :: "foo" :: HNil, r)
33+
typed[CCWithCustomUnapply](f)
34+
assertEquals(13, f.x)
35+
assertEquals("bar", f.y)
36+
}
1337
}

0 commit comments

Comments
 (0)