Skip to content

Add Typeable test #9840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/run/Typeable.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
1 is a Int
List(1, 2, 3) is a List[Int]
List(1, 2, 3) is not a Int
1 is not a List[Int]
a is not a Int
List() is a List[Int]
List(1, a) is not a List[Int]
List(1, 2) is a List[Int]
57 changes: 57 additions & 0 deletions tests/run/Typeable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/** A test that shows how to use shapeless.Typeable in extractors without the
* TypeLevel Scala 4 extensions.
* In essence you have to write
*
* case Typeable.instanceOf[T](x) =>
*
* instead of
*
* case Typeable[T](x)
*
* The first idiom would be nice to have but it requires more backtracking
* in Typer that we allow now. Essentially, given
*
* case C[T](x)
*
* it's unclear whether this should expand to `C[T].unapply(x)`, (as it does now)
* or to `C.unapply[T](x)` (which is what TypeLevel Scala 4 did, I believe)
*/
trait Typeable[T]:
def cast(x: Any): Option[T]
def describe: String
override def toString = s"Typeable[$describe]"

object Typeable:
def apply[T: Typeable]: Typeable[T] = summon

class instanceOf[T: Typeable]:
def unapply(x: Any): Option[T] = Typeable[T].cast(x)

given int as Typeable[Int]:
def cast(x: Any): Option[Int] = x match
case x: Int => Some(x)
case _ => None
def describe = "Int"

given list[T: Typeable] as Typeable[List[T]]:
def cast(x: Any): Option[List[T]] = x match
case x: List[_] if x.forall(Typeable[T].cast(_).isDefined) => Some(x.asInstanceOf[List[T]])
case _ => None
def describe = s"List[${Typeable[T].describe}]"
end Typeable

def testInstance[T: Typeable](x: Any): Unit =
val isa = x match
case Typeable.instanceOf[T](x) => "is a"
case _ => "is not a"
println(s"$x $isa ${Typeable[T].describe}")

@main def Test() =
testInstance[Int](1)
testInstance[List[Int]](List(1, 2, 3))
testInstance[Int](List(1, 2, 3))
testInstance[List[Int]](1)
testInstance[Int]("a")
testInstance[List[Int]](Nil)
testInstance[List[Int]](1 :: "a" :: Nil)
testInstance[List[Int]](1 :: 2 :: Nil)