Skip to content

Commit 69fd3d1

Browse files
authored
Merge pull request #1272 from joroKr21/implicit-params
Capture implicit parameters at Generic materialization time
2 parents 0fe4020 + a505dd4 commit 69fd3d1

File tree

2 files changed

+35
-32
lines changed

2 files changed

+35
-32
lines changed

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

+21-25
Original file line numberDiff line numberDiff line change
@@ -673,18 +673,23 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
673673
else mkCoproductTypTree1(ctorsOf1(tpe), param, arg)
674674
}
675675

676+
/** Returns the parameter lists of `tpe`, removing any implicit parameters. */
677+
private def nonImplicitParamLists(tpe: Type): List[List[Symbol]] =
678+
tpe.paramLists.takeWhile(params => params.isEmpty || !params.head.isImplicit)
679+
676680
def isCaseClassLike(sym: ClassSymbol): Boolean = {
677681
def isConcrete = !(sym.isAbstract || sym.isTrait || sym == symbolOf[Object])
678682
def isFinalLike = sym.isFinal || sym.knownDirectSubclasses.isEmpty
679-
def ctor = for {
680-
ctor <- accessiblePrimaryCtorOf(sym.typeSignature)
681-
Seq(params) <- Option(ctor.typeSignature.paramLists)
682-
if params.size == fieldsOf(sym.typeSignature).size
683-
} yield ctor
684-
sym.isCaseClass || (isConcrete && isFinalLike && ctor.isDefined)
683+
def constructor = for {
684+
constructor <- accessiblePrimaryCtorOf(sym.typeSignature)
685+
Seq(params) <- Option(nonImplicitParamLists(constructor.typeSignature))
686+
if params.length == fieldsOf(sym.typeSignature).length
687+
} yield constructor
688+
sym.isCaseClass || (isConcrete && isFinalLike && constructor.isDefined)
685689
}
686690

687-
def isCaseObjectLike(sym: ClassSymbol): Boolean = sym.isModuleClass
691+
def isCaseObjectLike(sym: ClassSymbol): Boolean =
692+
sym.isModuleClass
688693

689694
def isCaseAccessorLike(sym: TermSymbol): Boolean = {
690695
val isGetter =
@@ -867,27 +872,18 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
867872
def numNonCaseParamLists(tpe: Type): Int = {
868873
val companion = patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature
869874
val apply = companion.member(TermName("apply"))
870-
if (apply.isMethod && !isNonGeneric(apply) && isAccessible(companion, apply)) {
871-
val paramLists = apply.typeSignatureIn(companion).paramLists
872-
val numParamLists = paramLists.length
873-
if (numParamLists <= 1) 0
874-
else {
875-
if (paramLists.last.headOption.map(_.isImplicit).getOrElse(false))
876-
numParamLists-2
877-
else
878-
numParamLists-1
879-
}
880-
} else 0
875+
if (!apply.isMethod || isNonGeneric(apply) || !isAccessible(companion, apply)) 0
876+
else nonImplicitParamLists(apply.typeSignatureIn(companion)).length.max(1) - 1
881877
}
882878

883879
object HasApply {
884880
def unapply(tpe: Type): Option[List[(TermName, Type)]] = for {
885881
companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature)
886-
apply = companion.member(TermName("apply"))
882+
apply <- Option(companion.member(TermName("apply")))
887883
if apply.isTerm && !apply.asTerm.isOverloaded
888884
if apply.isMethod && !isNonGeneric(apply)
889885
if isAccessible(companion, apply)
890-
Seq(params) <- Option(apply.typeSignatureIn(companion).paramLists)
886+
Seq(params) <- Option(nonImplicitParamLists(apply.typeSignatureIn(companion)))
891887
aligned <- alignFields(tpe, for (param <- params)
892888
yield param.name.toTermName -> param.typeSignature)
893889
} yield aligned
@@ -896,20 +892,20 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
896892
object HasUnapply {
897893
def unapply(tpe: Type): Option[List[Type]] = for {
898894
companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature)
899-
unapply = companion.member(TermName("unapply"))
895+
unapply <- Option(companion.member(TermName("unapply")))
900896
if unapply.isTerm && !unapply.asTerm.isOverloaded
901897
if unapply.isMethod && !isNonGeneric(unapply)
902898
if isAccessible(companion, unapply)
903-
returnTpe <- unapply.asMethod.typeSignatureIn(companion).finalResultType
899+
returnTpe <- unapply.typeSignatureIn(companion).finalResultType
904900
.baseType(symbolOf[Option[_]]).typeArgs.headOption
905901
} yield if (returnTpe <:< typeOf[Product]) returnTpe.typeArgs else List(returnTpe)
906902
}
907903

908904
object HasUniqueCtor {
909905
def unapply(tpe: Type): Option[List[(TermName, Type)]] = for {
910-
ctor <- accessiblePrimaryCtorOf(tpe)
911-
if !isNonGeneric(ctor)
912-
Seq(params) <- Option(ctor.typeSignatureIn(tpe).paramLists)
906+
constructor <- accessiblePrimaryCtorOf(tpe)
907+
if !isNonGeneric(constructor)
908+
Seq(params) <- Option(nonImplicitParamLists(constructor.typeSignatureIn(tpe)))
913909
aligned <- alignFields(tpe, for (param <- params)
914910
yield param.name.toTermName -> param.typeSignature)
915911
} yield aligned

core/src/test/scala/shapeless/generic.scala

+14-7
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,12 @@ package GenericTestsAux {
138138
}
139139

140140
case class CCOrdered[A: Ordering](value: A)
141-
class CCLikeOrdered[A: Ordering](val value: A)
141+
class CCLikeOrdered[A: Ordering](val value: A) {
142+
override def equals(that: Any): Boolean = that match {
143+
case that: CCLikeOrdered[_] => this.value == that.value
144+
case _ => false
145+
}
146+
}
142147

143148
case class CCDegen(i: Int)()
144149
class CCLikeDegen(val i: Int)()
@@ -817,13 +822,15 @@ class GenericTests {
817822
@Test
818823
def testGenericImplicitParams: Unit = {
819824
type Repr = Int :: HNil
820-
val gen = Generic[CCOrdered[Int]]
821-
val cc = CCOrdered(42)
825+
val gen1 = Generic[CCOrdered[Int]]
826+
val gen2 = Generic[CCLikeOrdered[Int]]
827+
val cc1 = CCOrdered(42)
828+
val cc2 = new CCLikeOrdered(42)
822829
val rep = 42 :: HNil
823-
824-
assertTypedEquals[CCOrdered[Int]](gen.from(rep), cc)
825-
assertTypedEquals[Repr](gen.to(cc), rep)
826-
illTyped("Generic[CCLikeOrdered[Int]]")
830+
assertTypedEquals[CCOrdered[Int]](gen1.from(rep), cc1)
831+
assertTypedEquals[CCLikeOrdered[Int]](gen2.from(rep), cc2)
832+
assertTypedEquals[Repr](gen1.to(cc1), rep)
833+
assertTypedEquals[Repr](gen2.to(cc2), rep)
827834
}
828835

829836
@Test

0 commit comments

Comments
 (0)