| 1 | import simplemodule |
| 2 | |
| 3 | fn simple[T](p T) T { |
| 4 | return p |
| 5 | } |
| 6 | |
| 7 | fn 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 | |
| 25 | fn 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 | |
| 33 | fn 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 | |
| 40 | fn plus_one[T](a T) T { |
| 41 | mut b := a |
| 42 | b++ |
| 43 | return b |
| 44 | } |
| 45 | |
| 46 | fn minus_one[T](a T) T { |
| 47 | mut b := a |
| 48 | b-- |
| 49 | return b |
| 50 | } |
| 51 | |
| 52 | fn 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 | |
| 84 | fn sum[T](l []T) T { |
| 85 | mut r := T(0) |
| 86 | for e in l { |
| 87 | r += e |
| 88 | } |
| 89 | return r |
| 90 | } |
| 91 | |
| 92 | fn test_array() { |
| 93 | b := [1, 2, 3] |
| 94 | assert sum(b) == 6 |
| 95 | } |
| 96 | |
| 97 | fn 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 | |
| 107 | fn 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 | |
| 114 | fn create[T]() { |
| 115 | _ := T{} |
| 116 | mut xx := T{} |
| 117 | xx.name = 'foo' |
| 118 | assert xx.name == 'foo' |
| 119 | xx.init() |
| 120 | } |
| 121 | |
| 122 | struct User { |
| 123 | mut: |
| 124 | name string |
| 125 | } |
| 126 | |
| 127 | struct City { |
| 128 | mut: |
| 129 | name string |
| 130 | } |
| 131 | |
| 132 | fn (u User) init() { |
| 133 | } |
| 134 | |
| 135 | fn (c City) init() { |
| 136 | } |
| 137 | |
| 138 | fn mut_arg[T](mut x T) { |
| 139 | // println(x.name) // = 'foo' |
| 140 | } |
| 141 | |
| 142 | fn mut_arg2[T](mut x T) T { |
| 143 | // println(x.name) // = 'foo' |
| 144 | return *x |
| 145 | } |
| 146 | |
| 147 | fn 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 | |
| 155 | fn return_array[T](arr []T) []T { |
| 156 | return arr |
| 157 | } |
| 158 | |
| 159 | fn 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 | |
| 170 | fn opt[T](v T) ?T { |
| 171 | if sizeof(T) > 1 { |
| 172 | return v |
| 173 | } |
| 174 | return none |
| 175 | } |
| 176 | |
| 177 | fn 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 | |
| 186 | fn ptr[T](v T) &T { |
| 187 | a := [v] |
| 188 | return a.data |
| 189 | } |
| 190 | |
| 191 | fn test_ptr() { |
| 192 | assert *ptr(4) == 4 |
| 193 | assert *ptr('aa') == 'aa' |
| 194 | } |
| 195 | |
| 196 | fn 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 | /* |
| 205 | fn 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 | */ |
| 213 | fn square(x int) int { |
| 214 | return x * x |
| 215 | } |
| 216 | |
| 217 | fn mul_int(x int, y int) int { |
| 218 | return x * y |
| 219 | } |
| 220 | |
| 221 | fn assert_eq[T](a T, b T) { |
| 222 | r := a == b |
| 223 | assert r |
| 224 | } |
| 225 | |
| 226 | fn 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 | |
| 234 | fn 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 | |
| 246 | struct Point { |
| 247 | mut: |
| 248 | x f64 |
| 249 | y f64 |
| 250 | } |
| 251 | |
| 252 | fn (mut p Point) translate[T](x T, y T) { |
| 253 | p.x += x |
| 254 | p.y += y |
| 255 | } |
| 256 | |
| 257 | fn 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 | |
| 263 | fn get_values[T](i T) []T { |
| 264 | return [i] |
| 265 | } |
| 266 | |
| 267 | fn 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 |
| 282 | struct DB { |
| 283 | driver string |
| 284 | } |
| 285 | |
| 286 | struct Group { |
| 287 | pub mut: |
| 288 | name string |
| 289 | group_name string |
| 290 | } |
| 291 | |
| 292 | struct Permission { |
| 293 | pub mut: |
| 294 | name string |
| 295 | } |
| 296 | |
| 297 | struct Repo[T, U] { |
| 298 | db DB |
| 299 | pub 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 | // } |
| 308 | fn 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 | |
| 327 | struct Foo[T] { |
| 328 | pub: |
| 329 | data T |
| 330 | } |
| 331 | |
| 332 | fn (f Foo[int]) value() string { |
| 333 | return f.data.str() |
| 334 | } |
| 335 | |
| 336 | fn test_generic_struct_method() { |
| 337 | foo_int := Foo[int]{2} |
| 338 | assert foo_int.value() == '2' |
| 339 | } |
| 340 | |
| 341 | fn test_struct_from_other_module() { |
| 342 | g := simplemodule.ThisIsGeneric[Permission]{} |
| 343 | assert g.msg.name == '' |
| 344 | } |
| 345 | |
| 346 | fn 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 | |
| 353 | struct Abc { |
| 354 | x int |
| 355 | y int |
| 356 | z int |
| 357 | } |
| 358 | |
| 359 | fn 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 | |
| 370 | fn 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 | |
| 383 | struct Context {} |
| 384 | |
| 385 | struct App { |
| 386 | mut: |
| 387 | context Context |
| 388 | } |
| 389 | |
| 390 | fn test[T](mut app T) { |
| 391 | nested_test[T](mut app) |
| 392 | } |
| 393 | |
| 394 | fn nested_test[T](mut app T) { |
| 395 | app.context = Context{} |
| 396 | } |
| 397 | |
| 398 | fn test_pass_generic_to_nested_function() { |
| 399 | mut app := App{} |
| 400 | test(mut app) |
| 401 | } |
| 402 | |
| 403 | fn generic_return_map[M]() map[string]M { |
| 404 | return { |
| 405 | '': M{} |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | fn test_generic_return_map() { |
| 410 | assert typeof(generic_return_map[string]()).name == 'map[string]string' |
| 411 | } |
| 412 | |
| 413 | fn generic_return_nested_map[M]() map[string]map[string]M { |
| 414 | return { |
| 415 | '': { |
| 416 | '': M{} |
| 417 | } |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | fn test_generic_return_nested_map() { |
| 422 | assert typeof(generic_return_nested_map[string]()).name == 'map[string]map[string]string' |
| 423 | } |
| 424 | |
| 425 | fn multi_return[A, B]() (A, B) { |
| 426 | return A{}, B{} |
| 427 | } |
| 428 | |
| 429 | struct Foo1 {} |
| 430 | |
| 431 | struct Foo2 {} |
| 432 | |
| 433 | struct Foo3 {} |
| 434 | |
| 435 | struct Foo4 {} |
| 436 | |
| 437 | fn test_multi_return() { |
| 438 | // compiles |
| 439 | multi_return[Foo1, Foo2]() |
| 440 | multi_return[Foo3, Foo4]() |
| 441 | } |
| 442 | |
| 443 | fn multi_generic_args[T, V](t T, v V) bool { |
| 444 | return true |
| 445 | } |
| 446 | |
| 447 | fn test_multi_generic_args() { |
| 448 | assert multi_generic_args('Super', 2021) |
| 449 | } |
| 450 | |
| 451 | fn new[T]() T { |
| 452 | return T{} |
| 453 | } |
| 454 | |
| 455 | fn 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 | |
| 476 | fn 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 | |
| 483 | struct MultiLevel[T] { |
| 484 | foo T |
| 485 | } |
| 486 | |
| 487 | fn get_multilevel_foo[T](bar MultiLevel[T]) int { |
| 488 | return bar.foo.foo |
| 489 | } |
| 490 | |
| 491 | fn get_multilevel_foo_2[T, U](bar T, baz U) int { |
| 492 | return bar.foo.foo + baz.foo.foo |
| 493 | } |
| 494 | |
| 495 | fn 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 | |
| 511 | struct Empty_ {} |
| 512 | |
| 513 | fn (e1 Empty_) < (e2 Empty_) bool { |
| 514 | return true |
| 515 | } |
| 516 | |
| 517 | struct TandU[T, U] { |
| 518 | t T |
| 519 | u U |
| 520 | } |
| 521 | |
| 522 | fn boring_function[T](t T) bool { |
| 523 | return true |
| 524 | } |
| 525 | |
| 526 | fn 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 | |