aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Pretty <jon.pretty@propensive.com>2017-11-10 23:14:30 +0000
committerGitHub <noreply@github.com>2017-11-10 23:14:30 +0000
commit089f14a261b4766cb44140d768b5ff81958ec4e3 (patch)
treecc1f53f0c80860d20498958766d99d23829b18bf
parent484bf11403f65edd178432992fd573810d0706e8 (diff)
parent15d57e45c6892b99c8d6ce674f4e661009b9ab98 (diff)
downloadmagnolia-089f14a261b4766cb44140d768b5ff81958ec4e3.tar.gz
magnolia-089f14a261b4766cb44140d768b5ff81958ec4e3.tar.bz2
magnolia-089f14a261b4766cb44140d768b5ff81958ec4e3.zip
Merge pull request #34 from propensive/additional-derivation-help
Include warnings if `combine` or `dispatch` methods are missing
-rw-r--r--core/src/main/scala/magnolia.scala26
-rw-r--r--tests/src/main/scala/tests.scala2
2 files changed, 22 insertions, 6 deletions
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala
index 31ae745..de5f187 100644
--- a/core/src/main/scala/magnolia.scala
+++ b/core/src/main/scala/magnolia.scala
@@ -74,7 +74,7 @@ object Magnolia {
val prefixType = c.prefix.tree.tpe
def companionRef(tpe: Type): Tree = {
- val global = c.universe.asInstanceOf[scala.tools.nsc.Global]
+ val global = c.universe match { case global: scala.tools.nsc.Global => global }
val globalTpe = tpe.asInstanceOf[global.Type]
val companion = globalTpe.typeSymbol.companionSymbol
if(companion != NoSymbol) global.gen.mkAttributedRef(globalTpe.prefix, companion).asInstanceOf[Tree]
@@ -86,7 +86,7 @@ object Magnolia {
tpe.asType.toType.asSeenFrom(prefixType, cls)
}
}
-
+
val typeConstructorOpt =
typeDefs.headOption.map(_.typeConstructor)
@@ -95,6 +95,22 @@ object Magnolia {
"magnolia: the derivation object does not define the Typeclass type constructor")
}
+ def checkMethod(termName: String, category: String, expected: String) = {
+ val term = TermName(termName)
+ val combineClass = c.prefix.tree.tpe.baseClasses.find { cls =>
+ cls.asType.toType.decl(term) != NoSymbol
+ }.getOrElse {
+ c.abort(c.enclosingPosition, s"magnolia: the method `$termName` must be defined on the derivation object to derive typeclasses for $category")
+ }
+ val firstParamBlock = combineClass.asType.toType.decl(term).asTerm.asMethod.paramLists.head
+ if(firstParamBlock.length != 1) c.abort(c.enclosingPosition,
+ s"magnolia: the method `combine` should take a single parameter of type $expected")
+ }
+
+ // FIXME: Only run these methods if they're used, particularly `dispatch`
+ checkMethod("combine", "case classes", "CaseClass[Typeclass, _]")
+ checkMethod("dispatch", "sealed traits", "SealedTrait[Typeclass, _]")
+
def findType(key: Type): Option[TermName] =
recursionStack(c.enclosingPosition).frames.find(_.genericType == key).map(_.termName(c))
@@ -193,11 +209,11 @@ object Magnolia {
val resultType = appliedType(typeConstructor, genericType)
- // FIXME: Handle AnyVals
val result = if (isCaseObject) {
// FIXME: look for an alternative which isn't deprecated on Scala 2.12+
val obj = companionRef(genericType)
val className = genericType.typeSymbol.name.decodedName.toString
+
val impl = q"""
${c.prefix}.combine($magnoliaObj.caseClass[$typeConstructor, $genericType](
$className, true, false, new $arrayCls(0), _ => $obj)
@@ -271,7 +287,7 @@ object Magnolia {
${param.name.decodedName.toString}, $ref, $defaultVal, _.${param.name}
)"""
}
-
+
Some(
Typeclass(
genericType,
@@ -331,7 +347,7 @@ object Magnolia {
(t: $genericType) => t.asInstanceOf[$typ]
)"""
}
-
+
Some {
Typeclass(
genericType,
diff --git a/tests/src/main/scala/tests.scala b/tests/src/main/scala/tests.scala
index 242bd41..e453502 100644
--- a/tests/src/main/scala/tests.scala
+++ b/tests/src/main/scala/tests.scala
@@ -136,7 +136,7 @@ object Tests extends TestApp {
}.assert(_ == "Blue()")
test("decode a company") {
- implicitly[Decoder[Company]].decode("""Company(name=Acme Inc)""")
+ Decoder.gen[Company].decode("""Company(name=Acme Inc)""")
}.assert(_ == Company("Acme Inc"))
test("decode a Person as an Entity") {