diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | build.sbt | 4 | ||||
-rw-r--r-- | core/src/main/scala/magnolia.scala | 19 | ||||
-rw-r--r-- | examples/src/main/scala/cats.scala | 22 | ||||
-rw-r--r-- | examples/src/main/scala/eq.scala (renamed from examples/src/main/scala/example.scala) | 38 | ||||
-rw-r--r-- | tests/shared/src/main/scala/magnolia/main.scala | 16 |
6 files changed, 52 insertions, 51 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7f1455 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target +.jvm +.js +.native @@ -23,6 +23,7 @@ lazy val examples = crossProject(JSPlatform, JVMPlatform, NativePlatform) .settings(publishSettings: _*) .settings(moduleName := "magnolia-examples") .settings(quasiQuotesDependencies) + .settings(examplesDependencies) .nativeSettings(nativeSettings) .dependsOn(core) @@ -132,6 +133,9 @@ lazy val scalaMacroDependencies: Seq[Setting[_]] = Seq( libraryDependencies += compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) ) +lazy val examplesDependencies: Seq[Setting[_]] = Seq( + libraryDependencies += "org.typelevel" %% "cats-core" % "0.9.0") + credentials ++= (for { username <- Option(System.getenv().get("SONATYPE_USERNAME")) password <- Option(System.getenv().get("SONATYPE_PASSWORD")) diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala index 66d59d0..e2d1341 100644 --- a/core/src/main/scala/magnolia.scala +++ b/core/src/main/scala/magnolia.scala @@ -221,8 +221,8 @@ class Macros(val c: whitebox.Context) { val contraDerivationType = appliedType(contraDerivationTypeclass, List(typeConstructor)) val contraDerivation2Type = appliedType(contraDerivation2Typeclass, List(typeConstructor)) - def findDerivationImplicit[T <: DerivationImplicit](tpe: c.Type, cons: Tree => T): Try[DerivationImplicit] = - Try(cons(c.untypecheck(c.inferImplicitValue(tpe, false, false)))) + def findDerivationImplicit[T <: DerivationImplicit](derivationType: c.Type, wrap: Tree => T): Try[DerivationImplicit] = + Try(wrap(c.untypecheck(c.inferImplicitValue(derivationType, false, false)))) val derivationImplicit = findDerivationImplicit(coDerivationType, CovariantDerivationImplicit) @@ -258,17 +258,12 @@ class Macros(val c: whitebox.Context) { val searchType = appliedType(typeConstructor, genericType) Some(q"_root_.magnolia.Lazy[$searchType]($methodAsString)") } - } else { - directInferImplicit(genericType, typeConstructor, derivationImplicit) - } + } else directInferImplicit(genericType, typeConstructor, derivationImplicit) - if(currentStack.frames.isEmpty) recursionStack = Map() + if(currentStack.frames.isEmpty) recursionStack = ListMap() result.map { tree => - if(currentStack.frames.isEmpty) { - val res = c.untypecheck(removeLazy.transform(tree)) - res - } else tree + if(currentStack.frames.isEmpty) c.untypecheck(removeLazy.transform(tree)) else tree }.getOrElse { c.abort(c.enclosingPosition, "could not infer typeclass for type $genericType") } @@ -312,8 +307,8 @@ private[magnolia] object CompileTimeState { def termName(c: whitebox.Context): c.TermName = term.asInstanceOf[c.TermName] } - private[magnolia] var recursionStack: Map[api.Position, Stack] = - Map() + private[magnolia] var recursionStack: ListMap[api.Position, Stack] = + ListMap() private[magnolia] var emittedErrors: Set[ImplicitNotFound] = Set() } diff --git a/examples/src/main/scala/cats.scala b/examples/src/main/scala/cats.scala new file mode 100644 index 0000000..8d33a0f --- /dev/null +++ b/examples/src/main/scala/cats.scala @@ -0,0 +1,22 @@ +package magnolia.examples + +import scala.collection.immutable.ListMap +import scala.language.experimental.macros + +import cats.Show +import magnolia.ContravariantDerivation +import magnolia.Macros + +object catsShowDerivation { + + implicit val showDerivation: ContravariantDerivation[Show] = + new ContravariantDerivation[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(_) + def join(xs: ListMap[String, String]): String = + xs.map { case (k, v) => s"$k=$v" }.mkString("{", ", ", "}") + } + + implicit def genericShow[T]: Show[T] = macro Macros.magnolia[T, Show[_]] +} diff --git a/examples/src/main/scala/example.scala b/examples/src/main/scala/eq.scala index 543fa3d..30e7869 100644 --- a/examples/src/main/scala/example.scala +++ b/examples/src/main/scala/eq.scala @@ -3,25 +3,19 @@ package magnolia.examples import magnolia._ import language.experimental.macros -import language.higherKinds import collection.immutable.ListMap object `package` { - implicit class Showable[T: Show](t: T) { - def show: String = implicitly[Show[T]].show(t) - } - implicit val showString: Show[String] = identity - implicit val showBool: Show[Boolean] = _.toString - implicit def showList[T: Show]: Show[List[T]] = xs => xs.map { x => s"list:${implicitly[Show[T]].show(x)}" }.mkString(";") - implicit def showSet[T: Show]: Show[Set[T]] = s => "set" - implicit class Equable[T: Eq](t: T) { def isEqualTo(other: T): Boolean = implicitly[Eq[T]].isEqual(t, other) } + implicit val eqString: Eq[String] = _ == _ implicit val eqBool: Eq[Boolean] = _ == _ + implicit def eqList[T: Eq]: Eq[List[T]] = (l1, l2) => l1.size == l2.size && (l1 zip l2).forall { case (e1, e2) => e1 isEqualTo e2 } + implicit def eqSet[T: Eq]: Eq[Set[T]] = (s1, s2) => s1.size == s2.size && (s1 zip s2).forall { case (e1, e2) => e1 isEqualTo e2 } } @@ -36,37 +30,21 @@ case class Organization(name: String, contacts: Set[Person]) extends Entity case class Address(lines: List[String], country: Country) case class Country(name: String, code: String, salesTax: Boolean) -trait Show[T] { def show(t: T): String } -object Show extends Show_1 { - implicit val showInt: Show[Int] = _.toString - implicit val derivation = new ContravariantDerivation[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(_) - def join(xs: ListMap[String, String]): String = xs.map { case (k, v) => s"$k=$v" }.mkString("{", ", ", "}") - } -} - -trait Show_1 { - implicit def generic[T]: Show[T] = macro Macros.magnolia[T, Show[_]] -} - trait Eq[T] { def isEqual(a: T, b: T): Boolean } -object Eq extends Eq_1 { +object Eq { implicit val eqInt: Eq[Int] = _ == _ - implicit val derivation = new ContravariantDerivation2[Eq] { + implicit val derivation: ContravariantDerivation2[Eq] = new ContravariantDerivation2[Eq] { type Return = Boolean + def call[T](eq: Eq[T], value1: T, value2: T): Boolean = if(value1.getClass == value2.getClass) eq.isEqual(value1, value2) else false + def construct[T](body: (T, T) => Boolean): Eq[T] = body(_, _) def join(elements: ListMap[String, Boolean]): Boolean = elements.forall(_._2) } -} - -trait Eq_1 { + 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 3ac3fb6..c6cd9bc 100644 --- a/tests/shared/src/main/scala/magnolia/main.scala +++ b/tests/shared/src/main/scala/magnolia/main.scala @@ -1,23 +1,21 @@ package magnolia -import examples._ +import examples.{Address, Branch, Country, Entity, Leaf, Person} +import cats.instances.all._ +import cats.syntax.all._ +import examples.catsShowDerivation._ +import language.experimental.macros object Main { - def main(args: Array[String]): Unit = { - val tree1: Tree = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)) - val tree2: Tree = Branch(Leaf(1), Leaf(2)) + def main(args: Array[String]): Unit = { + val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)) println(tree1.show) println(tree1 isEqualTo tree1) - println(tree1 isEqualTo tree2) - println(Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)).show) - println(List[Entity](Person("John Smith", Address(List("1 High Street", "London", "SW1A 1AA"), Country("UK", "GBR", false)))).show) - } } - |