aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Pretty <jon.pretty@propensive.com>2017-06-30 21:41:09 +0100
committerGitHub <noreply@github.com>2017-06-30 21:41:09 +0100
commitf257d2a616529b75b379407911d27b8021b7c751 (patch)
tree666e2e64fc982ebe34af94a3ab9d86a3b38a40cd
parent447c044ae8e1759fbaaf285338d0ad8cd74332e6 (diff)
parent1b894b9482c5019ed7a9c95d492a74eefb6084ff (diff)
downloadmagnolia-f257d2a616529b75b379407911d27b8021b7c751.tar.gz
magnolia-f257d2a616529b75b379407911d27b8021b7c751.tar.bz2
magnolia-f257d2a616529b75b379407911d27b8021b7c751.zip
Merge pull request #14 from propensive/better-api
Made a nicer API for inclusion
-rw-r--r--core/src/main/scala/magnolia.scala65
-rw-r--r--examples/src/main/scala/cats.scala4
-rw-r--r--examples/src/main/scala/eq.scala3
-rw-r--r--tests/shared/src/main/scala/magnolia/main.scala9
4 files changed, 40 insertions, 41 deletions
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala
index 2ebf116..8f52be7 100644
--- a/core/src/main/scala/magnolia.scala
+++ b/core/src/main/scala/magnolia.scala
@@ -5,6 +5,7 @@ import macrocompat.bundle
import scala.collection.immutable.ListMap
import language.existentials
import language.higherKinds
+import language.experimental.macros
@bundle
class Macros(val c: whitebox.Context) {
@@ -74,7 +75,7 @@ class Macros(val c: whitebox.Context) {
val updatedStack = currentStack.copy(errors = error :: currentStack.errors)
recursionStack = recursionStack.updated(c.enclosingPosition, updatedStack)
- c.abort(c.enclosingPosition, s"Could not find type class for type $genericType")
+ c.abort(c.enclosingPosition, s"Could not find typeclass for type $genericType")
}
}
@@ -215,7 +216,7 @@ class Macros(val c: whitebox.Context) {
}
}
- def magnolia[T: WeakTypeTag, Typeclass: WeakTypeTag]: Tree = {
+ def magnolia[T: WeakTypeTag, Typeclass: WeakTypeTag, DerivationType: WeakTypeTag]: Tree = {
import scala.util.{Try, Success, Failure}
val genericType: Type = weakTypeOf[T]
@@ -226,32 +227,22 @@ class Macros(val c: whitebox.Context) {
val directlyReentrant = Some(genericType) == currentStack.frames.headOption.map(_.genericType)
val typeConstructor: Type = weakTypeOf[Typeclass].typeConstructor
- val derivationTypeclass = weakTypeOf[Derivation[_]].typeConstructor
- val coderivationTypeclass = weakTypeOf[Coderivation[_]].typeConstructor
- val coderivation2Typeclass = weakTypeOf[Coderivation2[_]].typeConstructor
-
- val derivationType = appliedType(derivationTypeclass, List(typeConstructor))
- val coderivationType = appliedType(coderivationTypeclass, List(typeConstructor))
- val coderivation2Type = appliedType(coderivation2Typeclass, List(typeConstructor))
-
- def findDerivationImplicit[T <: GeneralDerivationImplicit](derivationType: c.Type, wrap: Tree => T):
- Try[GeneralDerivationImplicit] =
- Try(wrap(c.untypecheck(c.inferImplicitValue(derivationType, false, false))))
-
- val derivationImplicit =
- findDerivationImplicit(derivationType, DerivationImplicit)
- .orElse(findDerivationImplicit(coderivationType, Coderivation1Implicit))
- .orElse(findDerivationImplicit(coderivation2Type,
- Coderivation2Implicit)) match {
- case Failure(e) =>
- c.info(c.enclosingPosition, s"could not find an implicit instance of "+
- s"Derivation[$typeConstructor] or "+
- s"Coderivation[$typeConstructor] or "+
- s"Coderivation2[$typeConstructor]", true)
- throw e
- case Success(di) =>
- di
- }
+ val DerivationTypeclass = weakTypeOf[Derivation[_]].typeConstructor
+ val CoderivationTypeclass = weakTypeOf[Coderivation[_]].typeConstructor
+ val Coderivation2Typeclass = weakTypeOf[Coderivation2[_]].typeConstructor
+
+ val derivationType = appliedType(DerivationTypeclass, List(typeConstructor))
+ val coderivationType = appliedType(CoderivationTypeclass, List(typeConstructor))
+ val coderivation2Type = appliedType(Coderivation2Typeclass, List(typeConstructor))
+
+ val derivationImplicit = weakTypeOf[DerivationType].typeConstructor match {
+ case DerivationTypeclass =>
+ DerivationImplicit(c.prefix.tree)
+ case CoderivationTypeclass =>
+ Coderivation1Implicit(c.prefix.tree)
+ case Coderivation2Typeclass =>
+ Coderivation2Implicit(c.prefix.tree)
+ }
if(directlyReentrant) throw DirectlyReentrantException()
@@ -280,9 +271,8 @@ class Macros(val c: whitebox.Context) {
result.map { tree =>
if(currentStack.frames.isEmpty) c.untypecheck(removeLazy.transform(tree)) else tree
}.getOrElse {
- c.abort(c.enclosingPosition, "could not infer typeclass for type $genericType")
+ c.abort(c.enclosingPosition, s"could not infer typeclass for type $genericType")
}
-
}
}
@@ -328,7 +318,7 @@ private[magnolia] object CompileTimeState {
private[magnolia] var emittedErrors: Set[ImplicitNotFound] = Set()
}
-trait Derivation[Typeclass[_]] {
+abstract class Derivation[Typeclass[_]] {
type Value
def dereference(value: Value, param: String): Value
def call[T](typeclass: Typeclass[T], value: Value): T
@@ -336,19 +326,28 @@ trait Derivation[Typeclass[_]] {
def combine[Supertype, Right <: Supertype](left: Typeclass[_ <: Supertype],
right: Typeclass[Right]): Typeclass[Supertype]
+
+ implicit def generic[T]: Typeclass[T] = macro Macros.magnolia[T, Typeclass[_],
+ Derivation[Tc] forSome { type Tc[_] }]
}
-trait Coderivation[Typeclass[_]] {
+abstract class Coderivation[Typeclass[_]] {
type Return
def call[T](typeclass: Typeclass[T], value: T): Return
def construct[T](body: T => Return): Typeclass[T]
def join(name: String, elements: ListMap[String, Return]): Return
+
+ implicit def generic[T]: Typeclass[T] = macro Macros.magnolia[T, Typeclass[_],
+ Coderivation[Tc] forSome { type Tc[_] }]
}
-trait Coderivation2[Typeclass[_]] {
+abstract class Coderivation2[Typeclass[_]] {
type Return
def call[T](typeclass: Typeclass[T], value1: T, value2: T): Return
def construct[T](body: (T, T) => Return): Typeclass[T]
def join(name: String, elements: ListMap[String, Return]): Return
+
+ implicit def generic[T]: Typeclass[T] = macro Macros.magnolia[T, Typeclass[_],
+ Coderivation2[Tc] forSome { type Tc[_] }]
}
diff --git a/examples/src/main/scala/cats.scala b/examples/src/main/scala/cats.scala
index 18ed805..2283ce0 100644
--- a/examples/src/main/scala/cats.scala
+++ b/examples/src/main/scala/cats.scala
@@ -8,8 +8,7 @@ import magnolia.{Coderivation, Macros}
object catsShowDerivation {
- implicit val showDerivation: Coderivation[Show] =
- new Coderivation[Show] {
+ val ShowDerivation = new Coderivation[Show] {
type Return = String
def call[T](show: Show[T], value: T): String = show.show(value)
def construct[T](body: T => String): Show[T] = body(_)
@@ -17,5 +16,4 @@ object catsShowDerivation {
xs.map { case (k, v) => s"$k=$v" }.mkString(s"$name(", ", ", ")")
}
- implicit def genericShow[T]: Show[T] = macro Macros.magnolia[T, Show[_]]
}
diff --git a/examples/src/main/scala/eq.scala b/examples/src/main/scala/eq.scala
index 141a4e0..5a4c9fa 100644
--- a/examples/src/main/scala/eq.scala
+++ b/examples/src/main/scala/eq.scala
@@ -36,7 +36,7 @@ object Eq {
implicit val eqInt: Eq[Int] = _ == _
- implicit val derivation: Coderivation2[Eq] = new Coderivation2[Eq] {
+ val derivation: Coderivation2[Eq] = new Coderivation2[Eq] {
type Return = Boolean
def call[T](eq: Eq[T], value1: T, value2: T): Boolean =
@@ -47,5 +47,4 @@ object Eq {
elements.forall(_._2)
}
- implicit def generic[T]: Eq[T] = macro Macros.magnolia[T, Eq[_]]
}
diff --git a/tests/shared/src/main/scala/magnolia/main.scala b/tests/shared/src/main/scala/magnolia/main.scala
index c6cd9bc..9d7accb 100644
--- a/tests/shared/src/main/scala/magnolia/main.scala
+++ b/tests/shared/src/main/scala/magnolia/main.scala
@@ -1,9 +1,10 @@
package magnolia
-import examples.{Address, Branch, Country, Entity, Leaf, Person}
+import examples.{Address, Branch, Country, Entity, Leaf, Person, Eq}
import cats.instances.all._
import cats.syntax.all._
-import examples.catsShowDerivation._
+import examples.catsShowDerivation.ShowDerivation.generic
+import examples.catsShowDerivation.ShowDerivation
import language.experimental.macros
object Main {
@@ -12,10 +13,12 @@ object Main {
val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3))
println(tree1.show)
- println(tree1 isEqualTo tree1)
println(List[Entity](Person("John Smith",
Address(List("1 High Street", "London", "SW1A 1AA"),
Country("UK", "GBR", false)))).show)
+
+ import Eq.derivation.generic
+ println(tree1 isEqualTo tree1)
}
}