diff options
-rw-r--r-- | build.sbt | 2 | ||||
-rw-r--r-- | core/src/main/scala/magnolia.scala | 42 | ||||
-rw-r--r-- | examples/src/main/scala/example.scala | 7 | ||||
-rw-r--r-- | tests/shared/src/main/scala/magnolia/main.scala | 2 |
4 files changed, 33 insertions, 20 deletions
@@ -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) |