diff options
author | odersky <odersky@gmail.com> | 2017-03-09 10:20:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-09 10:20:25 +0100 |
commit | 8e5c9c4a1a4555883307b7e81fea064134f350f2 (patch) | |
tree | e2feee0b87ed785e32ed8ba8fa2953128498f917 /tests/run | |
parent | 6abaa109e1add82f4add605a5cb3243e34b1ee33 (diff) | |
parent | c7f1f35c36593ac9454c8572a59c649610829b6a (diff) | |
download | dotty-8e5c9c4a1a4555883307b7e81fea064134f350f2.tar.gz dotty-8e5c9c4a1a4555883307b7e81fea064134f350f2.tar.bz2 dotty-8e5c9c4a1a4555883307b7e81fea064134f350f2.zip |
Merge pull request #2045 from dotty-staging/fix-hlist-hmap
Fix type inference for HLists and HMaps
Diffstat (limited to 'tests/run')
-rw-r--r-- | tests/run/HLists-nonvariant.check | 8 | ||||
-rw-r--r-- | tests/run/HLists-nonvariant.scala | 78 | ||||
-rw-r--r-- | tests/run/HLists.check | 8 | ||||
-rw-r--r-- | tests/run/HLists.scala | 78 | ||||
-rw-r--r-- | tests/run/hmap-covariant.scala | 97 | ||||
-rw-r--r-- | tests/run/i2004.check | 1 | ||||
-rw-r--r-- | tests/run/i2004.scala | 11 |
7 files changed, 281 insertions, 0 deletions
diff --git a/tests/run/HLists-nonvariant.check b/tests/run/HLists-nonvariant.check new file mode 100644 index 000000000..53efe30d7 --- /dev/null +++ b/tests/run/HLists-nonvariant.check @@ -0,0 +1,8 @@ +1 +A +true +true +HCons(1,HCons(A,HCons(true,HNil))) +1 +A +true diff --git a/tests/run/HLists-nonvariant.scala b/tests/run/HLists-nonvariant.scala new file mode 100644 index 000000000..a3a639bcd --- /dev/null +++ b/tests/run/HLists-nonvariant.scala @@ -0,0 +1,78 @@ +sealed trait HList +case class HCons[HD, TL](hd: HD, tl: TL) extends HList +case object HNil extends HList + +sealed trait Num +case object Zero extends Num +case class Succ[N <: Num](pred: N) extends Num + +object Test { + + type HNil = HNil.type + type Zero = Zero.type + + trait Concat[Xs <: HList, Ys <: HList, Zs <: HList] { + def concat(xs: Xs, ys: Ys): Zs + } + + implicit def concatNil[Xs <: HList]: Concat[HNil, Xs, Xs] = + new Concat[HNil, Xs, Xs] { + def concat(fst: HNil, snd: Xs) = snd + } + + implicit def concatCons[X, Xs <: HList, Ys <: HList, Zs <: HList]( + implicit ev: Concat[Xs, Ys, Zs] + ): Concat[HCons[X, Xs], Ys, HCons[X, Zs]] = + new Concat[HCons[X, Xs], Ys, HCons[X, Zs]] { + def concat(xs: HCons[X, Xs], ys: Ys): HCons[X, Zs] = + HCons(xs.hd, ev.concat(xs.tl, ys)) + } + + def concat[Xs <: HList, Ys <: HList, Zs <: HList](xs: Xs, ys: Ys)(implicit ev: Concat[Xs, Ys, Zs]): Zs = + ev.concat(xs, ys) + + val xs = HCons(1, HCons("A", HNil)) + val ys = HCons(true, HNil) + val zs = concat(xs, ys) + val zs1: HCons[Int, HCons[String, HCons[Boolean, HNil]]] = zs + + trait At[Xs <: HList, N <: Num] { + type Out + def at(xs: Xs, n: N): Out + } + + implicit def atZero[XZ, Xs <: HList]: At[HCons[XZ, Xs], Zero] { type Out = XZ } = + new At[HCons[XZ, Xs], Zero] { + type Out = XZ + def at(xs: HCons[XZ, Xs], n: Zero) = xs.hd + } + + implicit def atSucc[XX, Xs <: HList, N <: Num]( + implicit ev: At[Xs, N] + ): At[HCons[XX, Xs], Succ[N]] { type Out = ev.Out } = new At[HCons[XX, Xs], Succ[N]] { + type Out = ev.Out + def at(xs: HCons[XX, Xs], n: Succ[N]): Out = ev.at(xs.tl, n.pred) + } + + def at[Xs <: HList, N <: Num](xs: Xs, n: N)( + implicit ev: At[Xs, N] + ): ev.Out = ev.at(xs, n) + + def main(args: Array[String]) = { + val ys1 = HCons(1, HNil) + println(at(ys1, Zero)) + + val ys2 = HCons(1, HCons("A", HNil)) + val y2 = at(ys2, Succ(Zero)) + println(at(ys2, Succ(Zero))) + val ys3 = HCons(1, HCons("A", HCons(true, HNil))) + println(at(ys3, Succ(Succ(Zero)))) + val ys4 = HCons(1, HCons("A", HCons(true, HCons(1.0, HNil)))) + println(at(ys4, Succ(Succ(Zero)))) + + println(zs1) + println(at(zs1, Zero)) + println(at(zs1, Succ(Zero))) + println(at(zs1, Succ(Succ(Zero)))) + } +} diff --git a/tests/run/HLists.check b/tests/run/HLists.check new file mode 100644 index 000000000..53efe30d7 --- /dev/null +++ b/tests/run/HLists.check @@ -0,0 +1,8 @@ +1 +A +true +true +HCons(1,HCons(A,HCons(true,HNil))) +1 +A +true diff --git a/tests/run/HLists.scala b/tests/run/HLists.scala new file mode 100644 index 000000000..eebbcb4cd --- /dev/null +++ b/tests/run/HLists.scala @@ -0,0 +1,78 @@ +sealed trait HList +case class HCons[+HD, +TL](hd: HD, tl: TL) extends HList +case object HNil extends HList + +sealed trait Num +case object Zero extends Num +case class Succ[N <: Num](pred: N) extends Num + +object Test { + + type HNil = HNil.type + type Zero = Zero.type + + trait Concat[Xs <: HList, Ys <: HList, Zs <: HList] { + def concat(xs: Xs, ys: Ys): Zs + } + + implicit def concatNil[Xs <: HList]: Concat[HNil, Xs, Xs] = + new Concat[HNil, Xs, Xs] { + def concat(fst: HNil, snd: Xs) = snd + } + + implicit def concatCons[X, Xs <: HList, Ys <: HList, Zs <: HList]( + implicit ev: Concat[Xs, Ys, Zs] + ): Concat[HCons[X, Xs], Ys, HCons[X, Zs]] = + new Concat[HCons[X, Xs], Ys, HCons[X, Zs]] { + def concat(xs: HCons[X, Xs], ys: Ys): HCons[X, Zs] = + HCons(xs.hd, ev.concat(xs.tl, ys)) + } + + def concat[Xs <: HList, Ys <: HList, Zs <: HList](xs: Xs, ys: Ys)(implicit ev: Concat[Xs, Ys, Zs]): Zs = + ev.concat(xs, ys) + + val xs = HCons(1, HCons("A", HNil)) + val ys = HCons(true, HNil) + val zs = concat(xs, ys) + val zs1: HCons[Int, HCons[String, HCons[Boolean, HNil]]] = zs + + trait At[Xs <: HList, N <: Num] { + type Out + def at(xs: Xs, n: N): Out + } + + implicit def atZero[XZ, Xs <: HList]: At[HCons[XZ, Xs], Zero] { type Out = XZ } = + new At[HCons[XZ, Xs], Zero] { + type Out = XZ + def at(xs: HCons[XZ, Xs], n: Zero) = xs.hd + } + + implicit def atSucc[XX, Xs <: HList, N <: Num]( + implicit ev: At[Xs, N] + ): At[HCons[XX, Xs], Succ[N]] { type Out = ev.Out } = new At[HCons[XX, Xs], Succ[N]] { + type Out = ev.Out + def at(xs: HCons[XX, Xs], n: Succ[N]): Out = ev.at(xs.tl, n.pred) + } + + def at[Xs <: HList, N <: Num](xs: Xs, n: N)( + implicit ev: At[Xs, N] + ): ev.Out = ev.at(xs, n) + + def main(args: Array[String]) = { + val ys1 = HCons(1, HNil) + println(at(ys1, Zero)) + + val ys2 = HCons(1, HCons("A", HNil)) + val y2 = at(ys2, Succ(Zero)) + println(at(ys2, Succ(Zero))) + val ys3 = HCons(1, HCons("A", HCons(true, HNil))) + println(at(ys3, Succ(Succ(Zero)))) + val ys4 = HCons(1, HCons("A", HCons(true, HCons(1.0, HNil)))) + println(at(ys4, Succ(Succ(Zero)))) + + println(zs1) + println(at(zs1, Zero)) + println(at(zs1, Succ(Zero))) + println(at(zs1, Succ(Succ(Zero)))) + } +} diff --git a/tests/run/hmap-covariant.scala b/tests/run/hmap-covariant.scala new file mode 100644 index 000000000..475cc6ee6 --- /dev/null +++ b/tests/run/hmap-covariant.scala @@ -0,0 +1,97 @@ +trait Tuple +case class TCons[+H, +T <: Tuple](h: H, t: T) extends Tuple +final case object TNil extends Tuple + +// Type level natural numbers ------------------------------------------------- + +sealed trait Nat +sealed trait Succ[P <: Nat] extends Nat +sealed trait Zero extends Nat + +// Accessor type class to compute the N'th element of an Tuple L -------------- + +trait At[L <: Tuple, N <: Nat, Out] { + def apply(l: L): Out +} + +object At { + implicit def caseZero[H, T <: Tuple]: At[H TCons T, Zero, H] = + new At[H TCons T, Zero, H] { + def apply(l: H TCons T): H = { + val (h TCons _) = l + h + } + } + + implicit def caseN[H, T <: Tuple, N <: Nat, O] + (implicit a: At[T, N, O]): At[H TCons T, Succ[N], O] = + new At[H TCons T, Succ[N], O] { + def apply(l: H TCons T): O = { + val (_ TCons t) = l + a(t) + } + } +} + +// An HMap is an Tuple with HEntry elements. We are reusing Tuple for it's nice syntax + +final case class HEntry[K, V](value: V) + +// Accessor type class to compute the element of type K in a HMap L ----------- + +trait PhantomGet[K, M <: Tuple, I <: Nat] // extends PhantomAny + +object PhantomGet { + implicit def getHead[K, V, T <: Tuple] + : PhantomGet[K, HEntry[K, V] TCons T, Zero] = null + + implicit def getTail[K, H, T <: Tuple, I <: Nat] + (implicit t: PhantomGet[K, T, I]) + : PhantomGet[K, H TCons T, Succ[I]] = null +} + +// Syntax --------------------------------------------------------------------- + +object syntax { + object hmap { + implicit class HmapGet[M <: Tuple](m: M) { + def get[K, V, I <: Nat](k: K) + (implicit + g: PhantomGet[k.type, M, I], + a: At[M, I, HEntry[k.type, V]] + ): V = a(m).value + } + + def --[K, V](key: K, value: V) = HEntry[key.type, V](value) + } +} + +object Test { + def main(args: Array[String]): Unit = { + import syntax.hmap._ + + val map1 = + TCons(HEntry[K = "name"]("foo"), + TCons(HEntry[K = "genre"](true), + TCons(HEntry[K = "moneyz"](123), + TCons(HEntry[K = "cat"]("bar"), + (TNil: TNil.type))))) + + assert(map1.get("name") == "foo") + assert(map1.get("genre") == true) + assert(map1.get("moneyz") == 123) + assert(map1.get("cat") == "bar") + + val map2 = + TCons(--("name" , "foo"), + TCons(--("genre" , true), + TCons(--("moneyz", 123), + TCons(--("cat" , "bar"), + TNil)))) + + assert(map2.get("name") == "foo") + assert(map2.get("genre") == true) + assert(map2.get("moneyz") == 123) + assert(map2.get("cat") == "bar") + } +} diff --git a/tests/run/i2004.check b/tests/run/i2004.check new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/tests/run/i2004.check @@ -0,0 +1 @@ +1 diff --git a/tests/run/i2004.scala b/tests/run/i2004.scala new file mode 100644 index 000000000..ff21a6cc9 --- /dev/null +++ b/tests/run/i2004.scala @@ -0,0 +1,11 @@ +object Test { + def main(args: Array[String]) = { + val f: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int,Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) => Int = + { + (x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int, x26: Int) => + x1 + } + println(f.apply(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)) + + } +} |