Skip to content

Commit a8fedf6

Browse files
committed
Add CaseClass and SingletonObject type classes
1 parent 0fb9116 commit a8fedf6

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object MyBuild extends Build{
1919
//scalacOptions ++= Seq("-Xprint:patmat", "-Xshow-phases"),
2020
testOptions in Test += Tests.Argument(TestFrameworks.ScalaTest, "-oFD"),
2121
parallelExecution := false, // <- until TMap thread-safety issues are resolved
22-
version := "0.5.0",
22+
version := "0.5.1",
2323
organizationName := "Jan Christopher Vogt",
2424
organization := "org.cvogt",
2525
scalacOptions in (Compile, doc) <++= (version,sourceDirectory in Compile,name).map((v,src,n) => Seq(

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ http://cvogt.org/scala-extensions/
44
Contents:
55

66
Type-level constraints (org.cvogt.constraints)
7+
- CaseClass and SingletonObject type classes
78
- Comparisons: <:<, =:=, >:>, !=:=, !<:<, !>:>, e.g. String !=:= And
89
- Boolean Algebra: True, False, ==, !, &&, ||, Implies, Xor
910
- Subset tests: In, NotIn, e.g. Int NotIn (Any,AnyRef,AnyVal)

src/main/scala/constraint.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,43 @@ object !=:={
3838
implicit def prove[Left,Right](implicit ev: ![Left =:= ${Right}]) = new !=:=[Left,Right]
3939
}
4040
*/
41+
42+
import scala.reflect.macros.blackbox
43+
import scala.language.experimental.macros
44+
45+
/**
46+
Type class for case classes
47+
*/
48+
final class CaseClass[T]
49+
object CaseClass{
50+
def checkCaseClassMacro[T:c.WeakTypeTag](c: blackbox.Context) = {
51+
import c.universe._
52+
val T = c.weakTypeOf[T]
53+
if(
54+
!T.typeSymbol.isClass || !T.typeSymbol.asClass.isCaseClass
55+
) c.error(c.enclosingPosition,s"$T does not have case modifier")
56+
q"new _root_.org.cvogt.scala.constraint.CaseClass[$T]"
57+
}
58+
/**
59+
fails compilation if T is not a case class
60+
meaning this can be used as an implicit to check
61+
*/
62+
implicit def checkCaseClass[T]: CaseClass[T] = macro checkCaseClassMacro[T]
63+
}
64+
65+
final class SingletonObject[T]
66+
object SingletonObject{
67+
def checkSingletonObjectMacro[T:c.WeakTypeTag](c: blackbox.Context) = {
68+
import c.universe._
69+
val T = c.weakTypeOf[T]
70+
if(
71+
!T.typeSymbol.isClass || !T.typeSymbol.asClass.isModuleClass
72+
) c.error(c.enclosingPosition,s"$T is not an object")
73+
q"new _root_.org.cvogt.scala.constraint.SingletonObject[$T]"
74+
}
75+
/**
76+
fails compilation if T is not a singleton object class
77+
meaning this can be used as an implicit to check
78+
*/
79+
implicit def checkSingletonObject[T]: SingletonObject[T] = macro checkSingletonObjectMacro[T]
80+
}

src/test/scala/constraint.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import org.cvogt.scala.constraint._
88
trait A
99
trait B extends A
1010
trait C
11-
11+
class ANonCaseClass(i: Int)
12+
case class ACaseClass(i: Int)
13+
case object ACaseObject
14+
object ANonCaseObject
1215
class ConstraintTest extends FunSuite{
1316
test("<:<"){
1417
implicitly[A <:< A]
@@ -71,4 +74,14 @@ class ConstraintTest extends FunSuite{
7174
implicitly[Nothing !=:= String]
7275
implicitly[Nothing !=:= Int]
7376
}
77+
test("CaseClass and SingletonObject type classes"){
78+
implicitly[CaseClass[ACaseClass]]
79+
assertTypeError("implicitly[CaseClass[ANonCaseClass]]")
80+
implicitly[CaseClass[ACaseObject.type]]
81+
assertTypeError("implicitly[CaseClass[ANonCaseObject.type]]")
82+
assertTypeError("implicitly[SingletonObject[ACaseClass]]")
83+
assertTypeError("implicitly[SingletonObject[ANonCaseClass]]")
84+
implicitly[SingletonObject[ACaseObject.type]]
85+
implicitly[SingletonObject[ANonCaseObject.type]]
86+
}
7487
}

0 commit comments

Comments
 (0)