diff --git a/core/src/main/scala/shapeless/generic.scala b/core/src/main/scala/shapeless/generic.scala index 6f4368029..e7aa27ddc 100644 --- a/core/src/main/scala/shapeless/generic.scala +++ b/core/src/main/scala/shapeless/generic.scala @@ -321,7 +321,7 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { def isProductAux(tpe: Type): Boolean = tpe.typeSymbol.isClass && { - val cls = classSym(tpe) + val cls = tpe.typeSymbol.asClass isCaseObjectLike(cls) || isCaseClassLike(cls) || HasApplyUnapply(tpe) || HasCtorUnapply(tpe) } @@ -333,7 +333,7 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { def isCoproduct(tpe: Type): Boolean = tpe.typeSymbol.isClass && { - val cls = classSym(tpe) + val cls = tpe.typeSymbol.asClass (cls.isTrait || cls.isAbstract) && cls.isSealed } @@ -400,18 +400,13 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { } def ctorsOfAux(tpe: Type, hk: Boolean): List[Type] = { - def collectCtors(classSym: ClassSymbol): List[ClassSymbol] = { - classSym.knownDirectSubclasses.toList flatMap { child0 => - val child = child0.asClass - child.typeSignature // Workaround for - if (isCaseClassLike(child) || isCaseObjectLike(child)) - List(child) - else if (child.isSealed) - collectCtors(child) - else - abort(s"$child is not case class like or a sealed trait") + def collectCtors(classSym: ClassSymbol): List[ClassSymbol] = + classSym.knownDirectSubclasses.toList.flatMap { child => + val cls = child.asClass + if (isProductAux(cls.typeSignature)) List(cls) + else if (cls.isSealed) collectCtors(cls) + else abort(s"$cls is not case class like or a sealed trait") } - } if(isProduct(tpe)) List(tpe) @@ -699,27 +694,19 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { } def isSealedHierarchyClassSymbol(symbol: ClassSymbol): Boolean = { - def helper(classSym: ClassSymbol): Boolean = { - classSym.knownDirectSubclasses.toList forall { child0 => - val child = child0.asClass - child.typeSignature // Workaround for - - isCaseClassLike(child) || (child.isSealed && helper(child)) + def helper(classSym: ClassSymbol): Boolean = + classSym.knownDirectSubclasses.toList.forall { child => + val cls = child.asClass + isCaseClassLike(cls) || (cls.isSealed && helper(cls)) } - } symbol.isSealed && helper(symbol) } def classSym(tpe: Type): ClassSymbol = { val sym = tpe.typeSymbol - if (!sym.isClass) - abort(s"$sym is not a class or trait") - - val classSym = sym.asClass - classSym.typeSignature // Workaround for - - classSym + if (!sym.isClass) abort(s"$sym is not a class or trait") + sym.asClass } // See https://github.com/milessabin/shapeless/issues/212 diff --git a/core/src/test/scala/shapeless/generic.scala b/core/src/test/scala/shapeless/generic.scala index 518610134..9b7c97d45 100644 --- a/core/src/test/scala/shapeless/generic.scala +++ b/core/src/test/scala/shapeless/generic.scala @@ -152,6 +152,20 @@ package GenericTestsAux { final case class InTap[A, -B](in: B => A) extends Tap[A] final case class OutTap[A, +B](out: A => B) extends Tap[A] final case class PipeTap[A, B](in: B => A, out: A => B) extends Tap[A] + + sealed trait PubOrPriv + final case class Pub(x: Int) extends PubOrPriv + final class Priv private(val y: String) extends PubOrPriv { + override def equals(that: Any): Boolean = that match { + case that: Priv => this.y == that.y + case _ => false + } + } + + object Priv { + def apply(y: String): Priv = new Priv(y) + def unapply(p: Priv): Some[String] = Some(p.y) + } } class GenericTests { @@ -829,6 +843,7 @@ class GenericTests { illTyped("Generic[Squared]") } + @Test def testCoproductWithFreeTypeParams: Unit = { type Repr[A] = ConstTap[A] :+: InTap[A, _] :+: OutTap[A, _] :+: PipeTap[A, _] :+: CNil val gen = Generic[Tap[String]] @@ -850,6 +865,15 @@ class GenericTests { assertEquals(gen.to(expected), actual) } } + + @Test + def testPublicAndPrivateCoproductChildren: Unit = { + val gen = Generic[PubOrPriv] + assertEquals(Pub(123), gen.from(Inr(Inl(Pub(123))))) + assertEquals(Inr(Inl(Pub(123))), gen.to(Pub(123))) + assertEquals(Priv("secret"), gen.from(Inl(Priv("secret")))) + assertEquals(Inl(Priv("secret")), gen.to(Priv("secret"))) + } } package GenericTestsAux2 {