| 1 | interface Element { |
| 2 | method(params ...f64) string |
| 3 | } |
| 4 | |
| 5 | struct Foo {} |
| 6 | |
| 7 | fn (f &Foo) method(params ...f64) string { |
| 8 | return params.str() |
| 9 | } |
| 10 | |
| 11 | fn test_variadic_array_decompose() { |
| 12 | mut a := []Element{} |
| 13 | a << Foo{} |
| 14 | |
| 15 | input := [0.0, 1.0] |
| 16 | assert a[0].method(...input) == '[0.0, 1.0]' |
| 17 | assert a[0].method(...[0.0, 1.0]) == '[0.0, 1.0]' |
| 18 | } |
| 19 | |
| 20 | fn test_variadic_multiple_args() { |
| 21 | mut a := []Element{} |
| 22 | a << Foo{} |
| 23 | |
| 24 | assert a[0].method(0.0, 1.0) == '[0.0, 1.0]' |
| 25 | } |
| 26 | |
| 27 | interface Animal {} |
| 28 | |
| 29 | struct Cat {} |
| 30 | |
| 31 | struct Dog {} |
| 32 | |
| 33 | fn test_variadic_interface_fn_arg() { |
| 34 | c := Cat{} |
| 35 | d := Dog{} |
| 36 | check_animals(c, d) |
| 37 | } |
| 38 | |
| 39 | // For issue 27326: passing a local variable declared inside a loop to a |
| 40 | // variadic interface parameter caused a `pointer expected` C error, because |
| 41 | // the value was promoted to auto-heap at the use site but not at its |
| 42 | // declaration, producing inconsistent pointer indirection in the generated C. |
| 43 | interface Value {} |
| 44 | |
| 45 | fn collect(params ...Value) int { |
| 46 | return params.len |
| 47 | } |
| 48 | |
| 49 | fn test_variadic_interface_arg_declared_in_loop() { |
| 50 | mut total := 0 |
| 51 | for i := 0; i < 3; i++ { |
| 52 | id := [u8(1), 2, 3] |
| 53 | code := 'hello ${i}' |
| 54 | total += collect(id, code) |
| 55 | } |
| 56 | assert total == 6 |
| 57 | } |
| 58 | |
| 59 | type ValueSum = Cat | Dog |
| 60 | |
| 61 | // For issue 27326: a variable smartcast via `if x is T` / `match` resolves to a |
| 62 | // synthetic smartcast scope var, not its real declaration. Promoting that |
| 63 | // synthetic var to auto-heap instead of the declaration must not desync the |
| 64 | // pointer indirection when the value is passed to a variadic interface param. |
| 65 | fn test_variadic_interface_arg_smartcast() { |
| 66 | mut total := 0 |
| 67 | s := ValueSum(Cat{}) |
| 68 | if s is Cat { |
| 69 | total += collect(s) |
| 70 | } |
| 71 | v := Value(Cat{}) |
| 72 | if v is Cat { |
| 73 | total += collect(v) |
| 74 | } |
| 75 | match v { |
| 76 | Cat { total += collect(v) } |
| 77 | else {} |
| 78 | } |
| 79 | |
| 80 | assert total == 3 |
| 81 | } |
| 82 | |
| 83 | // For issue 27326: a variable that is both declared in a nested scope (a `for` |
| 84 | // loop body) and smartcast via `if x is T` must still resolve to its real |
| 85 | // nested declaration, not the synthetic smartcast var nor only the function |
| 86 | // scope, otherwise the auto-heap promotion desyncs the pointer indirection. |
| 87 | fn test_variadic_interface_arg_smartcast_in_loop() { |
| 88 | mut total := 0 |
| 89 | for _ in 0 .. 3 { |
| 90 | s := ValueSum(Cat{}) |
| 91 | if s is Cat { |
| 92 | total += collect(s) |
| 93 | } |
| 94 | } |
| 95 | for _ in 0 .. 2 { |
| 96 | v := Value(Cat{}) |
| 97 | if v is Cat { |
| 98 | total += collect(v) |
| 99 | } |
| 100 | } |
| 101 | assert total == 5 |
| 102 | } |
| 103 | |
| 104 | fn maybe_value() ?Cat { |
| 105 | return Cat{} |
| 106 | } |
| 107 | |
| 108 | // For issue 27326: an option value unwrapped via an if-guard or `if x != none` |
| 109 | // and then passed to a variadic interface parameter is auto-heap promoted, so |
| 110 | // its declaration is emitted as an option pointer. The unwrapped `.data` read |
| 111 | // at the call site must use the matching pointer indirection (`->data`); |
| 112 | // previously cgen emitted value-style access and failed C compilation. |
| 113 | fn test_variadic_interface_arg_option_unwrap() { |
| 114 | mut total := 0 |
| 115 | if x := maybe_value() { |
| 116 | total += collect(x) |
| 117 | } |
| 118 | x := maybe_value() |
| 119 | if x != none { |
| 120 | total += collect(x) |
| 121 | } |
| 122 | for _ in 0 .. 2 { |
| 123 | y := maybe_value() |
| 124 | if y != none { |
| 125 | total += collect(y) |
| 126 | } |
| 127 | } |
| 128 | assert total == 4 |
| 129 | } |
| 130 | |
| 131 | fn check_animals(animals ...Animal) { |
| 132 | assert animals[0] is Cat |
| 133 | assert animals[1] is Dog |
| 134 | } |
| 135 | |
| 136 | // For issue: 16286 passing nothing to a variatic parameter on an interface method gives builder error |
| 137 | interface Bar { |
| 138 | get(...int) []int |
| 139 | } |
| 140 | |
| 141 | struct Baz {} |
| 142 | |
| 143 | fn (b Baz) get(n ...int) []int { |
| 144 | if n.len == 0 { |
| 145 | return [-1] |
| 146 | } else { |
| 147 | return n |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | fn test_empty_args_call_interface_methods() { |
| 152 | b := Baz{} |
| 153 | assert b.get() == [-1] |
| 154 | |
| 155 | b_values := Bar(Baz{}) |
| 156 | assert b_values.get(1, 2, 3) == [1, 2, 3] |
| 157 | |
| 158 | b_empty := Bar(Baz{}) |
| 159 | assert b_empty.get() == [-1] |
| 160 | } |
| 161 | |