aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Pretty <jon.pretty@propensive.com>2017-10-31 11:11:58 +0100
committerJon Pretty <jon.pretty@propensive.com>2017-10-31 11:11:58 +0100
commit88f36a7a552246e210266a7ae82a2e480718512e (patch)
tree1bce74641f237d081f3d18fc7e5897ecfb2441b8
parent7b776425828d27b3112ad5bddafaa7564c326536 (diff)
downloadmagnolia-88f36a7a552246e210266a7ae82a2e480718512e.tar.gz
magnolia-88f36a7a552246e210266a7ae82a2e480718512e.tar.bz2
magnolia-88f36a7a552246e210266a7ae82a2e480718512e.zip
Support nontrivial type constructors
-rw-r--r--core/src/main/scala/magnolia.scala22
-rw-r--r--examples/src/main/scala/typeclasses.scala15
-rw-r--r--tests/src/main/scala/tests.scala14
3 files changed, 19 insertions, 32 deletions
diff --git a/core/src/main/scala/magnolia.scala b/core/src/main/scala/magnolia.scala
index ae582e4..c2b280f 100644
--- a/core/src/main/scala/magnolia.scala
+++ b/core/src/main/scala/magnolia.scala
@@ -30,30 +30,14 @@ trait JoinContext[Tc[_], T] {
object Magnolia {
import CompileTimeState._
- type Construct[Call[_], T] = ((Call[R] => R) forSome { type R }) => T
-
def generic[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
import scala.util.{Try, Success, Failure}
- def javaClassName(sym: Symbol): String =
- if(sym.owner.isPackage) sym.fullName
- else if(sym.owner.isModuleClass) s"${javaClassName(sym.owner)}$$${sym.name}"
- else s"${javaClassName(sym.owner)}.${sym.name}"
-
- def getModule[M](tpe: Type): M = {
- val typeName = javaClassName(tpe.typeSymbol)
+ val typeConstructor: c.Type =
+ c.prefix.tree.tpe.member(TypeName("Typeclass")).asType.toType.typeConstructor
- try {
- val cls = Class.forName(s"$typeName$$")
- cls.getField("MODULE$").get(cls).asInstanceOf[M]
- } catch {
- case e: ClassNotFoundException =>
- c.abort(c.enclosingPosition, s"""Class "${typeName}" could not be found. This usually means you are trying to use an interpolator in the same compilation unit as the one in which you defined it. Please try compiling interpolators first, separately from the code using them.""")
- }
- }
-
- val typeConstructor: c.Type = c.prefix.tree.tpe.companion.typeConstructor
+ println(typeConstructor)
def findType(key: Type): Option[TermName] =
recursionStack(c.enclosingPosition).frames.find(_.genericType == key).map(_.termName(c))
diff --git a/examples/src/main/scala/typeclasses.scala b/examples/src/main/scala/typeclasses.scala
index ed59eda..589a075 100644
--- a/examples/src/main/scala/typeclasses.scala
+++ b/examples/src/main/scala/typeclasses.scala
@@ -12,23 +12,25 @@ import scala.annotation.unchecked.uncheckedVariance
object Show {
- def join[T](context: JoinContext[Show, T])(value: T): String = context.parameters.map { param =>
+ 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 split[T](subclasses: List[Subclass[Show, T]])(value: T): String =
+ def split[T](subclasses: List[Subclass[Typeclass, T]])(value: T): String =
subclasses.map { sub => sub.cast.andThen { value =>
sub.typeclass.show(sub.cast(value))
} }.reduce(_ orElse _)(value)
- implicit val string: Show[String] = identity
- implicit val int: Show[Int] = new Show[Int] { def show(s: Int): String = s.toString }
- implicit def generic[T]: Show[T] = macro Magnolia.generic[T]
+ implicit val string: Show[String, String] = identity
+ implicit val int: Show[String, Int] = new Show[String, Int] { def show(s: Int): String = s.toString }
+ implicit def generic[T]: Show[String, T] = macro Magnolia.generic[T]
}
-trait Show[T] { def show(value: T): String }
+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)) }
@@ -45,6 +47,7 @@ object Eq {
trait Eq[T] { def equal(value: T, value2: T): Boolean }
object Default {
+ type Typeclass[T] = Default[T]
def join[T](context: JoinContext[Default, T]): Default[T] = new Default[T] {
def default = context.construct { param => param.typeclass.default }
}
diff --git a/tests/src/main/scala/tests.scala b/tests/src/main/scala/tests.scala
index 6bfa1bd..ee3faf0 100644
--- a/tests/src/main/scala/tests.scala
+++ b/tests/src/main/scala/tests.scala
@@ -27,7 +27,7 @@ object Tests extends TestApp {
test("serialize a Branch") {
import magnolia.examples._
- implicitly[Show[Branch]].show(Branch(Leaf("LHS"), Leaf("RHS")))
+ implicitly[Show[String, Branch]].show(Branch(Leaf("LHS"), Leaf("RHS")))
}.assert(_ == "Branch(left=Leaf(value=LHS),right=Leaf(value=RHS))")
test("test equality false") {
@@ -52,23 +52,23 @@ object Tests extends TestApp {
test("construction of Show instance for Leaf") {
scalac"""
import magnolia.examples._
- implicitly[Show[Leaf]]
+ implicitly[Show[String, Leaf]]
"""
- }.assert(_ == (Returns(fqt"magnolia.examples.Show[magnolia.examples.Leaf]"): Compilation))
+ }.assert(_ == (Returns(fqt"magnolia.examples.Show[String,magnolia.examples.Leaf]"): Compilation))
test("construction of Show instance for Tree") {
scalac"""
import magnolia.examples._
- implicitly[Show[Tree]]
+ implicitly[Show[String, Tree]]
"""
- }.assert(_ == (Returns(fqt"magnolia.examples.Show[magnolia.examples.Tree]"): Compilation))
+ }.assert(_ == (Returns(fqt"magnolia.examples.Show[String,magnolia.examples.Tree]"): Compilation))
test("serialize a Leaf") {
- implicitly[Show[Leaf]].show(Leaf("testing"))
+ implicitly[Show[String, Leaf]].show(Leaf("testing"))
}.assert(_ == "Leaf(value=testing)")
test("serialize a Branch as a Tree") {
- implicitly[Show[Tree]].show(Branch(Leaf("LHS"), Leaf("RHS")))
+ implicitly[Show[String, Tree]].show(Branch(Leaf("LHS"), Leaf("RHS")))
}.assert(_ == "Branch(left=Leaf(value=LHS),right=Leaf(value=RHS))")
test("show error stack") {