object Test
{
object Variances extends Enumeration {
val CO, IN, CONTRA = Value
}
import Variances.{ CO, IN, CONTRA }
object SubtypeRelationship extends Enumeration {
val NONE, SAME, SUB, SUPER = Value
}
import SubtypeRelationship.{ NONE, SAME, SUB, SUPER }
class VarianceTester[T, U, CC[_]](expected: Variances.Value)(
implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) {
def elements = List(ev1 <:< ev2, ev2 <:< ev1)
def containers = List(ev3 <:< ev4, ev4 <:< ev3)
def isUnrelated = typeCompare[T, U] == NONE
def isSame = typeCompare[T, U] == SAME
def isSub = typeCompare[T, U] == SUB
def isSuper = typeCompare[T, U] == SUPER
def showsCovariance = (elements == containers)
def showsContravariance = (elements == containers.reverse)
def showsInvariance = containers forall (_ == isSame)
def allContainerVariances = List(showsCovariance, showsInvariance, showsContravariance)
def showsExpectedVariance =
if (isUnrelated) allContainerVariances forall (_ == false)
else if (isSame) allContainerVariances forall (_ == true)
else expected match {
case CO => showsCovariance && !showsContravariance && !showsInvariance
case IN => showsInvariance && !showsCovariance && !showsContravariance
case CONTRA => showsContravariance && !showsCovariance && !showsInvariance
}
}
def showsCovariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
new VarianceTester[T, U, CC](CO) showsExpectedVariance
def showsInvariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
new VarianceTester[T, U, CC](IN) showsExpectedVariance
def showsContravariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
new VarianceTester[T, U, CC](CONTRA) showsExpectedVariance
def typeCompare[T, U](implicit ev1: Manifest[T], ev2: Manifest[U]) = (ev1 <:< ev2, ev2 <:< ev1) match {
case (true, true) => SAME
case (true, false) => SUB
case (false, true) => SUPER
case (false, false) => NONE
}
def assertAnyRef[T: Manifest] = List(
manifest[T] <:< manifest[Any],
manifest[T] <:< manifest[AnyRef],
!(manifest[T] <:< manifest[AnyVal])
) foreach (assert(_, "assertAnyRef"))
def assertAnyVal[T: Manifest] = List(
manifest[T] <:< manifest[Any],
!(manifest[T] <:< manifest[AnyRef]),
manifest[T] <:< manifest[AnyVal]
) foreach (assert(_, "assertAnyVal"))
def assertSameType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SAME, "assertSameType")
def assertSuperType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SUPER, "assertSuperType")
def assertSubType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SUB, "assertSubType")
def assertNoRelationship[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == NONE, "assertNoRelationship")
def testVariancesVia[T: Manifest, U: Manifest] = assert(
typeCompare[T, U] == SUB &&
showsCovariance[T, U, List] &&
showsInvariance[T, U, Set],
"testVariancesVia"
)
def runAllTests = {
assertAnyVal[AnyVal]
assertAnyVal[Unit]
assertAnyVal[Int]
assertAnyVal[Double]
assertAnyVal[Boolean]
assertAnyVal[Char]
assertAnyRef[AnyRef]
assertAnyRef[java.lang.Object]
assertAnyRef[java.lang.Integer]
assertAnyRef[java.lang.Double]
assertAnyRef[java.lang.Boolean]
assertAnyRef[java.lang.Character]
assertAnyRef[String]
assertAnyRef[scala.List[String]]
assertAnyRef[scala.List[_]]
// variance doesn't work yet
// testVariancesVia[String, Any]
// testVariancesVia[String, AnyRef]
assertSubType[List[String], List[Any]]
assertSubType[List[String], List[AnyRef]]
assertNoRelationship[List[String], List[AnyVal]]
assertSubType[List[Int], List[Any]]
assertSubType[List[Int], List[AnyVal]]
assertNoRelationship[List[Int], List[AnyRef]]
// Nothing
assertSubType[Nothing, Any]
assertSubType[Nothing, AnyVal]
assertSubType[Nothing, AnyRef]
assertSubType[Nothing, String]
assertSubType[Nothing, List[String]]
assertSubType[Nothing, Null]
assertSameType[Nothing, Nothing]
// Null
assertSubType[Null, Any]
assertNoRelationship[Null, AnyVal]
assertSubType[Null, AnyRef]
assertSubType[Null, String]
assertSubType[Null, List[String]]
assertSameType[Null, Null]
assertSuperType[Null, Nothing]
// Any
assertSameType[Any, Any]
assertSuperType[Any, AnyVal]
assertSuperType[Any, AnyRef]
assertSuperType[Any, String]
assertSuperType[Any, List[String]]
assertSuperType[Any, Null]
assertSuperType[Any, Nothing]
// Misc unrelated types
assertNoRelationship[Unit, AnyRef]
assertNoRelationship[Unit, Int]
assertNoRelationship[Int, Long]
assertNoRelationship[Boolean, String]
assertNoRelationship[List[Boolean], List[String]]
assertNoRelationship[Set[Boolean], Set[String]]
}
def main(args: Array[String]): Unit = runAllTests
}