diff options
-rw-r--r-- | build.sbt | 3 | ||||
-rw-r--r-- | core/src/main/scala/magnolia.scala | 34 | ||||
-rw-r--r-- | examples/src/main/scala/typeclasses.scala | 24 | ||||
-rw-r--r-- | tests/src/main/scala/adt.scala | 2 | ||||
-rw-r--r-- | tests/src/main/scala/tests.scala | 4 |
5 files changed, 34 insertions, 33 deletions
@@ -9,6 +9,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform) .settings(buildSettings: _*) .settings(publishSettings: _*) .settings(scalaMacroDependencies: _*) + .settings(examplesDependencies) .settings(moduleName := "magnolia") .nativeSettings(nativeSettings) @@ -149,7 +150,7 @@ lazy val scalaMacroDependencies: Seq[Setting[_]] = Seq( lazy val examplesDependencies: Seq[Setting[_]] = Seq( libraryDependencies += "org.typelevel" %% "cats-core" % "0.9.0", - libraryDependencies += "com.propensive" %% "estrapade" % "1.0.0", + libraryDependencies += "com.propensive" %% "estrapade" % "1.0.2", libraryDependencies += "com.propensive" %% "contextual-data" % "1.0.3" ) diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala index 4d3d3d3..9d345ac 100644 --- a/core/src/main/scala/magnolia.scala +++ b/core/src/main/scala/magnolia.scala @@ -78,11 +78,7 @@ object Magnolia { val genericTypeName: String = genericType.typeSymbol.name.encodedName.toString.toLowerCase val assignedName: TermName = TermName(c.freshName(s"${genericTypeName}Typeclass")) recurse(ChainedImplicit(genericType.toString), genericType, assignedName) { - val inferredImplicit = c.inferImplicitValue(searchType, false, false) - q"""{ - def $assignedName: $searchType = $inferredImplicit - $assignedName - }""" + c.inferImplicitValue(searchType, false, false) }.get }.toOption.orElse(directInferImplicit(genericType, typeConstructor)) } @@ -116,7 +112,7 @@ object Magnolia { val resultType = appliedType(typeConstructor, genericType) // FIXME: Handle AnyVals - if(isCaseObject) { + val result = if(isCaseObject) { val termSym = genericType.typeSymbol.companionSymbol val obj = termSym.asTerm val className = obj.name.toString @@ -128,11 +124,7 @@ object Magnolia { def isObject = true }) """ - - Some(q""" - def $assignedName: $resultType = $impl - $assignedName - """) + Some(impl) } else if(isCaseClass) { val caseClassParameters = genericType.decls.collect { case m: MethodSymbol if m.isCaseAccessor => m.asMethod @@ -171,7 +163,7 @@ object Magnolia { q"fn($call).asInstanceOf[${imp._3}]" } })""" - val impl = q""" + q""" ${c.prefix}.join(new _root_.magnolia.JoinContext[$typeConstructor, $genericType] { def construct[R](fn: ((Param[${typeConstructor}, $genericType]) => Any)): $genericType = $constructor def typeName: _root_.java.lang.String = $className @@ -180,11 +172,6 @@ object Magnolia { def isObject = false }) """ - - q""" - def $assignedName: $resultType = $impl - $assignedName - """ } } else if(isSealedTrait) { val genericSubtypes = classType.get.knownDirectSubclasses.to[List] @@ -224,16 +211,19 @@ object Magnolia { }""" } - val impl = q"""{ + q"""{ ${c.prefix}.split(_root_.scala.collection.immutable.List[_root_.magnolia.Subclass[$typeConstructor, $genericType]](..$subclasses)) }""" - q""" - def $assignedName: $resultType = $impl - $assignedName - """ } } else None + + result.map { r => + q"""{ + def $assignedName: $resultType = $r + $assignedName + }""" + } } val genericType: Type = weakTypeOf[T] diff --git a/examples/src/main/scala/typeclasses.scala b/examples/src/main/scala/typeclasses.scala index b4af6d0..c79a6d7 100644 --- a/examples/src/main/scala/typeclasses.scala +++ b/examples/src/main/scala/typeclasses.scala @@ -13,9 +13,11 @@ import scala.annotation.unchecked.uncheckedVariance object Show { type Typeclass[T] = Show[String, T] - def join[T](context: JoinContext[Typeclass, T])(value: T): String = context.parameters.map { param => - s"${param.label}=${param.typeclass.show(param.dereference(value))}" - }.mkString(s"${context.typeName.split("\\.").last}(", ",", ")") + def join[T](context: JoinContext[Typeclass, T]): Show[String, T] = new Show[String, T] { + def show(value: T) = context.parameters.map { param => + s"${param.label}=${param.typeclass.show(param.dereference(value))}" + }.mkString(s"${context.typeName.split("\\.").last}(", ",", ")") + } def split[T](subclasses: List[Subclass[Typeclass, T]])(value: T): String = subclasses.map { sub => sub.cast.andThen { value => @@ -31,13 +33,17 @@ trait Show[Out, T] { def show(value: T): Out } object Eq { type Typeclass[T] = Eq[T] - def join[T](context: JoinContext[Eq, T])(value1: T, value2: T): Boolean = - context.parameters.forall { param => param.typeclass.equal(param.dereference(value1), param.dereference(value2)) } + def join[T](context: JoinContext[Eq, T]): Eq[T] = new Eq[T] { + def equal(value1: T, value2: T) = + context.parameters.forall { param => param.typeclass.equal(param.dereference(value1), param.dereference(value2)) } + } - def split[T](subclasses: List[Subclass[Eq, T]])(value1: T, value2: T): Boolean = - subclasses.map { case subclass => - subclass.cast.andThen { value => subclass.typeclass.equal(subclass.cast(value1), subclass.cast(value2)) } - }.reduce(_ orElse _)(value1) + def split[T](subclasses: List[Subclass[Eq, T]]): Eq[T] = new Eq[T] { + def equal(value1: T, value2: T) = + subclasses.map { case subclass => + subclass.cast.andThen { value => subclass.typeclass.equal(subclass.cast(value1), subclass.cast(value2)) } + }.reduce(_ orElse _)(value1) + } implicit val string: Eq[String] = _ == _ implicit val int: Eq[Int] = _ == _ diff --git a/tests/src/main/scala/adt.scala b/tests/src/main/scala/adt.scala index 75316aa..6d8a276 100644 --- a/tests/src/main/scala/adt.scala +++ b/tests/src/main/scala/adt.scala @@ -3,5 +3,5 @@ package adt import magnolia._, examples._ object Gen { - Eq.generic[Alphabet] + Show.generic[Alphabet] } diff --git a/tests/src/main/scala/tests.scala b/tests/src/main/scala/tests.scala index 64d6594..f269643 100644 --- a/tests/src/main/scala/tests.scala +++ b/tests/src/main/scala/tests.scala @@ -13,6 +13,8 @@ object Tests extends TestApp { def tests() = { import examples._ + compileTimeRestart() + test("construct a Show product instance") { import examples._ Show.generic[Person].show(Person("John Smith", 34)) @@ -86,6 +88,8 @@ object Tests extends TestApp { //test("construct a decoder") { //Decoder.generic[Tree[String]].decode("string") //}.assert(_ == (Leaf("something"): Tree[String])) + + compileTimeReport() } } |