|
| 1 | +/** A test that shows how to use shapeless.Typeable in extractors without the |
| 2 | + * TypeLevel Scala 4 extensions. |
| 3 | + * In essence you have to write |
| 4 | + * |
| 5 | + * case Typeable.instanceOf[T](x) => |
| 6 | + * |
| 7 | + * instead of |
| 8 | + * |
| 9 | + * case Typeable[T](x) |
| 10 | + * |
| 11 | + * The first idiom would be nice to have but it requires more backtracking |
| 12 | + * in Typer that we allow now. Essentially, given |
| 13 | + * |
| 14 | + * case C[T](x) |
| 15 | + * |
| 16 | + * it's unclear whether this should expand to `C[T].unapply(x)`, (as it does now) |
| 17 | + * or to `C.unapply[T](x)` (which is what TypeLevel Scala 4 did, I believe) |
| 18 | + */ |
| 19 | +trait Typeable[T]: |
| 20 | + def cast(x: Any): Option[T] |
| 21 | + def describe: String |
| 22 | + override def toString = s"Typeable[$describe]" |
| 23 | + |
| 24 | +object Typeable: |
| 25 | + def apply[T: Typeable]: Typeable[T] = summon |
| 26 | + |
| 27 | + class instanceOf[T: Typeable]: |
| 28 | + def unapply(x: Any): Option[T] = Typeable[T].cast(x) |
| 29 | + |
| 30 | + given int as Typeable[Int]: |
| 31 | + def cast(x: Any): Option[Int] = x match |
| 32 | + case x: Int => Some(x) |
| 33 | + case _ => None |
| 34 | + def describe = "Int" |
| 35 | + |
| 36 | + given list[T: Typeable] as Typeable[List[T]]: |
| 37 | + def cast(x: Any): Option[List[T]] = x match |
| 38 | + case x: List[_] if x.forall(Typeable[T].cast(_).isDefined) => Some(x.asInstanceOf[List[T]]) |
| 39 | + case _ => None |
| 40 | + def describe = s"List[${Typeable[T].describe}]" |
| 41 | +end Typeable |
| 42 | + |
| 43 | +def testInstance[T: Typeable](x: Any): Unit = |
| 44 | + val isa = x match |
| 45 | + case Typeable.instanceOf[T](x) => "is a" |
| 46 | + case _ => "is not a" |
| 47 | + println(s"$x $isa ${Typeable[T].describe}") |
| 48 | + |
| 49 | +@main def Test() = |
| 50 | + testInstance[Int](1) |
| 51 | + testInstance[List[Int]](List(1, 2, 3)) |
| 52 | + testInstance[Int](List(1, 2, 3)) |
| 53 | + testInstance[List[Int]](1) |
| 54 | + testInstance[Int]("a") |
| 55 | + testInstance[List[Int]](Nil) |
| 56 | + testInstance[List[Int]](1 :: "a" :: Nil) |
| 57 | + testInstance[List[Int]](1 :: 2 :: Nil) |
0 commit comments