Skip to content

Commit 09be8ce

Browse files
cknittclaude
andcommitted
Test GADTs and other OCaml-derived type and module features
GADTs, existentials, polymorphic record fields, constraint, private and indexed extensible types, destructive substitution and typed first-class modules had no behavioural tests. Part of #9074. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kbf3gLMawVgtmiKy3TMBc3 Claude-Session: https://claude.ai/code/session_01Kr4cjoUi2f5VpMvE6wT9bo Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent 799a82f commit 09be8ce

10 files changed

Lines changed: 1506 additions & 3 deletions
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/gadt_match_without_locally_abstract_type.res:6:5
4+
5+
4 ┆ switch x {
6+
5 ┆ | I => 1
7+
6 ┆ | S => "s"
8+
7 ┆ }
9+
8 ┆
10+
11+
This pattern matches values of type t<string>
12+
but a pattern was expected which matches values of type t<int>
13+
14+
The incompatible parts:
15+
string vs int
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/polymorphic_recursion_without_annotation.res:6:26
4+
5+
4 ┆ switch n {
6+
5 ┆ | Flat(_) => 0
7+
6 ┆ | Nest(n) => 1 + depth(n)
8+
7 ┆ }
9+
8 ┆
10+
11+
This has type: nested<array<'a>>
12+
But this function argument is expecting: nested<'a>
13+
The type variable 'a occurs inside array<'a>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type rec t<_> = I: t<int> | S: t<string>
2+
3+
let f = x =>
4+
switch x {
5+
| I => 1
6+
| S => "s"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type rec nested<'a> = Flat('a) | Nest(nested<array<'a>>)
2+
3+
let rec depth = n =>
4+
switch n {
5+
| Flat(_) => 0
6+
| Nest(n) => 1 + depth(n)
7+
}
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Generated by ReScript, PLEASE EDIT WITH CARE
2+
3+
import * as Mocha from "mocha";
4+
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.mjs";
5+
import * as Test_utils from "./test_utils.mjs";
6+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.mjs";
7+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.mjs";
8+
9+
function useIdentity(param) {
10+
let id = param.id;
11+
return [
12+
id(1),
13+
id("s")
14+
];
15+
}
16+
17+
let arrayMapper = {
18+
map: (xs, f) => xs.map(f)
19+
};
20+
21+
function singleton(x) {
22+
return [x];
23+
}
24+
25+
let withDefault_1 = [2];
26+
27+
let withDefault = [
28+
1,
29+
withDefault_1
30+
];
31+
32+
function sum(l) {
33+
if (typeof l !== "object") {
34+
return 0;
35+
}
36+
let match = l.VAL;
37+
return match[0] + sum(match[1]) | 0;
38+
}
39+
40+
function keep(x) {
41+
return x;
42+
}
43+
44+
function describeColor(c) {
45+
if (c === "Blue") {
46+
return "blue";
47+
} else {
48+
return "basic " + c;
49+
}
50+
}
51+
52+
function make(n) {
53+
if (n > 0) {
54+
return n;
55+
}
56+
}
57+
58+
let Positive = {
59+
make: make
60+
};
61+
62+
function parse(s) {
63+
let n = Stdlib_Int.fromString(s);
64+
if (n !== undefined) {
65+
return {
66+
TAG: "Number",
67+
_0: n
68+
};
69+
} else {
70+
return {
71+
TAG: "Word",
72+
_0: s
73+
};
74+
}
75+
}
76+
77+
let Token = {
78+
parse: parse
79+
};
80+
81+
function make$1(x) {
82+
return Primitive_option.some(x);
83+
}
84+
85+
function get(x) {
86+
return Stdlib_Option.getOrThrow(x, undefined);
87+
}
88+
89+
let Box = {
90+
make: make$1,
91+
get: get
92+
};
93+
94+
let widened = "A";
95+
96+
function make$2(x) {
97+
return [x];
98+
}
99+
100+
function toArray(t) {
101+
return t;
102+
}
103+
104+
let IntContainer = {
105+
make: make$2,
106+
toArray: toArray
107+
};
108+
109+
function compare(a, b) {
110+
return a - b | 0;
111+
}
112+
113+
let IntOrd = {
114+
compare: compare
115+
};
116+
117+
function max(a, b) {
118+
if ((a - b | 0) > 0) {
119+
return a;
120+
} else {
121+
return b;
122+
}
123+
}
124+
125+
let IntMax = {
126+
O: IntOrd,
127+
max: max
128+
};
129+
130+
function Apply(F) {
131+
return X => F(X);
132+
}
133+
134+
function Reverse(X) {
135+
let compare = (a, b) => X.compare(b, a);
136+
return {
137+
compare: compare
138+
};
139+
}
140+
141+
function compare$1(a, b) {
142+
return b - a | 0;
143+
}
144+
145+
let ReverseInt = {
146+
compare: compare$1
147+
};
148+
149+
function Counter($star) {
150+
let count = {
151+
contents: 0
152+
};
153+
let next = () => {
154+
count.contents = count.contents + 1 | 0;
155+
return count.contents;
156+
};
157+
return {
158+
count: count,
159+
next: next
160+
};
161+
}
162+
163+
let count = {
164+
contents: 0
165+
};
166+
167+
function next() {
168+
count.contents = count.contents + 1 | 0;
169+
return count.contents;
170+
}
171+
172+
let Counter1 = {
173+
count: count,
174+
next: next
175+
};
176+
177+
let count$1 = {
178+
contents: 0
179+
};
180+
181+
function next$1() {
182+
count$1.contents = count$1.contents + 1 | 0;
183+
return count$1.contents;
184+
}
185+
186+
let Counter2 = {
187+
count: count$1,
188+
next: next$1
189+
};
190+
191+
function showValue(m) {
192+
return m.show(m.value);
193+
}
194+
195+
function valueOf(m) {
196+
return m.value;
197+
}
198+
199+
function show(n) {
200+
return n.toString();
201+
}
202+
203+
let IntValue = {
204+
value: 3,
205+
show: show
206+
};
207+
208+
Mocha.describe("Advanced_types_test", () => {
209+
Mocha.test("polymorphic fields", () => {
210+
Test_utils.eq("File \"advanced_types_test.res\", line 144, characters 7-14", [
211+
1,
212+
"s"
213+
], useIdentity({
214+
id: x => x
215+
}));
216+
Test_utils.eq("File \"advanced_types_test.res\", line 146, characters 6-13", [
217+
[2],
218+
["a!"]
219+
], [
220+
arrayMapper.map([1], x => x + 1 | 0),
221+
arrayMapper.map(["a"], s => s + "!")
222+
]);
223+
Test_utils.eq("File \"advanced_types_test.res\", line 150, characters 7-14", [
224+
[1],
225+
["a"]
226+
], [
227+
[1],
228+
["a"]
229+
]);
230+
});
231+
Mocha.test("constraint and alias", () => {
232+
Test_utils.eq("File \"advanced_types_test.res\", line 154, characters 7-14", [
233+
1,
234+
[2]
235+
], withDefault);
236+
Test_utils.eq("File \"advanced_types_test.res\", line 155, characters 7-14", 3, sum({
237+
NAME: "Cons",
238+
VAL: [
239+
1,
240+
{
241+
NAME: "Cons",
242+
VAL: [
243+
2,
244+
"Nil"
245+
]
246+
}
247+
]
248+
}));
249+
Test_utils.eq("File \"advanced_types_test.res\", line 156, characters 7-14", "B", "B");
250+
});
251+
Mocha.test("type pattern", () => {
252+
Test_utils.eq("File \"advanced_types_test.res\", line 160, characters 7-14", "basic Red", "basic Red");
253+
Test_utils.eq("File \"advanced_types_test.res\", line 161, characters 7-14", "blue", "blue");
254+
});
255+
Mocha.test("private types", () => {
256+
Test_utils.eq("File \"advanced_types_test.res\", line 166, characters 20-27", 4, 3 + 1 | 0);
257+
Test_utils.eq("File \"advanced_types_test.res\", line 169, characters 7-14", undefined, undefined);
258+
let n = parse("7");
259+
let tmp;
260+
tmp = n.TAG === "Word" ? 0 : n._0;
261+
Test_utils.eq("File \"advanced_types_test.res\", line 171, characters 6-13", 7, tmp);
262+
});
263+
Mocha.test("variance", () => Test_utils.eq("File \"advanced_types_test.res\", line 181, characters 7-14", "A", Stdlib_Option.getOrThrow(widened, undefined)));
264+
Mocha.test("signatures", () => {
265+
Test_utils.eq("File \"advanced_types_test.res\", line 185, characters 7-14", [1], [1]);
266+
Test_utils.eq("File \"advanced_types_test.res\", line 186, characters 7-14", 9, 9);
267+
Test_utils.eq("File \"advanced_types_test.res\", line 187, characters 7-14", 2, 2);
268+
});
269+
Mocha.test("functors", () => {
270+
Test_utils.ok("File \"advanced_types_test.res\", line 191, characters 7-14", compare$1(1, 2) > 0);
271+
Test_utils.eq("File \"advanced_types_test.res\", line 192, characters 7-14", 1, next());
272+
Test_utils.eq("File \"advanced_types_test.res\", line 193, characters 7-14", 2, next());
273+
Test_utils.eq("File \"advanced_types_test.res\", line 194, characters 7-14", 1, next$1());
274+
});
275+
Mocha.test("first-class modules", () => {
276+
Test_utils.eq("File \"advanced_types_test.res\", line 198, characters 7-14", "3", (3).toString());
277+
Test_utils.eq("File \"advanced_types_test.res\", line 199, characters 7-14", 3, 3);
278+
});
279+
});
280+
281+
let IntOrdCopy = IntOrd;
282+
283+
let Positive$make = make;
284+
285+
let Box$make = make$1;
286+
287+
let IntContainer$make = make$2;
288+
289+
export {
290+
useIdentity,
291+
arrayMapper,
292+
singleton,
293+
withDefault,
294+
sum,
295+
keep,
296+
describeColor,
297+
Positive,
298+
Token,
299+
Box,
300+
widened,
301+
IntContainer,
302+
IntOrd,
303+
IntMax,
304+
IntOrdCopy,
305+
Apply,
306+
Reverse,
307+
ReverseInt,
308+
Counter,
309+
Counter1,
310+
Counter2,
311+
showValue,
312+
valueOf,
313+
IntValue,
314+
Positive$make,
315+
Box$make,
316+
IntContainer$make,
317+
}
318+
/* Not a pure module */

0 commit comments

Comments
 (0)