v2 / vlib / v / tests / generics / generics_test.v
585 lines · 492 sloc · 10.03 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1import simplemodule
2
3fn simple[T](p T) T {
4 return p
5}
6
7fn test_identity() {
8 assert simple[int](1) == 1
9 assert simple[int](1 + 0) == 1
10 assert simple[string]('g') == 'g'
11 assert simple[string]('g') + 'h' == 'gh'
12
13 assert simple[[]int]([1])[0] == 1
14 assert simple[map[string]string]({
15 'a': 'b'
16 })['a'] == 'b'
17
18 assert simple[simplemodule.Data](simplemodule.Data{ value: 8 }).value == 8
19 x := &simplemodule.Data{
20 value: 123
21 }
22 assert simple[&simplemodule.Data](x).value == 123
23}
24
25fn plus[T](xxx T, b T) T {
26 // x := a
27 // y := b
28 // ww := ww
29 // q := xx + 1
30 return xxx + b
31}
32
33fn test_infix_expr() {
34 a := plus[int](2, 3)
35 assert a == 5
36 assert plus[int](10, 1) == 11
37 assert plus[string]('a', 'b') == 'ab'
38}
39
40fn plus_one[T](a T) T {
41 mut b := a
42 b++
43 return b
44}
45
46fn minus_one[T](a T) T {
47 mut b := a
48 b--
49 return b
50}
51
52fn test_postfix_expr() {
53 assert plus_one(-1) == 0
54 assert plus_one(u8(0)) == 1
55 assert plus_one(u16(1)) == 2
56 assert plus_one(u32(2)) == 3
57 assert plus_one(u64(3)) == 4
58 assert plus_one(i8(-10)) == -9
59 assert plus_one(i16(-9)) == -8
60 assert plus_one(int(-8)) == -7
61 assert plus_one(i64(-7)) == -6
62 assert minus_one(0) == -1
63 assert minus_one(u8(1)) == 0
64 assert minus_one(u16(2)) == 1
65 assert minus_one(u32(3)) == 2
66 assert minus_one(u64(4)) == 3
67 assert minus_one(i8(-8)) == -9
68 assert minus_one(i16(-7)) == -8
69 assert minus_one(int(-6)) == -7
70 assert minus_one(i64(-5)) == -6
71
72 // the point is to see if it compiles, more than if the result
73 // is correct, so 1e-6 isn't necessarily the right value to do this
74 // but it's not important
75 delta := 1e-6
76 assert plus_one(1.1) - 2.1 < delta
77 assert plus_one(f32(2.2)) - 3.2 < delta
78 assert plus_one(f64(3.3)) - 4.3 < delta
79 assert minus_one(1.1) - 0.1 < delta
80 assert minus_one(f32(2.2)) - 1.2 < delta
81 assert minus_one(f64(3.3)) - 2.3 < delta
82}
83
84fn sum[T](l []T) T {
85 mut r := T(0)
86 for e in l {
87 r += e
88 }
89 return r
90}
91
92fn test_array() {
93 b := [1, 2, 3]
94 assert sum(b) == 6
95}
96
97fn max[T](brug string, a ...T) T {
98 mut max := a[0]
99 for item in a[1..] {
100 if max < item {
101 max = item
102 }
103 }
104 return max
105}
106
107fn test_generic_variadic() {
108 assert max('krkr', 1, 2, 3, 4) == 4
109 a := [f64(1.2), 3.2, 0.1, 2.2]
110 assert max('krkr', ...a) == 3.2
111 assert max('krkr', ...[u8(4), 3, 2, 1]) == 4
112}
113
114fn create[T]() {
115 _ := T{}
116 mut xx := T{}
117 xx.name = 'foo'
118 assert xx.name == 'foo'
119 xx.init()
120}
121
122struct User {
123mut:
124 name string
125}
126
127struct City {
128mut:
129 name string
130}
131
132fn (u User) init() {
133}
134
135fn (c City) init() {
136}
137
138fn mut_arg[T](mut x T) {
139 // println(x.name) // = 'foo'
140}
141
142fn mut_arg2[T](mut x T) T {
143 // println(x.name) // = 'foo'
144 return *x
145}
146
147fn test_create() {
148 create[User]()
149 create[City]()
150 mut u := User{}
151 mut_arg[User](mut u)
152 mut_arg2[User](mut u)
153}
154
155fn return_array[T](arr []T) []T {
156 return arr
157}
158
159fn test_return_array() {
160 a1 := return_array[int]([1, 2, 3])
161 assert a1 == [1, 2, 3]
162 a2 := return_array[f64]([1.1, 2.2, 3.3])
163 assert a2 == [1.1, 2.2, 3.3]
164 a3 := return_array[string](['a', 'b', 'c'])
165 assert a3 == ['a', 'b', 'c']
166 a4 := return_array[bool]([true, false, true])
167 assert a4 == [true, false, true]
168}
169
170fn opt[T](v T) ?T {
171 if sizeof(T) > 1 {
172 return v
173 }
174 return none
175}
176
177fn test_option() {
178 s := opt('hi') or { '' }
179 assert s == 'hi'
180 i := opt(5) or { 0 }
181 assert i == 5
182 b := opt(s[0]) or { 99 }
183 assert b == 99
184}
185
186fn ptr[T](v T) &T {
187 a := [v]
188 return a.data
189}
190
191fn test_ptr() {
192 assert *ptr(4) == 4
193 assert *ptr('aa') == 'aa'
194}
195
196fn map_f[T, U](l []T, f fn (T) U) []U {
197 mut r := []U{}
198 for e in l {
199 r << f(e)
200 }
201 return r
202}
203
204/*
205fn foldl[T](l []T, nil T, f fn(T,T)T) T {
206 mut r := nil
207 for e in l {
208 r = f(r, e)
209 }
210 return r
211}
212*/
213fn square(x int) int {
214 return x * x
215}
216
217fn mul_int(x int, y int) int {
218 return x * y
219}
220
221fn assert_eq[T](a T, b T) {
222 r := a == b
223 assert r
224}
225
226fn print_nice[T](x T, indent int) string {
227 mut space := ''
228 for _ in 0 .. indent {
229 space = space + ' '
230 }
231 return '${space}${x}'
232}
233
234fn test_generic_fn() {
235 assert_eq(simple(0 + 1), 1)
236 assert_eq(simple('g') + 'h', 'gh')
237 assert_eq(sum([5.1, 6.2, 7.0]), 18.3)
238 assert_eq(plus(i64(4), i64(6)), i64(10))
239 a := [1, 2, 3, 4]
240 b := map_f(a, square)
241 assert_eq(sum(b), 30) // 1+4+9+16 = 30
242 // assert_eq(foldl(b, 1, mul_int), 576) // 1*4*9*16 = 576
243 assert print_nice('str', 8) == ' str'
244}
245
246struct Point {
247mut:
248 x f64
249 y f64
250}
251
252fn (mut p Point) translate[T](x T, y T) {
253 p.x += x
254 p.y += y
255}
256
257fn test_generic_method() {
258 mut p := Point{}
259 p.translate(2, 1.0)
260 assert p.x == 2.0 && p.y == 1.0
261}
262
263fn get_values[T](i T) []T {
264 return [i]
265}
266
267fn test_generic_fn_in_for_in_expression() {
268 for value in get_values(1) {
269 assert value == 1
270 }
271
272 for i, val in get_values(0) {
273 assert i == val
274 }
275
276 for value in get_values('a') {
277 assert value == 'a'
278 }
279}
280
281// test generic struct
282struct DB {
283 driver string
284}
285
286struct Group {
287pub mut:
288 name string
289 group_name string
290}
291
292struct Permission {
293pub mut:
294 name string
295}
296
297struct Repo[T, U] {
298 db DB
299pub mut:
300 model T
301 permission U
302}
303
304// TODO: multiple type generic struct needs fixing in return for fn
305// fn new_repo[T](db DB) Repo[T,U] {
306// return Repo[T,Permission]{db: db}
307// }
308fn test_generic_struct() {
309 mut a := Repo[User, Permission]{
310 model: User{
311 name: 'joe'
312 }
313 }
314 assert a.model.name == 'joe'
315 mut b := Repo[Group, Permission]{
316 permission: Permission{
317 name: 'superuser'
318 }
319 }
320 b.model.name = 'admins'
321 assert b.model.name == 'admins'
322 assert b.permission.name == 'superuser'
323 assert typeof(a.model).name == 'User'
324 assert typeof(b.model).name == 'Group'
325}
326
327struct Foo[T] {
328pub:
329 data T
330}
331
332fn (f Foo[int]) value() string {
333 return f.data.str()
334}
335
336fn test_generic_struct_method() {
337 foo_int := Foo[int]{2}
338 assert foo_int.value() == '2'
339}
340
341fn test_struct_from_other_module() {
342 g := simplemodule.ThisIsGeneric[Permission]{}
343 assert g.msg.name == ''
344}
345
346fn test_generic_struct_print_array_as_field() {
347 foo := Foo[[]string]{
348 data: []string{}
349 }
350 assert foo.str() == 'Foo[[]string]{\n data: []\n}'
351}
352
353struct Abc {
354 x int
355 y int
356 z int
357}
358
359fn p[T](args ...T) {
360 size := sizeof(T)
361 print('p called with size: ${size:3} | ')
362 for _, x in args {
363 print(x)
364 print(' ')
365 }
366 println('')
367 assert true
368}
369
370fn test_generic_fn_with_variadics() {
371 s := 'abc'
372 i := 1
373 abc := Abc{1, 2, 3}
374
375 // these calls should all compile, and print the arguments,
376 // even though the arguments are all a different type and arity:
377 p(s)
378 p(i)
379 p(abc)
380 p('Good', 'morning', 'world')
381}
382
383struct Context {}
384
385struct App {
386mut:
387 context Context
388}
389
390fn test[T](mut app T) {
391 nested_test[T](mut app)
392}
393
394fn nested_test[T](mut app T) {
395 app.context = Context{}
396}
397
398fn test_pass_generic_to_nested_function() {
399 mut app := App{}
400 test(mut app)
401}
402
403fn generic_return_map[M]() map[string]M {
404 return {
405 '': M{}
406 }
407}
408
409fn test_generic_return_map() {
410 assert typeof(generic_return_map[string]()).name == 'map[string]string'
411}
412
413fn generic_return_nested_map[M]() map[string]map[string]M {
414 return {
415 '': {
416 '': M{}
417 }
418 }
419}
420
421fn test_generic_return_nested_map() {
422 assert typeof(generic_return_nested_map[string]()).name == 'map[string]map[string]string'
423}
424
425fn multi_return[A, B]() (A, B) {
426 return A{}, B{}
427}
428
429struct Foo1 {}
430
431struct Foo2 {}
432
433struct Foo3 {}
434
435struct Foo4 {}
436
437fn test_multi_return() {
438 // compiles
439 multi_return[Foo1, Foo2]()
440 multi_return[Foo3, Foo4]()
441}
442
443fn multi_generic_args[T, V](t T, v V) bool {
444 return true
445}
446
447fn test_multi_generic_args() {
448 assert multi_generic_args('Super', 2021)
449}
450
451fn new[T]() T {
452 return T{}
453}
454
455fn test_generic_init() {
456 // array init
457 mut a := new[[]string]()
458 assert a.len == 0
459 a << 'a'
460 assert a.len == 1
461 assert a[0] == 'a'
462
463 // map init
464 mut b := new[map[string]string]()
465 assert b.len == 0
466 b['b'] = 'b'
467 assert b.len == 1
468 assert b['b'] == 'b'
469
470 // struct init
471 mut c := new[User]()
472 c.name = 'c'
473 assert c.name == 'c'
474}
475
476fn return_one[T](rec int, useless T) T {
477 if rec == 0 || 0 < return_one[T](rec - 1, useless) {
478 return T(1)
479 }
480 return T(0)
481}
482
483struct MultiLevel[T] {
484 foo T
485}
486
487fn get_multilevel_foo[T](bar MultiLevel[T]) int {
488 return bar.foo.foo
489}
490
491fn get_multilevel_foo_2[T, U](bar T, baz U) int {
492 return bar.foo.foo + baz.foo.foo
493}
494
495fn test_multi_level_generics() {
496 one := MultiLevel[int]{
497 foo: 10
498 }
499 two := MultiLevel[MultiLevel[int]]{
500 foo: one
501 }
502 assert two.foo.foo == 10
503 three := MultiLevel[MultiLevel[MultiLevel[int]]]{
504 foo: two
505 }
506 assert three.foo.foo.foo == 10
507 assert get_multilevel_foo[MultiLevel[int]](two) == 10
508 assert get_multilevel_foo_2[MultiLevel[MultiLevel[int]], MultiLevel[MultiLevel[int]]](two, two) == 20
509}
510
511struct Empty_ {}
512
513fn (e1 Empty_) < (e2 Empty_) bool {
514 return true
515}
516
517struct TandU[T, U] {
518 t T
519 u U
520}
521
522fn boring_function[T](t T) bool {
523 return true
524}
525
526fn test_generic_detection() {
527 v1, v2 := -1, 1
528
529 // not generic
530 a1, a2 := v1 < v2, v2 > v1
531 assert a1 && a2
532 b1, b2 := v1 < simplemodule.zero, v2 > v1
533 assert b1 && b2
534
535 // generic
536 assert multi_generic_args[int, string](0, 's')
537 assert multi_generic_args[Foo1, Foo2](Foo1{}, Foo2{})
538 assert multi_generic_args[Foo[int], Foo[int]](Foo[int]{}, Foo[int]{})
539
540 // TODO: assert multi_generic_args<Foo<int>, Foo<int>>(Foo1{}, Foo2{})
541 assert multi_generic_args[simplemodule.Data, int](simplemodule.Data{}, 0)
542 assert multi_generic_args[int, simplemodule.Data](0, simplemodule.Data{})
543 assert multi_generic_args[[]int, int]([]int{}, 0)
544 assert multi_generic_args[map[int]int, int](map[int]int{}, 0)
545 assert 0 < return_one[int](10, 0)
546
547 // "the hardest cases"
548 foo, bar, baz := 1, 2, 16
549 res1, res2 := foo < bar, baz >> (foo + 1 - 1)
550 assert res1
551 assert res2 == 8
552 res3, res4 := Empty_{} < Empty_{}, baz >> (foo + 1 - 1)
553 assert res3
554 assert res4 == 8
555 assert boring_function[TandU[Empty_, int]](TandU[Empty_, int]{
556 t: Empty_{}
557 u: 10
558 })
559
560 assert boring_function[MultiLevel[MultiLevel[int]]](MultiLevel[MultiLevel[int]]{
561 foo: MultiLevel[int]{
562 foo: 10
563 }
564 })
565
566 assert boring_function[TandU[MultiLevel[int], []int]](TandU[MultiLevel[int], []int]{
567 t: MultiLevel[int]{
568 foo: 10
569 }
570 u: [10]
571 })
572
573 // this final case challenges your scanner :-)
574 assert boring_function[TandU[TandU[int, MultiLevel[Empty_]], map[string][]int]](TandU[TandU[int, MultiLevel[Empty_]], map[string][]int]{
575 t: TandU[int, MultiLevel[Empty_]]{
576 t: 20
577 u: MultiLevel[Empty_]{
578 foo: Empty_{}
579 }
580 }
581 u: {
582 'bar': [40]
583 }
584 })
585}
586