Skip to content

Commit 6bdeb06

Browse files
Add tests for new the tuples
The LogPendingSubTypesThreshold change is requires for tests on size ~25 tuples that would otherwise trigger -Yno-deep-subtypes
1 parent d06e320 commit 6bdeb06

18 files changed

+1754
-1
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ object Config {
133133
final val LogPendingUnderlyingThreshold = 50
134134

135135
/** How many recursive calls to isSubType are performed before logging starts. */
136-
final val LogPendingSubTypesThreshold = 50
136+
final val LogPendingSubTypesThreshold = 70
137137

138138
/** How many recursive calls to findMember are performed before logging names starts
139139
* Note: this threshold has to be chosen carefully. Too large, and programs

compiler/test/dotc/tests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ class tests extends CompilerTest {
201201

202202
@Test def run_all = runFiles(runDir)
203203

204+
@Test def run_tuples = runFiles(testsDir + "tuples/")
205+
204206
private val stdlibFiles: List[String] = StdLibSources.whitelisted
205207

206208
@Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode)

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ class CompilationTests extends ParallelSummaryReport with ParallelTesting {
165165
@Test def runAll: Unit =
166166
compileFilesInDir("../tests/run", defaultOptions).checkRuns()
167167

168+
@Test def runTuples: Unit =
169+
compileFilesInDir("../tests/tuples", defaultOptions).checkRuns()
170+
168171
// Pickling Tests ------------------------------------------------------------
169172
//
170173
// Pickling tests are very memory intensive and as such need to be run with a

tests/run/tuple-accessors.scala

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import dotty._
2+
3+
case class X2[A, B](a: A, b: B)
4+
case class X3[A, B, C](a: A, b: B, c: C)
5+
case class X4[A, B, C, D](a: A, b: B, c: C, d: D)
6+
case class X5[A, B, C, D, E](a: A, b: B, c: C, d: D, e: E)
7+
case class X6[A, B, C, D, E, F](a: A, b: B, c: C, d: D, e: E, f: F)
8+
9+
object Test {
10+
def main(args: Array[String]) = {
11+
12+
val x2 = X2("a", 2)
13+
val X2(a2, b2) = x2
14+
15+
assert(a2 == "a")
16+
assert(b2 == 2)
17+
18+
val x3 = X3("a", 2, "b")
19+
val X3(a3, b3, c3) = x3
20+
21+
assert(a3 == "a")
22+
assert(b3 == 2)
23+
assert(c3 == "b")
24+
25+
val x4 = X4("a", 2, "b", 3)
26+
val X4(a4, b4, c4, d4) = x4
27+
28+
assert(a4 == "a")
29+
assert(b4 == 2)
30+
assert(c4 == "b")
31+
assert(d4 == 3)
32+
33+
val x5 = X5("a", 2, "b", 3, "c")
34+
val X5(a5, b5, c5, d5, e5) = x5
35+
36+
assert(a5 == "a")
37+
assert(b5 == 2)
38+
assert(c5 == "b")
39+
assert(d5 == 3)
40+
assert(e5 == "c")
41+
42+
val x6 = X6("a", 2, "b", 3, "c", 4)
43+
val X6(a6, b6, c6, d6, e6, f6) = x6
44+
45+
assert(a6 == "a")
46+
assert(b6 == 2)
47+
assert(c6 == "b")
48+
assert(d6 == 3)
49+
assert(e6 == "c")
50+
assert(f6 == 4)
51+
}
52+
53+
def any = {
54+
val x: Any = null
55+
val X2(a2, b2) = x
56+
val X3(a3, b3, c3) = x
57+
val X4(a4, b4, c4, d4) = x
58+
val X5(a5, b5, c5, d5, e5) = x
59+
val X6(a6, b6, c6, d6, e6, f6) = x
60+
}
61+
}

tests/tuples/hmap.scala

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import dotty.{Tuple, TupleCons, LargeTuple}
2+
import dotty.{TupleCons => ::}
3+
4+
// Type level natural numbers ---------------------------------------------------------------------
5+
6+
sealed trait Nat
7+
sealed trait Succ[P <: Nat] extends Nat
8+
sealed trait Zero extends Nat
9+
10+
// Accessor type class to compute the N'th element of an Tuple L ----------------------------------
11+
12+
trait At[L <: Tuple, N <: Nat, Out] {
13+
def apply(l: L): Out
14+
}
15+
16+
object At {
17+
implicit def caseZero[H, T <: Tuple]: At[H :: T, Zero, H] =
18+
new At[H :: T, Zero, H] {
19+
def apply(l: H :: T): H = {
20+
val TupleCons(h, _) = l
21+
h
22+
}
23+
}
24+
25+
implicit def caseN[H, T <: Tuple, N <: Nat, O]
26+
(implicit a: At[T, N, O]): At[H :: T, Succ[N], O] =
27+
new At[H :: T, Succ[N], O] {
28+
def apply(l: H :: T): O = {
29+
val TupleCons(_, t) = l
30+
a(t)
31+
}
32+
}
33+
}
34+
35+
36+
// An HMap is an Tuple with HEntry elements. We are reusing Tuple for it's nice syntax
37+
38+
// Should be `K <: Singleton` but inference for `--` does not quite work with that.
39+
final case class HEntry[K, V](value: V)
40+
41+
// Accessor type class to compute the element of type K in a HMap L -------------------------------
42+
43+
trait PhantomGet[K, M <: Tuple, I <: Nat] // extends PhantomAny
44+
45+
object PhantomGet {
46+
implicit def getHead[K, V, T <: Tuple]
47+
: PhantomGet[K, HEntry[K, V] :: T, Zero] = null
48+
49+
implicit def getTail[K, H, T <: Tuple, I <: Nat]
50+
(implicit t: PhantomGet[K, T, I])
51+
: PhantomGet[K, H :: T, Succ[I]] = null
52+
}
53+
54+
// Syntax -----------------------------------------------------------------------------------------
55+
56+
object syntax {
57+
object hmap {
58+
implicit class hmapGet[M <: Tuple](m: M) {
59+
def get[K, V, I <: Nat](k: K)
60+
(implicit
61+
g: PhantomGet[k.type, M, I],
62+
a: At[M, I, HEntry[k.type, V]]
63+
): V = a(m).value
64+
}
65+
66+
implicit class EntryAssoc[K](k: K) {
67+
def -- [V](value: V): HEntry[K, V] = HEntry(value)
68+
}
69+
70+
type --[A, B] = HEntry[A, B]
71+
}
72+
}
73+
74+
object Test {
75+
def main(args: Array[String]): Unit = {
76+
import syntax.hmap._
77+
78+
type MapType = (
79+
"name" -- String,
80+
"genre" -- Boolean,
81+
"moneyz" -- Int,
82+
"cat" -- String
83+
)
84+
85+
86+
val f = HEntry[K = "name"]("foo")
87+
val l = HEntry[K = "genre"](true)
88+
val i = HEntry[K = "moneyz"](123)
89+
val b = HEntry[K = "cat"]("bar")
90+
91+
val map: MapType = TupleCons(f, TupleCons(l, TupleCons(i, TupleCons(b, ()))))
92+
93+
94+
assert(map.get("name") == "foo")
95+
assert(map.get("genre") == true)
96+
assert(map.get("moneyz") == 123)
97+
assert(map.get("cat") == "bar")
98+
99+
val map2: MapType = (
100+
"name" -- "foo",
101+
"genre" -- true,
102+
"moneyz" -- 123,
103+
"cat" -- "bar"
104+
)
105+
106+
assert(map2.get("name") == "foo")
107+
assert(map2.get("genre") == true)
108+
assert(map2.get("moneyz") == 123)
109+
assert(map2.get("cat") == "bar")
110+
}
111+
}

0 commit comments

Comments
 (0)