aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt2
-rw-r--r--core/src/main/scala/magnolia.scala42
-rw-r--r--examples/src/main/scala/example.scala7
-rw-r--r--tests/shared/src/main/scala/magnolia/main.scala2
4 files changed, 33 insertions, 20 deletions
diff --git a/build.sbt b/build.sbt
index e943e73..db54f76 100644
--- a/build.sbt
+++ b/build.sbt
@@ -48,7 +48,7 @@ lazy val buildSettings = Seq(
organization := "com.propensive",
scalaVersion := "2.12.2",
name := "magnolia",
- version := "0.1.0",
+ version := "0.2.0",
scalacOptions ++= Seq("-deprecation", "-feature", "-Ywarn-value-discard", "-Ywarn-dead-code", "-Ywarn-nullary-unit", "-Ywarn-numeric-widen", "-Ywarn-inaccessible", "-Ywarn-adapted-args"),
crossScalaVersions := Seq("2.10.6", "2.11.11", "2.12.2"),
scmInfo := Some(ScmInfo(url("https://github.com/propensive/magnolia"),
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala
index 08210f8..d2978b5 100644
--- a/core/src/main/scala/magnolia.scala
+++ b/core/src/main/scala/magnolia.scala
@@ -3,6 +3,7 @@ package magnolia
import scala.reflect._, macros._
import macrocompat.bundle
import scala.util.Try
+import scala.collection.immutable.ListMap
import language.existentials
import language.higherKinds
@@ -92,9 +93,11 @@ class Macros(val c: whitebox.Context) {
val resultType = appliedType(typeConstructor, genericType)
val construct = if(isCaseClass) {
- val implicits = genericType.decls.collect {
+ val caseClassParameters = genericType.decls.collect {
case m: MethodSymbol if m.isCaseAccessor => m.asMethod
- }.map { param =>
+ }
+
+ val implicits = caseClassParameters.map { param =>
val paramName = param.name.encodedName.toString
val derivedImplicit = recurse(ProductType(paramName, genericType.toString), genericType,
@@ -122,11 +125,20 @@ class Macros(val c: whitebox.Context) {
case Left(_) =>
Some(q"new $genericType(..$implicits)")
case Right(impl) =>
- Some(q"$impl.join(_root_.scala.List(..$implicits))")
+ val namedImplicits = caseClassParameters.zip(implicits).map { case (param, tree) =>
+ q"(${param.name.encodedName.toString}, $tree)"
+ }
+
+ Some(q"$impl.join(_root_.scala.collection.immutable.ListMap(..$namedImplicits))")
}
} else if(isSealedTrait) {
val subtypes = classType.get.knownDirectSubclasses.to[List]
+
+ if(subtypes.isEmpty) {
+ c.info(c.enclosingPosition, s"could not find any direct subtypes of $typeSymbol", true)
+ c.abort(c.enclosingPosition, "")
+ }
Some {
val components = subtypes.map(_.asType.toType).map { searchType =>
@@ -160,20 +172,14 @@ class Macros(val c: whitebox.Context) {
construct.map { const =>
val impl = derivationImplicit.merge
- val res = q"""{
+ q"""{
def $assignedName: $resultType = $impl.construct { sourceParameter => $const }
$assignedName
}"""
-
- try c.typecheck(res) catch {
- case e: Exception =>
- e.printStackTrace()
- }
- res
}
}
- def magnolia[T: WeakTypeTag, Typeclass: WeakTypeTag]: Tree = try {
+ def magnolia[T: WeakTypeTag, Typeclass: WeakTypeTag]: Tree = {
val genericType: Type = weakTypeOf[T]
val currentStack: Stack = recursionStack.get(c.enclosingPosition).getOrElse(Stack(List(), List()))
@@ -189,7 +195,14 @@ class Macros(val c: whitebox.Context) {
Left(c.untypecheck(c.inferImplicitValue(coDerivationType, false, false)))
} catch {
case e: Exception =>
- Right(c.untypecheck(c.inferImplicitValue(contraDerivationType)))
+ try Right(c.untypecheck(c.inferImplicitValue(contraDerivationType, false, false))) catch {
+ case e: Exception =>
+ c.info(c.enclosingPosition, s"could not find an implicit instance of "+
+ s"CovariantDerivation[$typeConstructor] or "+
+ s"ContravariantDerivation[$typeConstructor]", true)
+
+ throw e
+ }
}
if(directlyReentrant) throw DirectlyReentrantException()
@@ -228,9 +241,6 @@ class Macros(val c: whitebox.Context) {
c.abort(c.enclosingPosition, "could not infer typeclass for type $genericType")
}
- } catch {
- case DirectlyReentrantException() => ???
- case e: Exception => e.printStackTrace(); ???
}
}
@@ -290,6 +300,6 @@ trait ContravariantDerivation[Typeclass[_]] {
type Return
def call[T](typeclass: Typeclass[T], value: T): Return
def construct[T](body: T => Return): Typeclass[T]
- def join(elements: List[Return]): Return
+ def join(elements: ListMap[String, Return]): Return
}
diff --git a/examples/src/main/scala/example.scala b/examples/src/main/scala/example.scala
index 9301a0d..e649b88 100644
--- a/examples/src/main/scala/example.scala
+++ b/examples/src/main/scala/example.scala
@@ -4,6 +4,7 @@ import magnolia._
import language.experimental.macros
import language.higherKinds
+import collection.immutable.ListMap
object `package` {
implicit class Showable[T: Show](t: T) {
@@ -15,9 +16,11 @@ object `package` {
implicit def showSet[T: Show]: Show[Set[T]] = s => "set"
}
+sealed trait EmptyType
+
sealed trait Tree
case class Branch(left: Tree, right: Tree) extends Tree
-case class Leaf(value: Int) extends Tree
+case class Leaf(value: Int, no: EmptyType) extends Tree
sealed trait Entity
case class Person(name: String, address: Address) extends Entity
@@ -32,7 +35,7 @@ object Show extends Show_1 {
type Return = String
def call[T](show: Show[T], value: T): String = show.show(value)
def construct[T](body: T => String): Show[T] = body(_)
- def join(xs: List[String]): String = xs.mkString("(", ", ", ")")
+ def join(xs: ListMap[String, String]): String = xs.map { case (k, v) => s"$k=$v" }.mkString("{", ", ", "}")
}
}
diff --git a/tests/shared/src/main/scala/magnolia/main.scala b/tests/shared/src/main/scala/magnolia/main.scala
index 727eb1f..014ec33 100644
--- a/tests/shared/src/main/scala/magnolia/main.scala
+++ b/tests/shared/src/main/scala/magnolia/main.scala
@@ -4,7 +4,7 @@ import examples._
object Main {
def main(args: Array[String]): Unit = {
- println(Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)).show)
+ println(Branch(Branch(Leaf(1, null), Leaf(2, null)), Leaf(3, null)).show)
println(List[Entity](Person("John Smith",
Address(List("1 High Street", "London", "SW1A 1AA"),
Country("UK", "GBR", false)))).show)