Skip to content
Open
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
14 changes: 13 additions & 1 deletion core/src/main/scala/magnolia1/magnolia.scala
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,18 @@ object Magnolia {

val isValueClass = genericType <:< AnyValTpe && !primitives.exists(_ =:= genericType)
val resultType = appliedType(typeConstructor, genericType)
val narrowResultType: Type = {
val macroSym = c.macroApplication.symbol
if (macroSym != null && macroSym.isMethod) {
val method = macroSym.asMethod
val tparams = method.typeParams
val rawReturn = method.returnType.asSeenFrom(prefixType, method.owner)
val substituted =
if (tparams.size == 1) rawReturn.substituteTypes(tparams, List(genericType))
else rawReturn
if (substituted <:< resultType) substituted else resultType
} else resultType
}
val typeName = c.freshName(TermName("typeName"))

def typeNameOf(tpe: Type): Tree = {
Expand Down Expand Up @@ -714,7 +726,7 @@ object Magnolia {

for (term <- result)
yield q"""{
${deferredVal(assignedName, resultType, term)}
${deferredVal(assignedName, narrowResultType, term)}
$assignedName
}"""
}
Expand Down
18 changes: 18 additions & 0 deletions examples/src/main/scala/magnolia1/examples/exportedAuto.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package magnolia1.examples

import magnolia1.{CaseClass, Magnolia, SealedTrait}

class ExportedTypeclassAuto[T]()

object ExportedTypeclassAuto {
type Typeclass[T] = ExportedTypeclassAuto[T]
case class Exported[T]() extends ExportedTypeclassAuto[T]
def join[T](ctx: CaseClass[Typeclass, T]): Exported[T] = Exported()
def split[T](ctx: SealedTrait[Typeclass, T]): Exported[T] = Exported()

implicit val intInstance: Typeclass[Int] = new ExportedTypeclassAuto()
implicit val stringInstance: Typeclass[String] = new ExportedTypeclassAuto()
implicit def seqInstance[T: Typeclass]: Typeclass[Seq[T]] = new ExportedTypeclassAuto()

implicit def gen[T]: Exported[T] = macro Magnolia.gen[T]
}
33 changes: 33 additions & 0 deletions test/src/test/scala/magnolia1/tests/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ case class Portfolio(companies: Company*)

case class Recursive(children: Seq[Recursive])

sealed trait RecursiveSum
case object RecursiveSumLeaf extends RecursiveSum
case class RecursiveSumNode(next: RecursiveSum) extends RecursiveSum

sealed trait MutuallyRecA
case object MutuallyRecALeaf extends MutuallyRecA
case class MutuallyRecANode(b: MutuallyRecB) extends MutuallyRecA
sealed trait MutuallyRecB
case object MutuallyRecBLeaf extends MutuallyRecB
case class MutuallyRecBNode(a: MutuallyRecA) extends MutuallyRecB

sealed trait BranchingRec
case object BranchingRecLeaf extends BranchingRec
case class BranchingRecNode(left: BranchingRec, right: BranchingRec) extends BranchingRec

// This tests compilation.
class GenericCsv[A: Csv]
object ParamCsv extends GenericCsv[Param]
Expand Down Expand Up @@ -848,6 +863,24 @@ class Tests extends munit.FunSuite {
|""".stripMargin)
}

test("recursive sealed trait derivation returns the narrow result type") {
val instance: ExportedTypeclass.Exported[RecursiveSum] = ExportedTypeclass.gen[RecursiveSum]
assert(instance != null)
}

test("mutually recursive sealed traits preserve narrow result type") {
val a: ExportedTypeclassAuto.Exported[MutuallyRecA] = ExportedTypeclassAuto.gen[MutuallyRecA]
val b: ExportedTypeclassAuto.Exported[MutuallyRecB] = ExportedTypeclassAuto.gen[MutuallyRecB]
assert(a != null)
assert(b != null)
}

test("branching recursive sealed trait preserves narrow result type") {
val instance: ExportedTypeclass.Exported[BranchingRec] = ExportedTypeclass.gen[BranchingRec]
assert(instance != null)
}


test("report an error when an abstract member of a sealed hierarchy is not sealed") {
val error = compileErrors("Show.gen[Parent]")
assert(error contains "magnolia: child trait BadChild of trait Parent is not sealed")
Expand Down
Loading