From 1b894b9482c5019ed7a9c95d492a74eefb6084ff Mon Sep 17 00:00:00 2001 From: Jon Pretty Date: Fri, 30 Jun 2017 22:38:42 +0200 Subject: Made a nicer API for inclusion --- core/src/main/scala/magnolia.scala | 65 ++++++++++++------------- examples/src/main/scala/cats.scala | 4 +- examples/src/main/scala/eq.scala | 3 +- tests/shared/src/main/scala/magnolia/main.scala | 9 ++-- 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) } } -- cgit v1.2.3