diff --git a/cmd/tools/gen_vc.v b/cmd/tools/gen_vc.v index 33d694421d..d568cb8317 100644 --- a/cmd/tools/gen_vc.v +++ b/cmd/tools/gen_vc.v @@ -125,7 +125,7 @@ fn main() { } // webhook server mode if flag_options.serve { - vweb.run(&WebhookServer{}, flag_options.port) + vweb.run[WebhookServer](&WebhookServer{}, flag_options.port) } else { // cmd mode mut gen_vc := new_gen_vc(flag_options) diff --git a/cmd/tools/modules/testing/common.v b/cmd/tools/modules/testing/common.v index 0c7d674bad..60dfe06f5f 100644 --- a/cmd/tools/modules/testing/common.v +++ b/cmd/tools/modules/testing/common.v @@ -336,7 +336,7 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr { } tls_bench.no_cstep = true tls_bench.njobs = ts.benchmark.njobs - mut relative_file := os.real_path(p.get_item(idx)) + mut relative_file := os.real_path(p.get_item[string](idx)) mut cmd_options := [ts.vargs] mut run_js := false diff --git a/cmd/tools/vast/test/demo.v b/cmd/tools/vast/test/demo.v index 536dc04e1a..d08e9a8475 100644 --- a/cmd/tools/vast/test/demo.v +++ b/cmd/tools/vast/test/demo.v @@ -109,23 +109,23 @@ fn defer_fn() { } // generic function -fn g_fn(p T) T { +fn g_fn[T](p T) T { return p } // generic struct -struct GenericStruct { +struct GenericStruct[T] { point Point mut: model T } // generic interface -interface Gettable { +interface Gettable[T] { get() T } // generic sumtype struct None {} -type MyOption = Error | None | T +type MyOption[T] = Error | None | T diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index 52843a4e63..588dec94c7 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -228,7 +228,7 @@ fn (t Tree) token_node(tok_kind token.Kind) &Node { } // enum type node -fn (t Tree) enum_node(value T) &Node { +fn (t Tree) enum_node[T](value T) &Node { return t.string_node('enum:${int(value)}(${value})') } diff --git a/cmd/tools/vdoc/vdoc.v b/cmd/tools/vdoc/vdoc.v index 681da0b222..1226e430af 100644 --- a/cmd/tools/vdoc/vdoc.v +++ b/cmd/tools/vdoc/vdoc.v @@ -201,7 +201,7 @@ fn (vd VDoc) work_processor(mut work sync.Channel, mut wg sync.WaitGroup) { fn (vd VDoc) render_parallel(out Output) { vjobs := runtime.nr_jobs() - mut work := sync.new_channel(u32(vd.docs.len)) + mut work := sync.new_channel[ParallelDoc](u32(vd.docs.len)) mut wg := sync.new_waitgroup() for i in 0 .. vd.docs.len { p_doc := ParallelDoc{vd.docs[i], out} diff --git a/doc/docs.md b/doc/docs.md index a2910ff7ab..299b52732e 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -2719,10 +2719,10 @@ In general, V's references are similar to Go pointers and C++ references. For example, a generic tree structure definition would look like this: ```v -struct Node { +struct Node[T] { val T - left &Node - right &Node + left &Node[T] + right &Node[T] } ``` @@ -3787,7 +3787,7 @@ receiver argument `r` uses a generic type `T`. Another example: ```v -fn compare(a T, b T) int { +fn compare[T](a T, b T) int { if a < b { return -1 } @@ -3797,15 +3797,15 @@ fn compare(a T, b T) int { return 0 } -// compare +// compare[int] println(compare(1, 0)) // Outputs: 1 println(compare(1, 1)) // 0 println(compare(1, 2)) // -1 -// compare +// compare[string] println(compare('1', '0')) // Outputs: 1 println(compare('1', '1')) // 0 println(compare('1', '2')) // -1 -// compare +// compare[f64] println(compare(1.1, 1.0)) // Outputs: 1 println(compare(1.1, 1.1)) // 0 println(compare(1.1, 1.2)) // -1 diff --git a/examples/binary_search_tree.v b/examples/binary_search_tree.v index 2835c3f2f5..3a18f09e90 100644 --- a/examples/binary_search_tree.v +++ b/examples/binary_search_tree.v @@ -2,38 +2,38 @@ struct Empty {} -struct Node { +struct Node[T] { value T - left Tree - right Tree + left Tree[T] + right Tree[T] } -type Tree = Empty | Node +type Tree[T] = Empty | Node[T] // return size(number of nodes) of BST -fn (tree Tree) size() int { +fn (tree Tree[T]) size[T]() int { return match tree { Empty { 0 } - Node { 1 + tree.left.size() + tree.right.size() } + Node[T] { 1 + tree.left.size() + tree.right.size() } } } // insert a value to BST -fn (tree Tree) insert(x T) Tree { +fn (tree Tree[T]) insert[T](x T) Tree[T] { return match tree { Empty { - Node{x, tree, tree} + Node[T]{x, tree, tree} } - Node { + Node[T] { if x == tree.value { tree } else if x < tree.value { - Node{ + Node[T]{ ...tree left: tree.left.insert(x) } } else { - Node{ + Node[T]{ ...tree right: tree.right.insert(x) } @@ -43,12 +43,12 @@ fn (tree Tree) insert(x T) Tree { } // whether able to find a value in BST -fn (tree Tree) search(x T) bool { +fn (tree Tree[T]) search[T](x T) bool { return match tree { Empty { false } - Node { + Node[T] { if x == tree.value { true } else if x < tree.value { @@ -61,12 +61,12 @@ fn (tree Tree) search(x T) bool { } // find the minimal value of a BST -fn (tree Tree) min() T { +fn (tree Tree[T]) min[T]() T { return match tree { Empty { T(1e9) } - Node { + Node[T] { if tree.value < tree.left.min() { tree.value } else { @@ -77,25 +77,25 @@ fn (tree Tree) min() T { } // delete a value in BST (if nonexistant do nothing) -fn (tree Tree) delete(x T) Tree { +fn (tree Tree[T]) delete[T](x T) Tree[T] { return match tree { Empty { tree } - Node { + Node[T] { if tree.left !is Empty && tree.right !is Empty { if x < tree.value { - Node{ + Node[T]{ ...tree left: tree.left.delete(x) } } else if x > tree.value { - Node{ + Node[T]{ ...tree right: tree.right.delete(x) } } else { - Node{ + Node[T]{ ...tree value: tree.right.min() right: tree.right.delete(tree.right.min()) @@ -105,7 +105,7 @@ fn (tree Tree) delete(x T) Tree { if x == tree.value { tree.left } else { - Node{ + Node[T]{ ...tree left: tree.left.delete(x) } @@ -114,7 +114,7 @@ fn (tree Tree) delete(x T) Tree { if x == tree.value { tree.right } else { - Node{ + Node[T]{ ...tree right: tree.right.delete(x) } @@ -125,7 +125,7 @@ fn (tree Tree) delete(x T) Tree { } fn main() { - mut tree := Tree(Empty{}) + mut tree := Tree[f64](Empty{}) vals := [0.2, 0.0, 0.5, 0.3, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7] for i in vals { tree = tree.insert(i) diff --git a/examples/bst_map.v b/examples/bst_map.v index 64217ae7a1..3f2e249850 100644 --- a/examples/bst_map.v +++ b/examples/bst_map.v @@ -15,7 +15,7 @@ fn (a KeyVal) < (b KeyVal) bool { } fn main() { - mut bst := datatypes.BSTree{} + mut bst := datatypes.BSTree[KeyVal]{} bst.insert(KeyVal{ key: 1, val: 12 }) println(bst.in_order_traversal()) diff --git a/examples/compiletime/reflection.v b/examples/compiletime/reflection.v index f6cf491738..e51664ff86 100644 --- a/examples/compiletime/reflection.v +++ b/examples/compiletime/reflection.v @@ -7,11 +7,11 @@ struct User { fn main() { data := 'name=Alice\nage=18' - user := decode(data) + user := decode[User](data) println(user) } -fn decode(data string) T { +fn decode[T](data string) T { mut result := T{} // compile-time `for` loop // T.fields gives an array of a field metadata type diff --git a/examples/graphs/bellman-ford.v b/examples/graphs/bellman-ford.v index 1ee12799d0..84d9ebd21b 100644 --- a/examples/graphs/bellman-ford.v +++ b/examples/graphs/bellman-ford.v @@ -23,7 +23,7 @@ mut: // building a map of with all edges etc of a graph, represented from a matrix adjacency // Input: matrix adjacency --> Output: edges list of src, dest and weight -fn build_map_edges_from_graph(g [][]T) map[T]EDGE { +fn build_map_edges_from_graph[T](g [][]T) map[T]EDGE { n := g.len // TOTAL OF NODES for this graph -- its dimmension mut edges_map := map[int]EDGE{} // a graph represented by map of edges @@ -52,7 +52,7 @@ fn print_sol(dist []int) { // The main function that finds shortest distances from src // to all other vertices using Bellman-Ford algorithm. The // function also detects negative weight cycle -fn bellman_ford(graph [][]T, src int) { +fn bellman_ford[T](graph [][]T, src int) { mut edges := build_map_edges_from_graph(graph) // this function was done to adapt a graph representation // by a adjacency matrix, to list of adjacency (using a MAP) diff --git a/examples/graphs/dijkstra.v b/examples/graphs/dijkstra.v index 1bc3323a49..79454e4489 100644 --- a/examples/graphs/dijkstra.v +++ b/examples/graphs/dijkstra.v @@ -36,7 +36,7 @@ mut: // Function to push according to priority ... the lower priority is goes ahead // The "push" always sorted in pq -fn push_pq(mut prior_queue []T, data int, priority int) { +fn push_pq[T](mut prior_queue []T, data int, priority int) { mut temp := []T{} lenght_pq := prior_queue.len @@ -57,7 +57,7 @@ fn push_pq(mut prior_queue []T, data int, priority int) { } // Change the priority of a value/node ... exist a value, change its priority -fn updating_priority(mut prior_queue []T, search_data int, new_priority int) { +fn updating_priority[T](mut prior_queue []T, search_data int, new_priority int) { mut i := 0 mut lenght_pq := prior_queue.len @@ -76,7 +76,7 @@ fn updating_priority(mut prior_queue []T, search_data int, new_priority int) } // a single departure or remove from queue -fn departure_priority(mut prior_queue []T) int { +fn departure_priority[T](mut prior_queue []T) int { mut x := prior_queue[0].data prior_queue.delete(0) // or .delete_many(0, 1 ) return x @@ -84,7 +84,7 @@ fn departure_priority(mut prior_queue []T) int { // give a NODE v, return a list with all adjacents // Take care, only positive EDGES -fn all_adjacents(g [][]T, v int) []int { +fn all_adjacents[T](g [][]T, v int) []int { mut temp := []int{} for i in 0 .. (g.len) { if g[v][i] > 0 { @@ -95,7 +95,7 @@ fn all_adjacents(g [][]T, v int) []int { } // print the costs from origin up to all nodes -fn print_solution(dist []T) { +fn print_solution[T](dist []T) { print('Vertex \tDistance from Source') for node in 0 .. (dist.len) { print('\n ${node} ==> \t ${dist[node]}') @@ -103,7 +103,7 @@ fn print_solution(dist []T) { } // print all paths and their cost or weight -fn print_paths_dist(path []T, dist []T) { +fn print_paths_dist[T](path []T, dist []T) { print('\n Read the nodes from right to left (a path): \n') for node in 1 .. (path.len) { diff --git a/examples/graphs/minimal_spann_tree_prim.v b/examples/graphs/minimal_spann_tree_prim.v index 416400ebf5..ee40546c52 100644 --- a/examples/graphs/minimal_spann_tree_prim.v +++ b/examples/graphs/minimal_spann_tree_prim.v @@ -30,7 +30,7 @@ mut: // Function to push according to priority ... the lower priority is goes ahead // The "push" always sorted in pq -fn push_pq(mut prior_queue []T, data int, priority int) { +fn push_pq[T](mut prior_queue []T, data int, priority int) { mut temp := []T{} lenght_pq := prior_queue.len @@ -50,7 +50,7 @@ fn push_pq(mut prior_queue []T, data int, priority int) { } // Change the priority of a value/node ... exist a value, change its priority -fn updating_priority(mut prior_queue []T, search_data int, new_priority int) { +fn updating_priority[T](mut prior_queue []T, search_data int, new_priority int) { mut i := 0 mut lenght_pq := prior_queue.len @@ -72,7 +72,7 @@ fn updating_priority(mut prior_queue []T, search_data int, new_priority int) } // a single departure or remove from queue -fn departure_priority(mut prior_queue []T) int { +fn departure_priority[T](mut prior_queue []T) int { mut x := prior_queue[0].data prior_queue.delete(0) // or .delete_many(0, 1 ) return x @@ -80,7 +80,7 @@ fn departure_priority(mut prior_queue []T) int { // give a NODE v, return a list with all adjacents // Take care, only positive EDGES -fn all_adjacents(g [][]T, v int) []int { +fn all_adjacents[T](g [][]T, v int) []int { mut temp := []int{} for i in 0 .. (g.len) { if g[v][i] > 0 { diff --git a/examples/news_fetcher.v b/examples/news_fetcher.v index 6c90f0e3a6..e90daab57a 100644 --- a/examples/news_fetcher.v +++ b/examples/news_fetcher.v @@ -11,7 +11,7 @@ struct Story { } fn worker_fetch(mut p pool.PoolProcessor, cursor int, worker_id int) voidptr { - id := p.get_item(cursor) + id := p.get_item[int](cursor) resp := http.get('https://hacker-news.firebaseio.com/v0/item/${id}.json') or { println('failed to fetch data from /v0/item/${id}.json') return pool.no_result diff --git a/examples/quick_sort.v b/examples/quick_sort.v index 8455f642dc..4a0c089f1f 100644 --- a/examples/quick_sort.v +++ b/examples/quick_sort.v @@ -11,12 +11,12 @@ fn main() { arr << rand.intn(gen_max) or { 0 } } println('length of random array is ${arr.len}') - println('before quick sort whether array is sorted: ${is_sorted(arr)}') - quick_sort(mut arr, 0, arr.len - 1) - println('after quick sort whether array is sorted: ${is_sorted(arr)}') + println('before quick sort whether array is sorted: ${is_sorted[int](arr)}') + quick_sort[int](mut arr, 0, arr.len - 1) + println('after quick sort whether array is sorted: ${is_sorted[int](arr)}') } -fn quick_sort(mut arr []T, l int, r int) { +fn quick_sort[T](mut arr []T, l int, r int) { if l >= r { return } @@ -28,11 +28,11 @@ fn quick_sort(mut arr []T, l int, r int) { } } arr[l], arr[sep] = arr[sep], arr[l] - quick_sort(mut arr, l, sep - 1) - quick_sort(mut arr, sep + 1, r) + quick_sort[T](mut arr, l, sep - 1) + quick_sort[T](mut arr, sep + 1, r) } -fn is_sorted(arr []T) bool { +fn is_sorted[T](arr []T) bool { for i in 0 .. arr.len - 1 { if arr[i] > arr[i + 1] { return false diff --git a/vlib/arrays/arrays.v b/vlib/arrays/arrays.v index ce53102c13..ac7d010e06 100644 --- a/vlib/arrays/arrays.v +++ b/vlib/arrays/arrays.v @@ -11,7 +11,7 @@ module arrays // min returns the minimum value in the array // Example: arrays.min([1,2,3,0,9]) // => 0 -pub fn min(array []T) !T { +pub fn min[T](array []T) !T { if array.len == 0 { return error('.min called on an empty array') } @@ -26,7 +26,7 @@ pub fn min(array []T) !T { // max returns the maximum value in the array // Example: arrays.max([1,2,3,0,9]) // => 9 -pub fn max(array []T) !T { +pub fn max[T](array []T) !T { if array.len == 0 { return error('.max called on an empty array') } @@ -41,7 +41,7 @@ pub fn max(array []T) !T { // idx_min returns the index of the minimum value in the array // Example: arrays.idx_min([1,2,3,0,9]) // => 3 -pub fn idx_min(array []T) !int { +pub fn idx_min[T](array []T) !int { if array.len == 0 { return error('.idx_min called on an empty array') } @@ -58,7 +58,7 @@ pub fn idx_min(array []T) !int { // idx_max returns the index of the maximum value in the array // Example: arrays.idx_max([1,2,3,0,9]) // => 4 -pub fn idx_max(array []T) !int { +pub fn idx_max[T](array []T) !int { if array.len == 0 { return error('.idx_max called on an empty array') } @@ -76,7 +76,7 @@ pub fn idx_max(array []T) !int { // merge two sorted arrays (ascending) and maintain sorted order // Example: arrays.merge([1,3,5,7], [2,4,6,8]) // => [1,2,3,4,5,6,7,8] [direct_array_access] -pub fn merge(a []T, b []T) []T { +pub fn merge[T](a []T, b []T) []T { mut m := []T{len: a.len + b.len} mut ia := 0 mut ib := 0 @@ -114,7 +114,7 @@ pub fn merge(a []T, b []T) []T { // // NOTE: An error will be generated if the type annotation is omitted. // Example: arrays.group([1,2,3],[4,5,6]) // => [[1, 4], [2, 5], [3, 6]] -pub fn group(arrays ...[]T) [][]T { +pub fn group[T](arrays ...[]T) [][]T { mut length := if arrays.len > 0 { arrays[0].len } else { 0 } // calculate length of output by finding shortest input array for ndx in 1 .. arrays.len { @@ -142,7 +142,7 @@ pub fn group(arrays ...[]T) [][]T { // chunk array into a single array of arrays where each element is the next `size` elements of the original // Example: arrays.chunk([1, 2, 3, 4, 5, 6, 7, 8, 9], 2)) // => [[1, 2], [3, 4], [5, 6], [7, 8], [9]] -pub fn chunk(array []T, size int) [][]T { +pub fn chunk[T](array []T, size int) [][]T { // allocate chunk array mut chunks := [][]T{cap: array.len / size + if array.len % size == 0 { 0 } else { 1 }} @@ -177,7 +177,7 @@ pub struct WindowAttribute { // // Example: arrays.window([1, 2, 3, 4], size: 2) // => [[1, 2], [2, 3], [3, 4]] // Example: arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) // => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]] -pub fn window(array []T, attr WindowAttribute) [][]T { +pub fn window[T](array []T, attr WindowAttribute) [][]T { // allocate snapshot array mut windows := [][]T{cap: array.len - attr.size + 1} @@ -200,7 +200,7 @@ pub fn window(array []T, attr WindowAttribute) [][]T { // which means you can only pass array of numbers for now. // TODO: Fix generic operator overloading detection issue. // Example: arrays.sum([1, 2, 3, 4, 5])? // => 15 -pub fn sum(array []T) !T { +pub fn sum[T](array []T) !T { if array.len == 0 { return error('Cannot sum up array of nothing.') } else { @@ -223,7 +223,7 @@ pub fn sum(array []T) !T { // returns an error if the array is empty. // See also: [fold](#fold). // Example: arrays.reduce([1, 2, 3, 4, 5], fn (t1 int, t2 int) int { return t1 * t2 })! // => 120 -pub fn reduce(array []T, reduce_op fn (acc T, elem T) T) !T { +pub fn reduce[T](array []T, reduce_op fn (acc T, elem T) T) !T { if array.len == 0 { return error('Cannot reduce array of nothing.') } else { @@ -245,7 +245,7 @@ pub fn reduce(array []T, reduce_op fn (acc T, elem T) T) !T { // returns the accumulated value in `acc`. // returns an error if the array is empty. // See also: [fold_indexed](#fold_indexed). -pub fn reduce_indexed(array []T, reduce_op fn (idx int, acc T, elem T) T) !T { +pub fn reduce_indexed[T](array []T, reduce_op fn (idx int, acc T, elem T) T) !T { if array.len == 0 { return error('Cannot reduce array of nothing.') } else { @@ -265,7 +265,7 @@ pub fn reduce_indexed(array []T, reduce_op fn (idx int, acc T, elem T) T) !T // filter_indexed filters elements based on `predicate` function // being invoked on each element with its index in the original array. -pub fn filter_indexed(array []T, predicate fn (idx int, elem T) bool) []T { +pub fn filter_indexed[T](array []T, predicate fn (idx int, elem T) bool) []T { mut result := []T{cap: array.len} for i, e in array { @@ -287,7 +287,7 @@ pub fn filter_indexed(array []T, predicate fn (idx int, elem T) bool) []T { // fn (r int, t string) int { return r + t.len }) // assert r == 5 // ``` -pub fn fold(array []T, init R, fold_op fn (acc R, elem T) R) R { +pub fn fold[T, R](array []T, init R, fold_op fn (acc R, elem T) R) R { mut value := init for e in array { @@ -299,7 +299,7 @@ pub fn fold(array []T, init R, fold_op fn (acc R, elem T) R) R { // fold_indexed sets `acc = init`, then successively calls `acc = fold_op(idx, acc, elem)` for each element in `array`. // returns `acc`. -pub fn fold_indexed(array []T, init R, fold_op fn (idx int, acc R, elem T) R) R { +pub fn fold_indexed[T, R](array []T, init R, fold_op fn (idx int, acc R, elem T) R) R { mut value := init for i, e in array { @@ -311,7 +311,7 @@ pub fn fold_indexed(array []T, init R, fold_op fn (idx int, acc R, elem T) // flatten flattens n + 1 dimensional array into n dimensional array // Example: arrays.flatten([[1, 2, 3], [4, 5]]) // => [1, 2, 3, 4, 5] -pub fn flatten(array [][]T) []T { +pub fn flatten[T](array [][]T) []T { // calculate required capacity mut required_size := 0 @@ -335,7 +335,7 @@ pub fn flatten(array [][]T) []T { // flat_map creates a new array populated with the flattened result of calling transform function // being invoked on each element of `list`. -pub fn flat_map(array []T, transform fn (elem T) []R) []R { +pub fn flat_map[T, R](array []T, transform fn (elem T) []R) []R { mut result := [][]R{cap: array.len} for v in array { @@ -347,7 +347,7 @@ pub fn flat_map(array []T, transform fn (elem T) []R) []R { // flat_map_indexed creates a new array populated with the flattened result of calling the `transform` function // being invoked on each element with its index in the original array. -pub fn flat_map_indexed(array []T, transform fn (idx int, elem T) []R) []R { +pub fn flat_map_indexed[T, R](array []T, transform fn (idx int, elem T) []R) []R { mut result := [][]R{cap: array.len} for i, v in array { @@ -359,7 +359,7 @@ pub fn flat_map_indexed(array []T, transform fn (idx int, elem T) []R) []R // map_indexed creates a new array populated with the result of calling the `transform` function // being invoked on each element with its index in the original array. -pub fn map_indexed(array []T, transform fn (idx int, elem T) R) []R { +pub fn map_indexed[T, R](array []T, transform fn (idx int, elem T) R) []R { mut result := []R{cap: array.len} for i, v in array { @@ -371,7 +371,7 @@ pub fn map_indexed(array []T, transform fn (idx int, elem T) R) []R { // group_by groups together elements, for which the `grouping_op` callback produced the same result. // Example: arrays.group_by(['H', 'el', 'lo'], fn (v string) int { return v.len }) // => {1: ['H'], 2: ['el', 'lo']} -pub fn group_by(array []V, grouping_op fn (val V) K) map[K][]V { +pub fn group_by[K, V](array []V, grouping_op fn (val V) K) map[K][]V { mut result := map[K][]V{} for v in array { @@ -394,7 +394,7 @@ pub fn group_by(array []V, grouping_op fn (val V) K) map[K][]V { // Example: arrays.concat([1, 2, 3], 4, 5, 6) == [1, 2, 3, 4, 5, 6] // => true // Example: arrays.concat([1, 2, 3], ...[4, 5, 6]) == [1, 2, 3, 4, 5, 6] // => true // Example: arr << [4, 5, 6] // does what you need if arr is mutable -pub fn concat(a []T, b ...T) []T { +pub fn concat[T](a []T, b ...T) []T { mut m := []T{cap: a.len + b.len} m << a @@ -405,7 +405,7 @@ pub fn concat(a []T, b ...T) []T { // returns the smallest element >= val, requires `array` to be sorted // Example: arrays.lower_bound([2, 4, 6, 8], 3)? // => 4 -pub fn lower_bound(array []T, val T) !T { +pub fn lower_bound[T](array []T, val T) !T { if array.len == 0 { return error('.lower_bound called on an empty array') } @@ -428,7 +428,7 @@ pub fn lower_bound(array []T, val T) !T { // returns the largest element <= val, requires `array` to be sorted // Example: arrays.upper_bound([2, 4, 6, 8], 3)! // => 2 -pub fn upper_bound(array []T, val T) !T { +pub fn upper_bound[T](array []T, val T) !T { if array.len == 0 { return error('.upper_bound called on an empty array') } @@ -453,7 +453,7 @@ pub fn upper_bound(array []T, val T) !T { // Binary searches on sorted lists can be faster than other array searches because at maximum // the algorithm only has to traverse log N elements // Example: arrays.binary_search([1, 2, 3, 4], 4)? // => 3 -pub fn binary_search(array []T, target T) !int { +pub fn binary_search[T](array []T, target T) !int { mut left := 0 mut right := array.len - 1 for ; left <= right; { @@ -480,12 +480,12 @@ pub fn binary_search(array []T, target T) !int { // arrays.rotate_left(mut x, 2) // println(x) // [3, 4, 5, 6, 1, 2] // ``` -pub fn rotate_left(mut array []T, mid int) { +pub fn rotate_left[T](mut array []T, mid int) { assert mid <= array.len && mid >= 0 k := array.len - mid p := &T(array.data) unsafe { - ptr_rotate(mid, &T(usize(voidptr(p)) + usize(sizeof(T)) * usize(mid)), k) + ptr_rotate[T](mid, &T(usize(voidptr(p)) + usize(sizeof(T)) * usize(mid)), k) } } @@ -498,27 +498,27 @@ pub fn rotate_left(mut array []T, mid int) { // arrays.rotate_right(mut x, 2) // println(x) // [5, 6, 1, 2, 3, 4] // ``` -pub fn rotate_right(mut array []T, k int) { +pub fn rotate_right[T](mut array []T, k int) { assert k <= array.len && k >= 0 mid := array.len - k p := &T(array.data) unsafe { - ptr_rotate(mid, &T(usize(voidptr(p)) + usize(sizeof(T)) * usize(mid)), k) + ptr_rotate[T](mid, &T(usize(voidptr(p)) + usize(sizeof(T)) * usize(mid)), k) } } [unsafe] -fn ptr_rotate(left_ int, mid &T, right_ int) { +fn ptr_rotate[T](left_ int, mid &T, right_ int) { mut left := usize(left_) mut right := usize(right_) for { delta := if left < right { left } else { right } - if delta <= raw_array_cap() { + if delta <= raw_array_cap[T]() { break } unsafe { - swap_nonoverlapping(&T(usize(voidptr(mid)) - left * usize(sizeof(T))), + swap_nonoverlapping[T](&T(usize(voidptr(mid)) - left * usize(sizeof(T))), &T(usize(voidptr(mid)) + usize(right - delta) * usize(sizeof(T))), int(delta)) } if left <= right { @@ -530,7 +530,7 @@ fn ptr_rotate(left_ int, mid &T, right_ int) { unsafe { sz := usize(sizeof(T)) - rawarray := C.malloc(raw_array_malloc_size()) + rawarray := C.malloc(raw_array_malloc_size[T]()) dim := &T(usize(voidptr(mid)) - left * sz + right * sz) if left <= right { C.memcpy(rawarray, voidptr(usize(voidptr(mid)) - left * sz), left * sz) @@ -565,7 +565,7 @@ const ( extra_size = 32 * sizeof(usize) ) -fn raw_array_cap() usize { +fn raw_array_cap[T]() usize { if sizeof(T) > arrays.extra_size { return 1 } else { @@ -573,7 +573,7 @@ fn raw_array_cap() usize { } } -fn raw_array_malloc_size() usize { +fn raw_array_malloc_size[T]() usize { if sizeof(T) > arrays.extra_size { return usize(sizeof(T)) * 2 } else { @@ -614,7 +614,7 @@ fn memswap(x voidptr, y voidptr, len usize) { } [unsafe] -fn swap_nonoverlapping(x_ &T, y_ &T, count int) { +fn swap_nonoverlapping[T](x_ &T, y_ &T, count int) { x := voidptr(x_) y := voidptr(y_) @@ -627,12 +627,12 @@ fn swap_nonoverlapping(x_ &T, y_ &T, count int) { // copy copies the `src` array elements to the `dst` array. // The number of the elements copied is the minimum of the length of both arrays. // Returns the number of elements copied. -pub fn copy(mut dst []T, src []T) int { +pub fn copy[T](mut dst []T, src []T) int { min := if dst.len < src.len { dst.len } else { src.len } if min <= 0 { return 0 } - if can_copy_bits() { + if can_copy_bits[T]() { blen := min * int(sizeof(T)) unsafe { vmemmove(&T(dst.data), src.data, blen) } } else { @@ -646,7 +646,7 @@ pub fn copy(mut dst []T, src []T) int { // determines if T can be copied using `memcpy` // false if autofree needs to intervene // false if type is not copyable e.g. map -fn can_copy_bits() bool { +fn can_copy_bits[T]() bool { // references, C pointers, integers, floats, runes if T.name[0] in [`&`, `b`, `c`, `f`, `i`, `r`, `u`, `v`] { return true @@ -657,7 +657,7 @@ fn can_copy_bits() bool { // carray_to_varray copies a C byte array into a V array of type `T`. // See also: `cstring_to_vstring` [unsafe] -pub fn carray_to_varray(c_array voidptr, c_array_len int) []T { +pub fn carray_to_varray[T](c_array voidptr, c_array_len int) []T { mut v_array := []T{len: c_array_len} unsafe { vmemcpy(v_array.data, c_array, c_array_len * int(sizeof(T))) } return v_array diff --git a/vlib/arrays/arrays_test.v b/vlib/arrays/arrays_test.v index 4fac1753e4..fb9d7275c8 100644 --- a/vlib/arrays/arrays_test.v +++ b/vlib/arrays/arrays_test.v @@ -65,10 +65,10 @@ fn test_merge() { b := [2, 4, 4, 5, 6, 8] c := []int{} d := []int{} - assert merge(a, b) == [1, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8] - assert merge(c, d) == [] - assert merge(a, c) == a - assert merge(d, b) == b + assert merge[int](a, b) == [1, 2, 3, 4, 4, 5, 5, 5, 6, 7, 8] + assert merge[int](c, d) == [] + assert merge[int](a, c) == a + assert merge[int](d, b) == b } fn test_fixed_array_assignment() { @@ -94,14 +94,14 @@ fn test_fixed_array_assignment() { fn test_array_flat_map() { a := ['Hello V', 'Hello World', 'V Lang'] - assert flat_map(a, fn (e string) []string { + assert flat_map[string, string](a, fn (e string) []string { return e.split(' ') }) == ['Hello', 'V', 'Hello', 'World', 'V', 'Lang'] } fn test_array_flat_map_indexed() { a := ['AB', 'CD', 'EF'] - assert flat_map_indexed(a, fn (i int, e string) []string { + assert flat_map_indexed[string, string](a, fn (i int, e string) []string { mut arr := [i.str()] arr << e.split('') return arr @@ -110,7 +110,7 @@ fn test_array_flat_map_indexed() { fn test_map_indexed() { a := [1, 2, 3] - assert map_indexed(a, fn (i int, e int) int { + assert map_indexed[int, int](a, fn (i int, e int) int { return i + e * e }) == [1, 5, 11] } @@ -119,59 +119,59 @@ fn test_group() { x := [4, 5, 6] y := [2, 1, 3] - z := group(x, y) + z := group[int](x, y) assert z == [[4, 2], [5, 1], [6, 3]] x2 := [8, 9] - z2 := group(x2, y) + z2 := group[int](x2, y) assert z2 == [[8, 2], [9, 1]] - assert group(x, []int{}) == [][]int{} + assert group[int](x, []int{}) == [][]int{} } fn test_chunk() { x := [1, 2, 3, 4, 5] y := ['a', 'b', 'c', 'd', 'e', 'f'] - z1 := chunk(x, 2) + z1 := chunk[int](x, 2) assert z1 == [[1, 2], [3, 4], [5]] - z2 := chunk(y, 3) + z2 := chunk[string](y, 3) assert z2 == [['a', 'b', 'c'], ['d', 'e', 'f']] - assert chunk([]int{}, 2) == [][]int{} + assert chunk[int]([]int{}, 2) == [][]int{} } fn test_window() { x := [1, 2, 3, 4, 5, 6] - assert window(x, size: 3) == [[1, 2, 3], [2, 3, 4], [3, 4, 5], + assert window[int](x, size: 3) == [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] - assert window(x, size: 3, step: 2) == [[1, 2, 3], [3, 4, 5]] - assert window([]int{}, size: 2) == [][]int{} + assert window[int](x, size: 3, step: 2) == [[1, 2, 3], [3, 4, 5]] + assert window[int]([]int{}, size: 2) == [][]int{} } fn test_sum() { x := [1, 2, 3, 4, 5] - assert sum(x) or { 0 } == 15 - assert sum([1.0, 2.5, 3.5, 4.0]) or { 0 } == 11.0 - assert sum([]int{}) or { 0 } == 0 + assert sum[int](x) or { 0 } == 15 + assert sum[f64]([1.0, 2.5, 3.5, 4.0]) or { 0 } == 11.0 + assert sum[int]([]int{}) or { 0 } == 0 } fn test_reduce() { x := [1, 2, 3, 4, 5] - assert reduce(x, fn (t1 int, t2 int) int { + assert reduce[int](x, fn (t1 int, t2 int) int { return t1 + t2 }) or { 0 } == 15 - assert reduce(['H', 'e', 'l', 'l', 'o'], fn (t1 string, t2 string) string { + assert reduce[string](['H', 'e', 'l', 'l', 'o'], fn (t1 string, t2 string) string { return t1 + t2 }) or { '' } == 'Hello' // For the sake please use array's join instead. - assert reduce([]int{}, fn (t1 int, t2 int) int { + assert reduce[int]([]int{}, fn (t1 int, t2 int) int { return 0 }) or { -1 } == -1 } fn test_reduce_indexed() { x := [1, 2, 3, 4, 5] - assert reduce_indexed(x, fn (idx int, t1 int, t2 int) int { + assert reduce_indexed[int](x, fn (idx int, t1 int, t2 int) int { return idx + t1 + t2 }) or { 0 } == 25 } @@ -179,7 +179,7 @@ fn test_reduce_indexed() { fn test_filter_indexed() { x := [0, 1, 2, 3, 4, 5] - assert filter_indexed(x, fn (idx int, e int) bool { + assert filter_indexed[int](x, fn (idx int, e int) bool { return idx % 2 == 0 }) == [0, 2, 4] } @@ -187,13 +187,13 @@ fn test_filter_indexed() { fn test_fold() { x := [1, 2, 3, 4, 5] - assert fold(x, 5, fn (r int, t int) int { + assert fold[int, int](x, 5, fn (r int, t int) int { return r + t }) == 20 - assert fold(['H', 'e', 'l', 'l', 'l'], 0, fn (r int, t string) int { + assert fold[string, int](['H', 'e', 'l', 'l', 'l'], 0, fn (r int, t string) int { return r + t[0] }) == 497 - assert fold([]int{}, -1, fn (t1 int, t2 int) int { + assert fold[int, int]([]int{}, -1, fn (t1 int, t2 int) int { return 0 }) == -1 } @@ -201,7 +201,7 @@ fn test_fold() { fn test_fold_indexed() { x := [1, 2, 3, 4, 5] - assert fold_indexed(x, 5, fn (idx int, r int, t int) int { + assert fold_indexed[int, int](x, 5, fn (idx int, r int, t int) int { return idx + r + t }) == 30 } @@ -209,20 +209,20 @@ fn test_fold_indexed() { fn test_flatten() { x := [[1, 2, 3], [4, 5, 6]] - assert flatten(x) == [1, 2, 3, 4, 5, 6] - assert flatten([[]int{}]) == [] + assert flatten[int](x) == [1, 2, 3, 4, 5, 6] + assert flatten[int]([[]int{}]) == [] } fn test_group_by() { x := ['H', 'el', 'l', 'o '] - assert group_by(x, fn (v string) int { + assert group_by[int, string](x, fn (v string) int { return v.len }) == { 1: ['H', 'l'] 2: ['el', 'o '] } - assert group_by([]int{}, fn (v int) int { + assert group_by[int, int]([]int{}, fn (v int) int { return 0 }) == map[int][]int{} } @@ -329,15 +329,15 @@ fn test_copy() { } fn test_can_copy_bits() { - assert can_copy_bits() - assert can_copy_bits() - assert can_copy_bits() - assert can_copy_bits<&u8>() + assert can_copy_bits[u8]() + assert can_copy_bits[int]() + assert can_copy_bits[voidptr]() + assert can_copy_bits[&u8]() // autofree needs to intercept assign - assert !can_copy_bits() - assert !can_copy_bits<[]int>() + assert !can_copy_bits[string]() + assert !can_copy_bits[[]int]() // map not copyable - assert !can_copy_bits() + assert !can_copy_bits[map[string]int]() } type Str = string diff --git a/vlib/bitfield/bitfield.v b/vlib/bitfield/bitfield.v index 9ae8d1d097..38d5a7d43d 100644 --- a/vlib/bitfield/bitfield.v +++ b/vlib/bitfield/bitfield.v @@ -155,7 +155,7 @@ pub fn (instance BitField) extract(start int, len int) u64 { // insert sets bit numbers from 'start' to 'len' length with // the value converted from the number 'value'. // 0000 (1, 2, 0b10) => 0100 -pub fn (mut instance BitField) insert(start int, len int, _value T) { +pub fn (mut instance BitField) insert[T](start int, len int, _value T) { // panic? if start < 0 { return @@ -190,7 +190,7 @@ pub fn (instance BitField) extract_lowest_bits_first(start int, len int) u64 { // insert sets bit numbers from 'start' to 'len' length with // the value converted from the number 'value'. // 0000 (1, 2, 0b10) => 0010 -pub fn (mut instance BitField) insert_lowest_bits_first(start int, len int, _value T) { +pub fn (mut instance BitField) insert_lowest_bits_first[T](start int, len int, _value T) { // panic? if start < 0 { return diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 432e73b520..4f2b1f265b 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -1570,7 +1570,7 @@ fn test_clone_of_same_elem_size_array() { assert arr2 == [Abc{1, 2, 3}, Abc{2, 3, 4}] } -pub fn example(mut arr []T) []T { +pub fn example[T](mut arr []T) []T { return arr.clone() } diff --git a/vlib/builtin/js/array_test.js.v b/vlib/builtin/js/array_test.js.v index 6a81a56159..2722eeccac 100644 --- a/vlib/builtin/js/array_test.js.v +++ b/vlib/builtin/js/array_test.js.v @@ -1482,7 +1482,7 @@ fn test_clone_of_same_elem_size_array() { assert arr2 == [Abc{1, 2, 3}, Abc{2, 3, 4}] } -pub fn example(mut arr []T) []T { +pub fn example[T](mut arr []T) []T { return arr.clone() } diff --git a/vlib/builtin/js/promise.js.v b/vlib/builtin/js/promise.js.v index a1a80626d0..e155b6992f 100644 --- a/vlib/builtin/js/promise.js.v +++ b/vlib/builtin/js/promise.js.v @@ -14,46 +14,46 @@ pub fn JS.Promise.race(JS.Array) JS.Promise // The Promise object represents the eventual completion (or failure) // of an asynchronous operation and its resulting value. -pub struct Promise { +pub struct Promise[T] { mut: promise JS.Promise [noinit] } -pub fn promise_new(executor fn (resolve fn (T), reject fn (JS.Any))) Promise { +pub fn promise_new[T](executor fn (resolve fn (T), reject fn (JS.Any))) Promise[T] { promise := JS.Promise.prototype.constructor(executor) - return Promise{promise} + return Promise[T]{promise} } -pub fn (p Promise) then(on_fullfilled fn (T), on_rejected fn (JS.Any)) { +pub fn (p Promise[T]) then(on_fullfilled fn (T), on_rejected fn (JS.Any)) { p.promise.then(on_fullfilled, on_rejected) } // catch method returns a Promise and deals with rejected cases only. -pub fn (p Promise) catch(callback fn (error JS.Any)) Promise { +pub fn (p Promise[T]) catch(callback fn (error JS.Any)) Promise[T] { promise := p.promise.catch(callback) - return Promise{promise} + return Promise[T]{promise} } -pub fn (p Promise) finally(callback fn ()) Promise { +pub fn (p Promise[T]) finally[U](callback fn ()) Promise[JS.Any] { promise := p.promise.finally(callback) - return Promise{promise} + return Promise[JS.Any]{promise} } // reject returns promise which was rejected because of specified error -pub fn promise_reject(error JS.Any) Promise { +pub fn promise_reject(error JS.Any) Promise[JS.Any] { promise := JS.Promise.reject(error) - return Promise{promise} + return Promise[JS.Any]{promise} } // resolve returns promise which was resolved with specified value -pub fn promise_resolve(result T) Promise { +pub fn promise_resolve[T](result T) Promise[T] { promise := JS.Promise.resolve(result) - return Promise{promise} + return Promise[T]{promise} } // race returns returns a promise that fulfills or rejects as soon as one of // the promises in an iterable fulfills or rejects, with the value or reason from that promise. -pub fn promise_race(promises []Promise) Promise { +pub fn promise_race[T](promises []Promise[T]) Promise[T] { promises_ := JS.Array.prototype.constructor() for elem in promises { @@ -61,7 +61,7 @@ pub fn promise_race(promises []Promise) Promise { } promise := JS.Promise.race(promises_) - return Promise{promise} + return Promise[T]{promise} } pub fn JS.Promise.all(JS.Array) JS.Promise diff --git a/vlib/crypto/ed25519/internal/ed25519_test.v b/vlib/crypto/ed25519/internal/ed25519_test.v index 102e272713..c4729cfe14 100644 --- a/vlib/crypto/ed25519/internal/ed25519_test.v +++ b/vlib/crypto/ed25519/internal/ed25519_test.v @@ -130,7 +130,7 @@ fn works_check_on_sign_input_string(item string) bool { } fn worker_for_string_content(mut p pool.PoolProcessor, idx int, worker_id int) &SignResult { - item := p.get_item(idx) + item := p.get_item[string](idx) // println('worker_s worker_id: $worker_id | idx: $idx ') res := works_check_on_sign_input_string(item) mut sr := &SignResult{ @@ -155,8 +155,8 @@ fn test_input_from_djb_ed25519_crypto_sign_input_with_syncpool() { callback: worker_for_string_content maxjobs: 4 ) - pool_s.work_on_items(contents) - for i, x in pool_s.get_results() { + pool_s.work_on_items[string](contents) + for i, x in pool_s.get_results[SignResult]() { // println("i: $i = $x.result") assert x.result == true } diff --git a/vlib/datatypes/README.md b/vlib/datatypes/README.md index bece6af48f..5c1251e568 100644 --- a/vlib/datatypes/README.md +++ b/vlib/datatypes/README.md @@ -14,7 +14,7 @@ your actual elements. For example: ```v import datatypes -mut stack := datatypes.Stack{} +mut stack := datatypes.Stack[int]{} stack.push(1) println(stack) ``` diff --git a/vlib/datatypes/bstree.v b/vlib/datatypes/bstree.v index db85302544..78e9637bf4 100644 --- a/vlib/datatypes/bstree.v +++ b/vlib/datatypes/bstree.v @@ -2,36 +2,36 @@ module datatypes /// Internal rapresentation of the tree node [heap] -struct BSTreeNode { +struct BSTreeNode[T] { mut: // Mark a node as initialized is_init bool // Value of the node value T // The parent of the node - parent &BSTreeNode = unsafe { 0 } + parent &BSTreeNode[T] = unsafe { 0 } // The left side with value less than the // value of this node - left &BSTreeNode = unsafe { 0 } + left &BSTreeNode[T] = unsafe { 0 } // The right side with value grater than the // value of thiss node - right &BSTreeNode = unsafe { 0 } + right &BSTreeNode[T] = unsafe { 0 } } // Create new root bst node -fn new_root_node(value T) &BSTreeNode { - return &BSTreeNode{ +fn new_root_node[T](value T) &BSTreeNode[T] { + return &BSTreeNode[T]{ is_init: true value: value - parent: new_none_node(true) - left: new_none_node(false) - right: new_none_node(false) + parent: new_none_node[T](true) + left: new_none_node[T](false) + right: new_none_node[T](false) } } // new_node creates a new bst node with a parent reference. -fn new_node(parent &BSTreeNode, value T) &BSTreeNode { - return &BSTreeNode{ +fn new_node[T](parent &BSTreeNode[T], value T) &BSTreeNode[T] { + return &BSTreeNode[T]{ is_init: true value: value parent: parent @@ -39,19 +39,19 @@ fn new_node(parent &BSTreeNode, value T) &BSTreeNode { } // new_none_node creates a dummy node. -fn new_none_node(init bool) &BSTreeNode { - return &BSTreeNode{ +fn new_none_node[T](init bool) &BSTreeNode[T] { + return &BSTreeNode[T]{ is_init: init } } // bind to an actual instance of a node. -fn (mut node BSTreeNode) bind(mut to_bind BSTreeNode, left bool) { +fn (mut node BSTreeNode[T]) bind(mut to_bind BSTreeNode[T], left bool) { node.left = to_bind.left node.right = to_bind.right node.value = to_bind.value node.is_init = to_bind.is_init - to_bind = new_none_node(false) + to_bind = new_none_node[T](false) } // Pure Binary Seach Tree implementation @@ -59,13 +59,13 @@ fn (mut node BSTreeNode) bind(mut to_bind BSTreeNode, left bool) { // Pure V implementation of the Binary Search Tree // Time complexity of main operation O(log N) // Space complexity O(N) -pub struct BSTree { +pub struct BSTree[T] { mut: - root &BSTreeNode = unsafe { 0 } + root &BSTreeNode[T] = unsafe { 0 } } // insert give the possibility to insert an element in the BST. -pub fn (mut bst BSTree) insert(value T) bool { +pub fn (mut bst BSTree[T]) insert(value T) bool { if bst.is_empty() { bst.root = new_root_node(value) return true @@ -74,7 +74,7 @@ pub fn (mut bst BSTree) insert(value T) bool { } // insert_helper walks the tree and inserts the given node. -fn (mut bst BSTree) insert_helper(mut node BSTreeNode, value T) bool { +fn (mut bst BSTree[T]) insert_helper(mut node BSTreeNode[T], value T) bool { if node.value < value { if unsafe { node.right != 0 } && node.right.is_init { return bst.insert_helper(mut node.right, value) @@ -92,13 +92,13 @@ fn (mut bst BSTree) insert_helper(mut node BSTreeNode, value T) bool { } // contains checks if an element with a given `value` is inside the BST. -pub fn (bst &BSTree) contains(value T) bool { +pub fn (bst &BSTree[T]) contains(value T) bool { return bst.contains_helper(bst.root, value) } // contains_helper is a helper function to walk the tree, and return // the absence or presence of the `value`. -fn (bst &BSTree) contains_helper(node &BSTreeNode, value T) bool { +fn (bst &BSTree[T]) contains_helper(node &BSTreeNode[T], value T) bool { if unsafe { node == 0 } || !node.is_init { return false } @@ -112,14 +112,14 @@ fn (bst &BSTree) contains_helper(node &BSTreeNode, value T) bool { } // remove removes an element with `value` from the BST. -pub fn (mut bst BSTree) remove(value T) bool { +pub fn (mut bst BSTree[T]) remove(value T) bool { if bst.is_empty() { return false } return bst.remove_helper(mut bst.root, value, false) } -fn (mut bst BSTree) remove_helper(mut node BSTreeNode, value T, left bool) bool { +fn (mut bst BSTree[T]) remove_helper(mut node BSTreeNode[T], value T, left bool) bool { if !node.is_init { return false } @@ -136,11 +136,11 @@ fn (mut bst BSTree) remove_helper(mut node BSTreeNode, value T, left bool) } else { mut parent := node.parent if left { - parent.left = new_none_node(false) + parent.left = new_none_node[T](false) } else { - parent.right = new_none_node(false) + parent.right = new_none_node[T](false) } - node = new_none_node(false) + node = new_none_node[T](false) } return true } @@ -152,9 +152,9 @@ fn (mut bst BSTree) remove_helper(mut node BSTreeNode, value T, left bool) } // get_max_from_right returns the max element of the BST following the right branch. -fn (bst &BSTree) get_max_from_right(node &BSTreeNode) &BSTreeNode { +fn (bst &BSTree[T]) get_max_from_right(node &BSTreeNode[T]) &BSTreeNode[T] { if unsafe { node == 0 } { - return new_none_node(false) + return new_none_node[T](false) } right_node := node.right if unsafe { right_node == 0 } || !right_node.is_init { @@ -164,9 +164,9 @@ fn (bst &BSTree) get_max_from_right(node &BSTreeNode) &BSTreeNode { } // get_min_from_left returns the min element of the BST by following the left branch. -fn (bst &BSTree) get_min_from_left(node &BSTreeNode) &BSTreeNode { +fn (bst &BSTree[T]) get_min_from_left(node &BSTreeNode[T]) &BSTreeNode[T] { if unsafe { node == 0 } { - return new_none_node(false) + return new_none_node[T](false) } left_node := node.left if unsafe { left_node == 0 } || !left_node.is_init { @@ -176,19 +176,19 @@ fn (bst &BSTree) get_min_from_left(node &BSTreeNode) &BSTreeNode { } // is_empty checks if the BST is empty -pub fn (bst &BSTree) is_empty() bool { +pub fn (bst &BSTree[T]) is_empty() bool { return unsafe { bst.root == 0 } } // in_order_traversal traverses the BST in order, and returns the result as an array. -pub fn (bst &BSTree) in_order_traversal() []T { +pub fn (bst &BSTree[T]) in_order_traversal() []T { mut result := []T{} bst.in_order_traversal_helper(bst.root, mut result) return result } // in_order_traversal_helper helps traverse the BST, and accumulates the result in the `result` array. -fn (bst &BSTree) in_order_traversal_helper(node &BSTreeNode, mut result []T) { +fn (bst &BSTree[T]) in_order_traversal_helper(node &BSTreeNode[T], mut result []T) { if unsafe { node == 0 } || !node.is_init { return } @@ -198,7 +198,7 @@ fn (bst &BSTree) in_order_traversal_helper(node &BSTreeNode, mut result [] } // post_order_traversal traverses the BST in post order, and returns the result in an array. -pub fn (bst &BSTree) post_order_traversal() []T { +pub fn (bst &BSTree[T]) post_order_traversal() []T { mut result := []T{} bst.post_order_traversal_helper(bst.root, mut result) return result @@ -206,7 +206,7 @@ pub fn (bst &BSTree) post_order_traversal() []T { // post_order_traversal_helper is a helper function that traverses the BST in post order, // accumulating the result in an array. -fn (bst &BSTree) post_order_traversal_helper(node &BSTreeNode, mut result []T) { +fn (bst &BSTree[T]) post_order_traversal_helper(node &BSTreeNode[T], mut result []T) { if unsafe { node == 0 } || !node.is_init { return } @@ -217,7 +217,7 @@ fn (bst &BSTree) post_order_traversal_helper(node &BSTreeNode, mut result } // pre_order_traversal traverses the BST in pre order, and returns the result as an array. -pub fn (bst &BSTree) pre_order_traversal() []T { +pub fn (bst &BSTree[T]) pre_order_traversal() []T { mut result := []T{} bst.pre_order_traversal_helper(bst.root, mut result) return result @@ -225,7 +225,7 @@ pub fn (bst &BSTree) pre_order_traversal() []T { // pre_order_traversal_helper is a helper function to traverse the BST // in pre order and accumulates the results in an array. -fn (bst &BSTree) pre_order_traversal_helper(node &BSTreeNode, mut result []T) { +fn (bst &BSTree[T]) pre_order_traversal_helper(node &BSTreeNode[T], mut result []T) { if unsafe { node == 0 } || !node.is_init { return } @@ -235,9 +235,9 @@ fn (bst &BSTree) pre_order_traversal_helper(node &BSTreeNode, mut result [ } // get_node is a helper method to ge the internal rapresentation of the node with the `value`. -fn (bst &BSTree) get_node(node &BSTreeNode, value T) &BSTreeNode { +fn (bst &BSTree[T]) get_node(node &BSTreeNode[T], value T) &BSTreeNode[T] { if unsafe { node == 0 } || !node.is_init { - return new_none_node(false) + return new_none_node[T](false) } if node.value == value { return node @@ -256,7 +256,7 @@ fn (bst &BSTree) get_node(node &BSTreeNode, value T) &BSTreeNode { //```v // left_value, exist := bst.to_left(10) //``` -pub fn (bst &BSTree) to_left(value T) ?T { +pub fn (bst &BSTree[T]) to_left(value T) ?T { if bst.is_empty() { return none } @@ -275,7 +275,7 @@ pub fn (bst &BSTree) to_left(value T) ?T { //```v // left_value, exist := bst.to_right(10) //``` -pub fn (bst &BSTree) to_right(value T) ?T { +pub fn (bst &BSTree[T]) to_right(value T) ?T { if bst.is_empty() { return none } @@ -289,7 +289,7 @@ pub fn (bst &BSTree) to_right(value T) ?T { // max return the max element inside the BST. // Time complexity O(N) if the BST is not balanced -pub fn (bst &BSTree) max() ?T { +pub fn (bst &BSTree[T]) max() ?T { if bst.is_empty() { return none } @@ -302,7 +302,7 @@ pub fn (bst &BSTree) max() ?T { // min return the minimum element in the BST. // Time complexity O(N) if the BST is not balanced. -pub fn (bst &BSTree) min() ?T { +pub fn (bst &BSTree[T]) min() ?T { if bst.is_empty() { return none } diff --git a/vlib/datatypes/bstree_test.v b/vlib/datatypes/bstree_test.v index 6309afdde1..63ae1833ea 100644 --- a/vlib/datatypes/bstree_test.v +++ b/vlib/datatypes/bstree_test.v @@ -3,7 +3,7 @@ module datatypes // Make an insert of one element and check if // the bst is able to fin it. fn test_insert_into_bst_one() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) == true assert bst.contains(10) == true assert bst.contains(20) == false @@ -12,7 +12,7 @@ fn test_insert_into_bst_one() { // Make the insert of more element inside the BST // and check if the BST is able to find all the values fn test_insert_into_bst_two() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(9) @@ -26,7 +26,7 @@ fn test_insert_into_bst_two() { // Test if the in_order_traversals list return the correct // result array fn test_in_order_bst_visit_one() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -38,7 +38,7 @@ fn test_in_order_bst_visit_one() { // Test if the post_order_bst_visit return the correct // result array fn test_post_order_bst_visit_one() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -49,7 +49,7 @@ fn test_post_order_bst_visit_one() { // Test if the pre_order_traversal return the correct result array fn test_pre_order_bst_visit_one() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -61,7 +61,7 @@ fn test_pre_order_bst_visit_one() { // After many insert check if we are abe to get the correct // right and left value of the root. fn test_get_left_root() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -76,7 +76,7 @@ fn test_get_left_root() { // Check if BST panic if we call some operation on an empty BST. fn test_get_left_on_empty_bst() { - mut bst := BSTree{} + mut bst := BSTree[int]{} left_val := bst.to_left(10) or { -1 } assert left_val == -1 @@ -88,7 +88,7 @@ fn test_get_left_on_empty_bst() { // Check the remove operation if it is able to remove // all elements required, and mantains the BST propriety. fn test_remove_from_bst_one() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -102,7 +102,7 @@ fn test_remove_from_bst_one() { // Another test n the remove BST, this remove an intermidia node // that it is a triky operation. fn test_remove_from_bst_two() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert bst.insert(10) assert bst.insert(20) assert bst.insert(21) @@ -115,7 +115,7 @@ fn test_remove_from_bst_two() { // check if we are able to get the max from the BST. fn test_get_max_in_bst() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert (bst.max() or { -1 }) == -1 assert bst.insert(10) assert bst.insert(20) @@ -127,7 +127,7 @@ fn test_get_max_in_bst() { // check if we are able to get the min from the BST. fn test_get_min_in_bst() { - mut bst := BSTree{} + mut bst := BSTree[int]{} assert (bst.min() or { -1 }) == -1 assert bst.insert(10) assert bst.insert(20) diff --git a/vlib/datatypes/doubly_linked_list.v b/vlib/datatypes/doubly_linked_list.v index e02e5047a3..e7b664dc75 100644 --- a/vlib/datatypes/doubly_linked_list.v +++ b/vlib/datatypes/doubly_linked_list.v @@ -1,36 +1,36 @@ module datatypes -struct DoublyListNode { +struct DoublyListNode[T] { mut: data T - next &DoublyListNode = unsafe { 0 } - prev &DoublyListNode = unsafe { 0 } + next &DoublyListNode[T] = unsafe { 0 } + prev &DoublyListNode[T] = unsafe { 0 } } // DoublyLinkedList represents a generic doubly linked list of elements, each of type T. -pub struct DoublyLinkedList { +pub struct DoublyLinkedList[T] { mut: - head &DoublyListNode = unsafe { 0 } - tail &DoublyListNode = unsafe { 0 } + head &DoublyListNode[T] = unsafe { 0 } + tail &DoublyListNode[T] = unsafe { 0 } // Internal iter pointer for allowing safe modification // of the list while iterating. TODO: use an option // instead of a pointer to determine it is initialized. - iter &DoublyListIter = unsafe { 0 } + iter &DoublyListIter[T] = unsafe { 0 } len int } // is_empty checks if the linked list is empty -pub fn (list DoublyLinkedList) is_empty() bool { +pub fn (list DoublyLinkedList[T]) is_empty() bool { return list.len == 0 } // len returns the length of the linked list -pub fn (list DoublyLinkedList) len() int { +pub fn (list DoublyLinkedList[T]) len() int { return list.len } // first returns the first element of the linked list -pub fn (list DoublyLinkedList) first() ?T { +pub fn (list DoublyLinkedList[T]) first() ?T { if list.is_empty() { return error('Linked list is empty') } @@ -38,7 +38,7 @@ pub fn (list DoublyLinkedList) first() ?T { } // last returns the last element of the linked list -pub fn (list DoublyLinkedList) last() ?T { +pub fn (list DoublyLinkedList[T]) last() ?T { if list.is_empty() { return error('Linked list is empty') } @@ -46,8 +46,8 @@ pub fn (list DoublyLinkedList) last() ?T { } // push_back adds an element to the end of the linked list -pub fn (mut list DoublyLinkedList) push_back(item T) { - mut new_node := &DoublyListNode{ +pub fn (mut list DoublyLinkedList[T]) push_back(item T) { + mut new_node := &DoublyListNode[T]{ data: item } if list.is_empty() { @@ -63,8 +63,8 @@ pub fn (mut list DoublyLinkedList) push_back(item T) { } // push_front adds an element to the beginning of the linked list -pub fn (mut list DoublyLinkedList) push_front(item T) { - mut new_node := &DoublyListNode{ +pub fn (mut list DoublyLinkedList[T]) push_front(item T) { + mut new_node := &DoublyListNode[T]{ data: item } if list.is_empty() { @@ -80,7 +80,7 @@ pub fn (mut list DoublyLinkedList) push_front(item T) { } // pop_back removes the last element of the linked list -pub fn (mut list DoublyLinkedList) pop_back() ?T { +pub fn (mut list DoublyLinkedList[T]) pop_back() ?T { if list.is_empty() { return error('Linked list is empty') } @@ -101,7 +101,7 @@ pub fn (mut list DoublyLinkedList) pop_back() ?T { } // pop_front removes the last element of the linked list -pub fn (mut list DoublyLinkedList) pop_front() ?T { +pub fn (mut list DoublyLinkedList[T]) pop_front() ?T { if list.is_empty() { return error('Linked list is empty') } @@ -122,7 +122,7 @@ pub fn (mut list DoublyLinkedList) pop_front() ?T { } // insert adds an element to the linked list at the given index -pub fn (mut list DoublyLinkedList) insert(idx int, item T) ? { +pub fn (mut list DoublyLinkedList[T]) insert(idx int, item T) ? { if idx < 0 || idx > list.len { return error('Index ${idx} out of bounds [0..${list.len}]') } else if idx == 0 { @@ -142,7 +142,7 @@ pub fn (mut list DoublyLinkedList) insert(idx int, item T) ? { // (determined from the forward index). This function should be called // when idx > list.len/2. This helper function assumes idx bounds have // already been checked and idx is not at the edges. -fn (mut list DoublyLinkedList) insert_back(idx int, item T) { +fn (mut list DoublyLinkedList[T]) insert_back(idx int, item T) { mut node := list.node(idx + 1) mut prev := node.prev // prev node @@ -150,7 +150,7 @@ fn (mut list DoublyLinkedList) insert_back(idx int, item T) { // |next|---->|next| // |prev|<----|prev| // ------ ------ - new := &DoublyListNode{ + new := &DoublyListNode[T]{ data: item next: node prev: prev @@ -169,7 +169,7 @@ fn (mut list DoublyLinkedList) insert_back(idx int, item T) { // (determined from the forward index). This function should be called // when idx <= list.len/2. This helper function assumes idx bounds have // already been checked and idx is not at the edges. -fn (mut list DoublyLinkedList) insert_front(idx int, item T) { +fn (mut list DoublyLinkedList[T]) insert_front(idx int, item T) { mut node := list.node(idx - 1) mut next := node.next // node next @@ -177,7 +177,7 @@ fn (mut list DoublyLinkedList) insert_front(idx int, item T) { // |next|---->|next| // |prev|<----|prev| // ------ ------ - new := &DoublyListNode{ + new := &DoublyListNode[T]{ data: item next: next prev: node @@ -195,7 +195,7 @@ fn (mut list DoublyLinkedList) insert_front(idx int, item T) { // node walks from the head or tail and finds the node at index idx. // This helper function assumes the list is not empty and idx is in // bounds. -fn (list &DoublyLinkedList) node(idx int) &DoublyListNode { +fn (list &DoublyLinkedList[T]) node(idx int) &DoublyListNode[T] { if idx <= list.len / 2 { mut node := list.head for h := 0; h < idx; h += 1 { @@ -212,7 +212,7 @@ fn (list &DoublyLinkedList) node(idx int) &DoublyListNode { // index searches the linked list for item and returns the forward index // or none if not found. -pub fn (list &DoublyLinkedList) index(item T) ?int { +pub fn (list &DoublyLinkedList[T]) index(item T) ?int { mut hn := list.head mut tn := list.tail for h, t := 0, list.len - 1; h <= t; { @@ -231,7 +231,7 @@ pub fn (list &DoublyLinkedList) index(item T) ?int { // delete removes index idx from the linked list and is safe to call // for any idx. -pub fn (mut list DoublyLinkedList) delete(idx int) { +pub fn (mut list DoublyLinkedList[T]) delete(idx int) { if idx < 0 || idx >= list.len { return } else if idx == 0 { @@ -249,12 +249,12 @@ pub fn (mut list DoublyLinkedList) delete(idx int) { } // str returns a string representation of the linked list -pub fn (list DoublyLinkedList) str() string { +pub fn (list DoublyLinkedList[T]) str() string { return list.array().str() } // array returns a array representation of the linked list -pub fn (list DoublyLinkedList) array() []T { +pub fn (list DoublyLinkedList[T]) array() []T { mut result_array := []T{cap: list.len} mut node := list.head for unsafe { node != 0 } { @@ -266,10 +266,10 @@ pub fn (list DoublyLinkedList) array() []T { // next implements the iter interface to use DoublyLinkedList with // V's `for x in list {` loop syntax. -pub fn (mut list DoublyLinkedList) next() ?T { +pub fn (mut list DoublyLinkedList[T]) next() ?T { if list.iter == unsafe { nil } { // initialize new iter object - list.iter = &DoublyListIter{ + list.iter = &DoublyListIter[T]{ node: list.head } return list.next() @@ -285,15 +285,15 @@ pub fn (mut list DoublyLinkedList) next() ?T { } // iterator returns a new iterator instance for the `list`. -pub fn (mut list DoublyLinkedList) iterator() DoublyListIter { - return DoublyListIter{ +pub fn (mut list DoublyLinkedList[T]) iterator() DoublyListIter[T] { + return DoublyListIter[T]{ node: list.head } } // back_iterator returns a new backwards iterator instance for the `list`. -pub fn (mut list DoublyLinkedList) back_iterator() DoublyListIterBack { - return DoublyListIterBack{ +pub fn (mut list DoublyLinkedList[T]) back_iterator() DoublyListIterBack[T] { + return DoublyListIterBack[T]{ node: list.tail } } @@ -303,14 +303,14 @@ pub fn (mut list DoublyLinkedList) back_iterator() DoublyListIterBack { // It can be used with V's `for x in iter {` construct. // One list can have multiple independent iterators, pointing to different positions/places in the list. // A DoublyListIter iterator instance always traverses the list from *start to finish*. -pub struct DoublyListIter { +pub struct DoublyListIter[T] { mut: - node &DoublyListNode = unsafe { 0 } + node &DoublyListNode[T] = unsafe { 0 } } // next returns *the next* element of the list, or `none` when the end of the list is reached. // It is called by V's `for x in iter{` on each iteration. -pub fn (mut iter DoublyListIter) next() ?T { +pub fn (mut iter DoublyListIter[T]) next() ?T { if iter.node == unsafe { nil } { return none } @@ -324,14 +324,14 @@ pub fn (mut iter DoublyListIter) next() ?T { // It can be used with V's `for x in iter {` construct. // One list can have multiple independent iterators, pointing to different positions/places in the list. // A DoublyListIterBack iterator instance always traverses the list from *finish to start*. -pub struct DoublyListIterBack { +pub struct DoublyListIterBack[T] { mut: - node &DoublyListNode = unsafe { 0 } + node &DoublyListNode[T] = unsafe { 0 } } // next returns *the previous* element of the list, or `none` when the start of the list is reached. // It is called by V's `for x in iter{` on each iteration. -pub fn (mut iter DoublyListIterBack) next() ?T { +pub fn (mut iter DoublyListIterBack[T]) next() ?T { if iter.node == unsafe { nil } { return none } diff --git a/vlib/datatypes/doubly_linked_list_test.v b/vlib/datatypes/doubly_linked_list_test.v index 07cbcc1180..ca2e7d0727 100644 --- a/vlib/datatypes/doubly_linked_list_test.v +++ b/vlib/datatypes/doubly_linked_list_test.v @@ -1,14 +1,14 @@ module datatypes fn test_is_empty() { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} assert list.is_empty() == true list.push_back(1) assert list.is_empty() == false } fn test_len() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} assert list.len() == 0 list.push_back(1) assert list.len() == 1 @@ -17,29 +17,29 @@ fn test_len() ? { } fn test_first() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) assert list.first()? == 1 list.push_back(2) assert list.first()? == 1 - list = DoublyLinkedList{} + list = DoublyLinkedList[int]{} list.first() or { return } assert false } fn test_last() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) assert list.last()? == 1 list.push_back(2) assert list.last()? == 2 - list = DoublyLinkedList{} + list = DoublyLinkedList[int]{} list.last() or { return } assert false } fn test_push() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) assert list.last()? == 1 list.push_back(2) @@ -49,7 +49,7 @@ fn test_push() ? { } fn test_pop() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -57,13 +57,13 @@ fn test_pop() ? { list.push_back(4) assert list.pop_back()? == 4 assert list.pop_back()? == 2 - list = DoublyLinkedList{} + list = DoublyLinkedList[int]{} list.pop_back() or { return } assert false } fn test_pop_front() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -71,13 +71,13 @@ fn test_pop_front() ? { list.push_back(4) assert list.pop_front()? == 2 assert list.pop_front()? == 3 - list = DoublyLinkedList{} + list = DoublyLinkedList[int]{} list.pop_front() or { return } assert false } fn test_insert() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -93,7 +93,7 @@ fn test_insert() ? { } fn test_push_front() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -102,7 +102,7 @@ fn test_push_front() ? { } fn test_delete() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(0) list.push_back(1) list.push_back(2) @@ -119,7 +119,7 @@ fn test_delete() ? { } fn test_iter() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} for i := 0; i < 10; i++ { list.push_back(i * 10) } @@ -141,7 +141,7 @@ fn test_iter() ? { } fn test_index() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} for i := 0; i < 10; i++ { list.push_back(i * 10) } @@ -152,7 +152,7 @@ fn test_index() ? { } fn test_str() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -160,7 +160,7 @@ fn test_str() ? { } fn test_array() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -168,7 +168,7 @@ fn test_array() ? { } fn test_string_array() ? { - mut list := DoublyLinkedList<[]string>{} + mut list := DoublyLinkedList[[]string]{} list.push_back(['a']) list.push_back(['b']) list.push_back(['c']) @@ -176,7 +176,7 @@ fn test_string_array() ? { } fn test_iteration_with_for() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -188,7 +188,7 @@ fn test_iteration_with_for() ? { } fn test_iterator() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) @@ -201,7 +201,7 @@ fn test_iterator() ? { } fn test_back_iterator() ? { - mut list := DoublyLinkedList{} + mut list := DoublyLinkedList[int]{} list.push_back(1) list.push_back(2) list.push_back(3) diff --git a/vlib/datatypes/heap.v b/vlib/datatypes/heap.v index 3c73123d5e..a1ba8e88e8 100644 --- a/vlib/datatypes/heap.v +++ b/vlib/datatypes/heap.v @@ -1,13 +1,13 @@ module datatypes // MinHeap is a binary minimum heap data structure. -pub struct MinHeap { +pub struct MinHeap[T] { mut: data []T } // insert adds an element to the heap. -pub fn (mut heap MinHeap) insert(item T) { +pub fn (mut heap MinHeap[T]) insert(item T) { // push item to the end of the array heap.data << item // swap the new node with its parent until the heap is in order @@ -21,7 +21,7 @@ pub fn (mut heap MinHeap) insert(item T) { } // pop removes the top-most element from the heap. -pub fn (mut heap MinHeap) pop() ?T { +pub fn (mut heap MinHeap[T]) pop() ?T { if heap.data.len == 0 { return none } else if heap.data.len == 1 { @@ -46,7 +46,7 @@ pub fn (mut heap MinHeap) pop() ?T { } // peek gets the top-most element from the heap without removing it. -pub fn (heap MinHeap) peek() ?T { +pub fn (heap MinHeap[T]) peek() ?T { if heap.data.len == 0 { return none } @@ -54,13 +54,13 @@ pub fn (heap MinHeap) peek() ?T { } // len returns the number of elements in the heap. -pub fn (heap MinHeap) len() int { +pub fn (heap MinHeap[T]) len() int { return heap.data.len } // left_child is a helper function that returns the index of the left // child given a parent idx, or none if there is no left child. -fn (heap MinHeap) left_child(idx int) ?int { +fn (heap MinHeap[T]) left_child(idx int) ?int { child := 2 * idx + 1 if child >= heap.data.len { return none @@ -70,7 +70,7 @@ fn (heap MinHeap) left_child(idx int) ?int { // right_child is a helper function that returns the index of the right // child given a parent idx, or none if there is no right child. -fn (heap MinHeap) right_child(idx int) ?int { +fn (heap MinHeap[T]) right_child(idx int) ?int { child := 2 * idx + 2 if child >= heap.data.len { return none @@ -79,6 +79,6 @@ fn (heap MinHeap) right_child(idx int) ?int { } // parent is a helper function that returns the parent index of the child. -fn (heap MinHeap) parent(idx int) int { +fn (heap MinHeap[T]) parent(idx int) int { return (idx - 1) / 2 } diff --git a/vlib/datatypes/heap_test.v b/vlib/datatypes/heap_test.v index e715f2cc6d..8b90ef5a95 100644 --- a/vlib/datatypes/heap_test.v +++ b/vlib/datatypes/heap_test.v @@ -1,7 +1,7 @@ module datatypes fn test_min_heap() ? { - mut heap := MinHeap{} + mut heap := MinHeap[int]{} heap.insert(2) heap.insert(0) heap.insert(8) @@ -28,7 +28,7 @@ fn (lhs Item) < (rhs Item) bool { } fn test_min_heap_custom() ? { - mut heap := MinHeap{} + mut heap := MinHeap[Item]{} heap.insert(Item{'buz', 10}) heap.insert(Item{'qux', 0}) heap.insert(Item{'baz', 50}) @@ -46,7 +46,7 @@ fn test_min_heap_custom() ? { } fn test_heap_len() ? { - mut heap := MinHeap{} + mut heap := MinHeap[int]{} heap.insert(2) assert heap.len() == 1 heap.insert(0) diff --git a/vlib/datatypes/linked_list.v b/vlib/datatypes/linked_list.v index c888e9c453..c4c5318c34 100644 --- a/vlib/datatypes/linked_list.v +++ b/vlib/datatypes/linked_list.v @@ -1,38 +1,38 @@ module datatypes -pub struct ListNode { +pub struct ListNode[T] { mut: data T - next &ListNode = unsafe { 0 } + next &ListNode[T] = unsafe { 0 } } -pub struct LinkedList { +pub struct LinkedList[T] { mut: - head &ListNode = unsafe { 0 } + head &ListNode[T] = unsafe { 0 } len int // Internal iter pointer for allowing safe modification // of the list while iterating. TODO: use an option // instead of a pointer to determine if it is initialized. - iter &ListIter = unsafe { 0 } + iter &ListIter[T] = unsafe { 0 } } // is_empty checks if the linked list is empty -pub fn (list LinkedList) is_empty() bool { +pub fn (list LinkedList[T]) is_empty() bool { return list.len == 0 } // len returns the length of the linked list -pub fn (list LinkedList) len() int { +pub fn (list LinkedList[T]) len() int { return list.len } // first returns the first element of the linked list -pub fn (list LinkedList) first() ?T { +pub fn (list LinkedList[T]) first() ?T { return if !list.is_empty() { list.head.data } else { error('Linked list is empty') } } // last returns the last element of the linked list -pub fn (list LinkedList) last() ?T { +pub fn (list LinkedList[T]) last() ?T { if unsafe { list.head == 0 } { return error('Linked list is empty') } else { @@ -45,7 +45,7 @@ pub fn (list LinkedList) last() ?T { } // index returns the element at the given index of the linked list -pub fn (list LinkedList) index(idx int) ?T { +pub fn (list LinkedList[T]) index(idx int) ?T { if unsafe { list.head == 0 } { return error('Linked list is empty') } else { @@ -64,8 +64,8 @@ pub fn (list LinkedList) index(idx int) ?T { } // push adds an element to the end of the linked list -pub fn (mut list LinkedList) push(item T) { - new_node := &ListNode{ +pub fn (mut list LinkedList[T]) push(item T) { + new_node := &ListNode[T]{ data: item } if unsafe { list.head == 0 } { @@ -82,7 +82,7 @@ pub fn (mut list LinkedList) push(item T) { } // pop removes the last element of the linked list -pub fn (mut list LinkedList) pop() ?T { +pub fn (mut list LinkedList[T]) pop() ?T { if unsafe { list.head == 0 } { return error('Linked list is empty') } @@ -105,7 +105,7 @@ pub fn (mut list LinkedList) pop() ?T { } // shift removes the first element of the linked list -pub fn (mut list LinkedList) shift() ?T { +pub fn (mut list LinkedList[T]) shift() ?T { if unsafe { list.head == 0 } { return error('Linked list is empty') } else { @@ -117,7 +117,7 @@ pub fn (mut list LinkedList) shift() ?T { } // insert adds an element to the linked list at the given index -pub fn (mut list LinkedList) insert(idx int, item T) ? { +pub fn (mut list LinkedList[T]) insert(idx int, item T) ? { if idx < 0 || idx > list.len { return error('Index ${idx} out of bounds [0..${list.len}]') } else if list.len == 0 { @@ -128,7 +128,7 @@ pub fn (mut list LinkedList) insert(idx int, item T) ? { if idx == 0 { // first node case - list.head = &ListNode{ + list.head = &ListNode[T]{ data: item next: node } @@ -136,7 +136,7 @@ pub fn (mut list LinkedList) insert(idx int, item T) ? { for i := 0; i < idx - 1; i++ { node = node.next } - node.next = &ListNode{ + node.next = &ListNode[T]{ data: item next: node.next } @@ -145,17 +145,17 @@ pub fn (mut list LinkedList) insert(idx int, item T) ? { } // prepend adds an element to the beginning of the linked list (equivalent to insert(0, item)) -pub fn (mut list LinkedList) prepend(item T) { +pub fn (mut list LinkedList[T]) prepend(item T) { list.insert(0, item) or {} } // str returns a string representation of the linked list -pub fn (list LinkedList) str() string { +pub fn (list LinkedList[T]) str() string { return list.array().str() } // array returns a array representation of the linked list -pub fn (list LinkedList) array() []T { +pub fn (list LinkedList[T]) array() []T { mut result_array := []T{cap: list.len} mut node := list.head for unsafe { node != 0 } { @@ -167,10 +167,10 @@ pub fn (list LinkedList) array() []T { // next implements the iteration interface to use LinkedList // with V's `for` loop syntax. -pub fn (mut list LinkedList) next() ?T { +pub fn (mut list LinkedList[T]) next() ?T { if list.iter == unsafe { nil } { // initialize new iter object - list.iter = &ListIter{ + list.iter = &ListIter[T]{ node: list.head } return list.next() @@ -186,8 +186,8 @@ pub fn (mut list LinkedList) next() ?T { } // iterator returns a new iterator instance for the `list`. -pub fn (mut list LinkedList) iterator() ListIter { - return ListIter{ +pub fn (mut list LinkedList[T]) iterator() ListIter[T] { + return ListIter[T]{ node: list.head } } @@ -196,14 +196,14 @@ pub fn (mut list LinkedList) iterator() ListIter { // It can be used with V's `for x in iter {` construct. // One list can have multiple independent iterators, pointing to different positions/places in the list. // An iterator instance always traverses the list from start to finish. -pub struct ListIter { +pub struct ListIter[T] { mut: - node &ListNode = unsafe { 0 } + node &ListNode[T] = unsafe { 0 } } // next returns the next element of the list, or `none` when the end of the list is reached. // It is called by V's `for x in iter{` on each iteration. -pub fn (mut iter ListIter) next() ?T { +pub fn (mut iter ListIter[T]) next() ?T { if iter.node == unsafe { nil } { return none } diff --git a/vlib/datatypes/linked_list_test.v b/vlib/datatypes/linked_list_test.v index 8bf1e07445..70ca6f1004 100644 --- a/vlib/datatypes/linked_list_test.v +++ b/vlib/datatypes/linked_list_test.v @@ -1,14 +1,14 @@ module datatypes fn test_is_empty() { - mut list := LinkedList{} + mut list := LinkedList[int]{} assert list.is_empty() == true list.push(1) assert list.is_empty() == false } fn test_len() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} assert list.len() == 0 list.push(1) assert list.len() == 1 @@ -17,29 +17,29 @@ fn test_len() ? { } fn test_first() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) assert list.first()? == 1 list.push(2) assert list.first()? == 1 - list = LinkedList{} + list = LinkedList[int]{} list.first() or { return } assert false } fn test_last() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) assert list.last()? == 1 list.push(2) assert list.last()? == 2 - list = LinkedList{} + list = LinkedList[int]{} list.last() or { return } assert false } fn test_index() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) assert list.index(0)? == 1 list.push(2) @@ -50,7 +50,7 @@ fn test_index() ? { } fn test_push() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) assert list.last()? == 1 list.push(2) @@ -60,7 +60,7 @@ fn test_push() ? { } fn test_pop() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -68,13 +68,13 @@ fn test_pop() ? { list.push(4) assert list.pop()? == 4 assert list.pop()? == 2 - list = LinkedList{} + list = LinkedList[int]{} list.pop() or { return } assert false } fn test_shift() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -82,13 +82,13 @@ fn test_shift() ? { list.push(4) assert list.shift()? == 2 assert list.shift()? == 3 - list = LinkedList{} + list = LinkedList[int]{} list.shift() or { return } assert false } fn test_insert() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -97,7 +97,7 @@ fn test_insert() ? { } fn test_prepend() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -106,7 +106,7 @@ fn test_prepend() ? { } fn test_str() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -114,7 +114,7 @@ fn test_str() ? { } fn test_array() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -122,7 +122,7 @@ fn test_array() ? { } fn test_linked_list_iterating_with_for() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) @@ -134,7 +134,7 @@ fn test_linked_list_iterating_with_for() ? { } fn test_linked_list_separate_iterators() ? { - mut list := LinkedList{} + mut list := LinkedList[int]{} list.push(1) list.push(2) list.push(3) diff --git a/vlib/datatypes/queue.v b/vlib/datatypes/queue.v index 95b912f386..e18fcb9f2e 100644 --- a/vlib/datatypes/queue.v +++ b/vlib/datatypes/queue.v @@ -1,51 +1,51 @@ module datatypes -pub struct Queue { +pub struct Queue[T] { mut: - elements LinkedList + elements LinkedList[T] } // is_empty checks if the queue is empty -pub fn (queue Queue) is_empty() bool { +pub fn (queue Queue[T]) is_empty() bool { return queue.elements.is_empty() } // len returns the length of the queue -pub fn (queue Queue) len() int { +pub fn (queue Queue[T]) len() int { return queue.elements.len() } // peek returns the head of the queue (first element added) -pub fn (queue Queue) peek() ?T { +pub fn (queue Queue[T]) peek() ?T { return queue.elements.first() } // last returns the tail of the queue (last element added) -pub fn (queue Queue) last() ?T { +pub fn (queue Queue[T]) last() ?T { return queue.elements.last() } // index returns the element at the given index of the queue -pub fn (queue Queue) index(idx int) ?T { +pub fn (queue Queue[T]) index(idx int) ?T { return queue.elements.index(idx) } // push adds an element to the tail of the queue -pub fn (mut queue Queue) push(item T) { +pub fn (mut queue Queue[T]) push(item T) { queue.elements.push(item) } // pop removes the element at the head of the queue and returns it -pub fn (mut queue Queue) pop() ?T { +pub fn (mut queue Queue[T]) pop() ?T { return queue.elements.shift() } // str returns a string representation of the queue -pub fn (queue Queue) str() string { +pub fn (queue Queue[T]) str() string { return queue.elements.str() } // array returns a array representation of the queue -pub fn (queue Queue) array() []T { +pub fn (queue Queue[T]) array() []T { return queue.elements.array() } diff --git a/vlib/datatypes/queue_test.v b/vlib/datatypes/queue_test.v index e3544b4053..548d563a33 100644 --- a/vlib/datatypes/queue_test.v +++ b/vlib/datatypes/queue_test.v @@ -1,14 +1,14 @@ module datatypes fn test_is_empty() { - mut queue := Queue{} + mut queue := Queue[int]{} assert queue.is_empty() == true queue.push(1) assert queue.is_empty() == false } fn test_len() ? { - mut queue := Queue{} + mut queue := Queue[int]{} assert queue.len() == 0 queue.push(1) assert queue.len() == 1 @@ -17,29 +17,29 @@ fn test_len() ? { } fn test_peek() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) assert queue.peek()? == 1 queue.push(2) assert queue.peek()? == 1 - queue = Queue{} + queue = Queue[int]{} queue.peek() or { return } assert false } fn test_last() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) assert queue.last()? == 1 queue.push(2) assert queue.last()? == 2 - queue = Queue{} + queue = Queue[int]{} queue.last() or { return } assert false } fn test_index() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) assert queue.index(0)? == 1 queue.push(2) @@ -50,14 +50,14 @@ fn test_index() ? { } fn test_push() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) queue.push(2) assert queue.peek()? == 1 } fn test_pop() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) queue.push(2) queue.push(3) @@ -65,13 +65,13 @@ fn test_pop() ? { queue.push(4) assert queue.pop()? == 2 assert queue.pop()? == 3 - queue = Queue{} + queue = Queue[int]{} queue.pop() or { return } assert false } fn test_array() ? { - mut queue := Queue{} + mut queue := Queue[int]{} queue.push(1) queue.push(2) assert queue.array() == [1, 2] diff --git a/vlib/datatypes/ringbuffer.v b/vlib/datatypes/ringbuffer.v index 3e608d80de..34216f6484 100644 --- a/vlib/datatypes/ringbuffer.v +++ b/vlib/datatypes/ringbuffer.v @@ -3,7 +3,7 @@ module datatypes // RingBuffer - public struct that represents the ringbuffer -pub struct RingBuffer { +pub struct RingBuffer[T] { mut: reader int // index of the tail where data is going to be read writer int // index of the head where data is going to be written @@ -11,14 +11,14 @@ mut: } // new_ringbuffer - creates an empty ringbuffer -pub fn new_ringbuffer(s int) RingBuffer { - return RingBuffer{ +pub fn new_ringbuffer[T](s int) RingBuffer[T] { + return RingBuffer[T]{ content: []T{len: s + 1, cap: s + 1} } // increasing custom set size by one element in order to make ring flow possible, so that writer cannot equal reader before reader-index has been read. } // push - adds an element to the ringbuffer -pub fn (mut rb RingBuffer) push(element T) ? { +pub fn (mut rb RingBuffer[T]) push(element T) ? { if rb.is_full() { return error('Buffer overflow') } else { @@ -28,7 +28,7 @@ pub fn (mut rb RingBuffer) push(element T) ? { } // pop - returns the oldest element of the buffer -pub fn (mut rb RingBuffer) pop() ?T { +pub fn (mut rb RingBuffer[T]) pop() ?T { mut v := rb.content[rb.reader] if rb.is_empty() { return error('Buffer is empty') @@ -39,14 +39,14 @@ pub fn (mut rb RingBuffer) pop() ?T { } // push_many - pushes an array to the buffer -pub fn (mut rb RingBuffer) push_many(elements []T) ? { +pub fn (mut rb RingBuffer[T]) push_many(elements []T) ? { for v in elements { rb.push(v) or { return err } } } // pop_many - returns a given number(n) of elements of the buffer starting with the oldest one -pub fn (mut rb RingBuffer) pop_many(n u64) ?[]T { +pub fn (mut rb RingBuffer[T]) pop_many(n u64) ?[]T { mut elements := []T{} for _ in 0 .. n { elements << rb.pop() or { return err } @@ -55,12 +55,12 @@ pub fn (mut rb RingBuffer) pop_many(n u64) ?[]T { } // is_empty - checks if the ringbuffer is empty -pub fn (rb RingBuffer) is_empty() bool { +pub fn (rb RingBuffer[T]) is_empty() bool { return rb.reader == rb.writer // if reader equals writer it means that no value to read has been written before. It follows that the buffer is empty. } // is_full - checks if the ringbuffer is full -pub fn (rb RingBuffer) is_full() bool { +pub fn (rb RingBuffer[T]) is_full() bool { if rb.writer + 1 == rb.reader { return true } else if rb.writer == rb.content.len - 1 && rb.reader == 0 { @@ -71,19 +71,19 @@ pub fn (rb RingBuffer) is_full() bool { } // capacity - returns the capacity of the ringbuffer -pub fn (rb RingBuffer) capacity() int { +pub fn (rb RingBuffer[T]) capacity() int { return rb.content.cap - 1 // reduce by one because of the extra element explained in function `new_ringbuffer()` } // clear - emptys the ringbuffer and all pushed elements -pub fn (mut rb RingBuffer) clear() { - rb = RingBuffer{ +pub fn (mut rb RingBuffer[T]) clear() { + rb = RingBuffer[T]{ content: []T{len: rb.content.len, cap: rb.content.cap} } } // occupied - returns occupied capacity of the buffer. -pub fn (rb RingBuffer) occupied() int { +pub fn (rb RingBuffer[T]) occupied() int { mut reader := rb.reader mut v := 0 if rb.is_empty() { @@ -103,20 +103,20 @@ pub fn (rb RingBuffer) occupied() int { } // remaining - returns remaining capacity of the buffer -pub fn (rb RingBuffer) remaining() int { +pub fn (rb RingBuffer[T]) remaining() int { return rb.capacity() - rb.occupied() } // head an tail-pointer move methods // these methods are not public, they are just an eneasement for handling the pointer-movement process. -fn (mut rb RingBuffer) move_reader() { +fn (mut rb RingBuffer[T]) move_reader() { rb.reader++ if rb.reader > rb.content.len - 1 { rb.reader = 0 } } -fn (mut rb RingBuffer) move_writer() { +fn (mut rb RingBuffer[T]) move_writer() { rb.writer++ if rb.writer > rb.content.len - 1 { rb.writer = 0 diff --git a/vlib/datatypes/ringbuffer_test.v b/vlib/datatypes/ringbuffer_test.v index 8607d0f050..d485e87c37 100644 --- a/vlib/datatypes/ringbuffer_test.v +++ b/vlib/datatypes/ringbuffer_test.v @@ -1,7 +1,7 @@ import datatypes fn test_push_and_pop() { - mut r := datatypes.new_ringbuffer(2) + mut r := datatypes.new_ringbuffer[int](2) r.push(3) or { panic(err) } r.push(4) or { panic(err) } @@ -18,7 +18,7 @@ fn test_push_and_pop() { } fn test_clear_and_empty() { - mut r := datatypes.new_ringbuffer(4) + mut r := datatypes.new_ringbuffer[int](4) r.push(3) or { panic(err) } r.push(4) or { panic(err) } @@ -31,7 +31,7 @@ fn test_clear_and_empty() { } fn test_capacity_and_is_full() { - mut r := datatypes.new_ringbuffer(4) + mut r := datatypes.new_ringbuffer[int](4) assert r.capacity() == 4 @@ -44,7 +44,7 @@ fn test_capacity_and_is_full() { } fn test_occupied_and_remaining() { - mut r := datatypes.new_ringbuffer(4) + mut r := datatypes.new_ringbuffer[int](4) r.push(3) or { panic(err) } r.push(4) or { panic(err) } @@ -53,7 +53,7 @@ fn test_occupied_and_remaining() { } fn test_push_and_pop_many() { - mut r := datatypes.new_ringbuffer(4) + mut r := datatypes.new_ringbuffer[int](4) a := [1, 2, 3, 4] r.push_many(a) or { panic(err) } diff --git a/vlib/datatypes/set.v b/vlib/datatypes/set.v index fecf4c799e..5c8f39824a 100644 --- a/vlib/datatypes/set.v +++ b/vlib/datatypes/set.v @@ -1,27 +1,27 @@ module datatypes -pub struct Set { +pub struct Set[T] { mut: elements map[T]u8 } // checks the element is exists. -pub fn (set Set) exists(element T) bool { +pub fn (set Set[T]) exists(element T) bool { return element in set.elements } // adds the element to set, if it is not present already. -pub fn (mut set Set) add(element T) { +pub fn (mut set Set[T]) add(element T) { set.elements[element] = 1 } // removes the element from set. -pub fn (mut set Set) remove(element T) { +pub fn (mut set Set[T]) remove(element T) { set.elements.delete(element) } // pick returns an arbitrary element of set, if set is not empty. -pub fn (set Set) pick() ?T { +pub fn (set Set[T]) pick() ?T { for k, _ in set.elements { return k } @@ -29,31 +29,31 @@ pub fn (set Set) pick() ?T { } // rest returns the set consisting of all elements except for the arbitrary element. -pub fn (mut set Set) rest() ?[]T { +pub fn (mut set Set[T]) rest() ?[]T { element := set.pick()? return set.elements.keys().filter(it != element) } // pop returns an arbitrary element and deleting it from set. -pub fn (mut set Set) pop() ?T { +pub fn (mut set Set[T]) pop() ?T { element := set.pick()? set.elements.delete(element) return element } // delete all elements of set. -pub fn (mut set Set) clear() { +pub fn (mut set Set[T]) clear() { set.elements = map[T]u8{} } // equal checks whether the two given sets are equal (i.e. contain all and only the same elements). [deprecated: 'use set1 == set2 instead'] -pub fn (l Set) equal(r Set) bool { +pub fn (l Set[T]) equal(r Set[T]) bool { return l == r } // == checks whether the two given sets are equal (i.e. contain all and only the same elements). -pub fn (l Set) == (r Set) bool { +pub fn (l Set[T]) == (r Set[T]) bool { if l.elements.len != r.elements.len { return false } @@ -66,31 +66,31 @@ pub fn (l Set) == (r Set) bool { } // is_empty checks whether the set is empty or not. -pub fn (set Set) is_empty() bool { +pub fn (set Set[T]) is_empty() bool { return set.size() == 0 } // size returns the number of elements in the set. -pub fn (set Set) size() int { +pub fn (set Set[T]) size() int { return set.elements.len } // copy returns a copy of all the elements in the set. -pub fn (set Set) copy() Set { - return Set{ +pub fn (set Set[T]) copy() Set[T] { + return Set[T]{ elements: set.elements.clone() } } // add_all adds the whole `elements` array to the set -pub fn (mut set Set) add_all(elements []T) { +pub fn (mut set Set[T]) add_all(elements []T) { for element in elements { set.add(element) } } // @union returns the union of the two sets. -pub fn (l Set) @union(r Set) Set { +pub fn (l Set[T]) @union(r Set[T]) Set[T] { mut set := l for e, _ in r.elements { set.add(e) @@ -99,7 +99,7 @@ pub fn (l Set) @union(r Set) Set { } // intersection returns the intersection of sets. -pub fn (l Set) intersection(r Set) Set { +pub fn (l Set[T]) intersection(r Set[T]) Set[T] { mut set := l for e, _ in l.elements { if !r.exists(e) { @@ -116,12 +116,12 @@ pub fn (l Set) intersection(r Set) Set { // difference returns the difference of sets. [deprecated: 'use set1 - set2 instead'] -pub fn (l Set) difference(r Set) Set { +pub fn (l Set[T]) difference(r Set[T]) Set[T] { return l - r } // - returns the difference of sets. -pub fn (l Set) - (r Set) Set { +pub fn (l Set[T]) - (r Set[T]) Set[T] { mut set := l for e, _ in l.elements { if r.exists(e) { @@ -132,7 +132,7 @@ pub fn (l Set) - (r Set) Set { } // subset returns true if the set `r` is a subset of the set `l`. -pub fn (l Set) subset(r Set) bool { +pub fn (l Set[T]) subset(r Set[T]) bool { for e, _ in r.elements { if e !in l.elements { return false diff --git a/vlib/datatypes/set_test.v b/vlib/datatypes/set_test.v index 97e0e9ce7c..36a680d6e7 100644 --- a/vlib/datatypes/set_test.v +++ b/vlib/datatypes/set_test.v @@ -1,14 +1,14 @@ module datatypes fn test_exists() { - mut set := Set{} + mut set := Set[string]{} set.add('foo') assert set.exists('foo') assert set.exists('bar') == false } fn test_remove() { - mut set := Set{} + mut set := Set[string]{} set.remove('foo') set.add('foo') assert set.exists('foo') @@ -17,28 +17,28 @@ fn test_remove() { } fn test_size() { - mut set := Set{} + mut set := Set[string]{} set.add('foo') set.add('foo') assert set.size() == 1 } fn test_pop() { - mut set := Set{} + mut set := Set[string]{} set.add('foo') set.pop() or { return } assert set.exists('foo') == false } fn test_clear() { - mut set := Set{} + mut set := Set[string]{} set.add('foo') set.clear() assert set.size() == 0 } fn test_rest() { - mut set := Set{} + mut set := Set[string]{} set.add('foo') set.add('bar') array := set.rest() or { return } @@ -46,8 +46,8 @@ fn test_rest() { } fn test_equal() { - mut first_set := Set{} - mut second_set := Set{} + mut first_set := Set[string]{} + mut second_set := Set[string]{} first_set.add('foo') assert second_set != first_set second_set.add('foo') @@ -55,15 +55,15 @@ fn test_equal() { } fn test_is_empty() { - mut set := Set{} + mut set := Set[string]{} assert set.is_empty() set.add('foo') assert set.is_empty() == false } fn test_union() { - mut first_set := Set{} - mut second_set := Set{} + mut first_set := Set[string]{} + mut second_set := Set[string]{} first_set.add_all(['b', 'c', 'd']) second_set.add_all(['a', 'e']) mut third_set := first_set.@union(second_set) @@ -75,9 +75,9 @@ fn test_union() { } fn test_intersection() { - mut first_set := Set{} + mut first_set := Set[string]{} first_set.add_all(['foo', 'bar', 'baz']) - mut second_set := Set{} + mut second_set := Set[string]{} second_set.add_all(['bar', 'baz', 'boo']) mut third_set := first_set.intersection(second_set) assert third_set.exists('foo') == false @@ -87,8 +87,8 @@ fn test_intersection() { } fn test_difference() { - mut first_set := Set{} - mut second_set := Set{} + mut first_set := Set[string]{} + mut second_set := Set[string]{} first_set.add_all(['foo', 'bar', 'baz']) second_set.add_all(['bar', 'baz', 'boo']) mut third_set := first_set - second_set @@ -109,9 +109,9 @@ fn test_difference() { } fn test_subset() { - mut set := Set{} + mut set := Set[string]{} set.add_all(['a', 'b', 'c']) - mut subset := Set{} + mut subset := Set[string]{} subset.add_all(['b', 'c']) assert set.subset(subset) } diff --git a/vlib/datatypes/stack.v b/vlib/datatypes/stack.v index 528a8261f8..a0fc6cba2c 100644 --- a/vlib/datatypes/stack.v +++ b/vlib/datatypes/stack.v @@ -1,41 +1,41 @@ module datatypes -pub struct Stack { +pub struct Stack[T] { mut: elements []T } // is_empty checks if the stack is empty -pub fn (stack Stack) is_empty() bool { +pub fn (stack Stack[T]) is_empty() bool { return stack.elements.len == 0 } // len returns the length of the stack -pub fn (stack Stack) len() int { +pub fn (stack Stack[T]) len() int { return stack.elements.len } // peek returns the top of the stack -pub fn (stack Stack) peek() ?T { +pub fn (stack Stack[T]) peek() ?T { return if !stack.is_empty() { stack.elements.last() } else { error('Stack is empty') } } // push adds an element to the top of the stack -pub fn (mut stack Stack) push(item T) { +pub fn (mut stack Stack[T]) push(item T) { stack.elements << item } // pop removes the element at the top of the stack and returns it -pub fn (mut stack Stack) pop() ?T { +pub fn (mut stack Stack[T]) pop() ?T { return if !stack.is_empty() { stack.elements.pop() } else { error('Stack is empty') } } // str returns a string representation of the stack -pub fn (stack Stack) str() string { +pub fn (stack Stack[T]) str() string { return stack.elements.str() } // array returns a array representation of the stack -pub fn (stack Stack) array() []T { +pub fn (stack Stack[T]) array() []T { return stack.elements } diff --git a/vlib/datatypes/stack_test.v b/vlib/datatypes/stack_test.v index db6df5d874..74040e5dcb 100644 --- a/vlib/datatypes/stack_test.v +++ b/vlib/datatypes/stack_test.v @@ -1,14 +1,14 @@ import datatypes as dt fn test_is_empty() { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} assert stack.is_empty() == true stack.push(1) assert stack.is_empty() == false } fn test_len() ? { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} assert stack.len() == 0 stack.push(1) assert stack.len() == 1 @@ -17,18 +17,18 @@ fn test_len() ? { } fn test_peek() ? { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} stack.push(1) assert stack.peek()? == 1 stack.push(2) assert stack.peek()? == 2 - stack = dt.Stack{} + stack = dt.Stack[int]{} stack.peek() or { return } assert false } fn test_push() ? { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} stack.push(1) assert stack.peek()? == 1 stack.push(2) @@ -38,7 +38,7 @@ fn test_push() ? { } fn test_pop() ? { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} stack.push(1) stack.push(2) stack.push(3) @@ -46,13 +46,13 @@ fn test_pop() ? { stack.push(4) assert stack.pop()? == 4 assert stack.pop()? == 2 - stack = dt.Stack{} + stack = dt.Stack[int]{} stack.pop() or { return } assert false } fn test_array() ? { - mut stack := dt.Stack{} + mut stack := dt.Stack[int]{} stack.push(1) stack.push(2) assert stack.array() == [1, 2] diff --git a/vlib/encoding/csv/reader_test.v b/vlib/encoding/csv/reader_test.v index 11549f429e..7759cb5921 100644 --- a/vlib/encoding/csv/reader_test.v +++ b/vlib/encoding/csv/reader_test.v @@ -290,7 +290,7 @@ mut: fn test_decode_to_struct() { text := 'id,bonus,amount,yes\r\n1,bomb,1,true\r\n2,rocket,1,false,\r\n3,lightning,2,2\r\n' - arr := csv.decode(text) + arr := csv.decode[Test](text) assert arr[0].id == 1 assert arr[0].bonus == 'bomb' assert arr[0].amount == 1 diff --git a/vlib/encoding/csv/to_struct_arr.v b/vlib/encoding/csv/to_struct_arr.v index 2b3cf35444..59c1426218 100644 --- a/vlib/encoding/csv/to_struct_arr.v +++ b/vlib/encoding/csv/to_struct_arr.v @@ -3,7 +3,7 @@ module csv import strconv // decode csv to struct -pub fn decode(data string) []T { +pub fn decode[T](data string) []T { mut result := []T{} if data == '' { return result diff --git a/vlib/hash/fnv1a/fnv1a.v b/vlib/hash/fnv1a/fnv1a.v index e60b199304..1a199a297f 100644 --- a/vlib/hash/fnv1a/fnv1a.v +++ b/vlib/hash/fnv1a/fnv1a.v @@ -33,7 +33,7 @@ pub fn sum32(data []u8) u32 { // sum32_bytes returns a fnv1a hash of the struct `s`. [direct_array_access; inline] -pub fn sum32_struct(s &T) u32 { +pub fn sum32_struct[T](s &T) u32 { bp := unsafe { &u8(s) } sz := int(sizeof(T)) mut hash := fnv1a.fnv32_offset_basis @@ -88,7 +88,7 @@ pub fn sum64_bytes(data &u8, data_len int) u64 { // sum64_bytes returns a fnv1a hash of the struct `s`. [direct_array_access; inline] -pub fn sum64_struct(s &T) u64 { +pub fn sum64_struct[T](s &T) u64 { bp := unsafe { &u8(s) } sz := int(sizeof(T)) mut hash := fnv1a.fnv64_offset_basis diff --git a/vlib/js/js.js.v b/vlib/js/js.js.v index ce557bee00..76cf777c96 100644 --- a/vlib/js/js.js.v +++ b/vlib/js/js.js.v @@ -22,9 +22,9 @@ pub interface JS.Response { clone() JS.Response } -pub fn fetch(input string, init map[string]JS.Any) promise.Promise { +pub fn fetch(input string, init map[string]JS.Any) promise.Promise[JS.Response, JS.String] { p_init := JS.Any(unsafe { nil }) - p := promise.Promise{p_init} + p := promise.Promise[JS.Response, String]{p_init} #let obj = {}; for (let [key,val] of init.map) { obj[key] = val; } #p.promise = fetch(input.str,obj); diff --git a/vlib/json/json_decode_with_generic_test.v b/vlib/json/json_decode_with_generic_test.v index fc7f8221d4..19ac5378c3 100644 --- a/vlib/json/json_decode_with_generic_test.v +++ b/vlib/json/json_decode_with_generic_test.v @@ -1,6 +1,6 @@ import json -struct Result { +struct Result[T] { ok bool result T } @@ -10,14 +10,14 @@ struct User { username string } -fn func() !T { +fn func[T]() !T { text := '{"ok": true, "result":{"id":37467243, "username": "ciao"}}' - a := json.decode(Result, text)! + a := json.decode(Result[T], text)! return a.result } fn test_decode_with_generic_struct() { - ret := func()! + ret := func[User]()! println(ret) assert ret.id == 37467243 assert ret.username == 'ciao' diff --git a/vlib/json/json_test.v b/vlib/json/json_test.v index a308cd576d..8de3f9c289 100644 --- a/vlib/json/json_test.v +++ b/vlib/json/json_test.v @@ -106,7 +106,7 @@ fn test_encode_decode_sumtype() { assert (game.other[4] as time.Time).unix_time() == (dec.other[4] as time.Time).unix_time() } -fn bar(payload string) !Bar { // ?T doesn't work currently +fn bar[T](payload string) !Bar { // ?T doesn't work currently result := json.decode(T, payload)! return result } @@ -116,7 +116,7 @@ struct Bar { } fn test_generic() { - result := bar('{"x":"test"}') or { Bar{} } + result := bar[Bar]('{"x":"test"}') or { Bar{} } assert result.x == 'test' } @@ -332,17 +332,17 @@ fn test_nested_type() { } } -struct Foo { +struct Foo[T] { pub: name string data T } fn test_generic_struct() { - foo_int := Foo{'bar', 12} + foo_int := Foo[int]{'bar', 12} foo_enc := json.encode(foo_int) assert foo_enc == '{"name":"bar","data":12}' - foo_dec := json.decode(Foo, foo_enc)! + foo_dec := json.decode(Foo[int], foo_enc)! assert foo_dec.name == 'bar' assert foo_dec.data == 12 } diff --git a/vlib/maps/maps.v b/vlib/maps/maps.v index e3fea5ebf4..a923fd6ddd 100644 --- a/vlib/maps/maps.v +++ b/vlib/maps/maps.v @@ -1,7 +1,7 @@ module maps // filter filters map entries by the given predicate function -pub fn filter(m map[K]V, f fn (key K, val V) bool) map[K]V { +pub fn filter[K, V](m map[K]V, f fn (key K, val V) bool) map[K]V { mut mp := map[K]V{} for k, v in m { @@ -14,7 +14,7 @@ pub fn filter(m map[K]V, f fn (key K, val V) bool) map[K]V { } // to_array maps map entries into one-dimensional array -pub fn to_array(m map[K]V, f fn (key K, val V) I) []I { +pub fn to_array[K, V, I](m map[K]V, f fn (key K, val V) I) []I { mut a := []I{cap: m.len} for k, v in m { @@ -25,7 +25,7 @@ pub fn to_array(m map[K]V, f fn (key K, val V) I) []I { } // flat_map maps map entries into arrays and flattens into a one-dimensional array -pub fn flat_map(m map[K]V, f fn (key K, val V) []I) []I { +pub fn flat_map[K, V, I](m map[K]V, f fn (key K, val V) []I) []I { mut a := []I{cap: m.len} for k, v in m { @@ -36,7 +36,7 @@ pub fn flat_map(m map[K]V, f fn (key K, val V) []I) []I { } // to_map maps map entries into new entries and constructs a new map -pub fn to_map(m map[K]V, f fn (key K, val V) (X, Y)) map[X]Y { +pub fn to_map[K, V, X, Y](m map[K]V, f fn (key K, val V) (X, Y)) map[X]Y { mut mp := map[X]Y{} for k, v in m { @@ -48,7 +48,7 @@ pub fn to_map(m map[K]V, f fn (key K, val V) (X, Y)) map[X]Y { } // invert returns a new map, created by swapping key to value and vice versa for each entry. -pub fn invert(m map[K]V) map[V]K { +pub fn invert[K, V](m map[K]V) map[V]K { mut mp := map[V]K{} for k, v in m { @@ -59,7 +59,7 @@ pub fn invert(m map[K]V) map[V]K { } // from_array maps array into map with index to element per entry -pub fn from_array(array []T) map[int]T { +pub fn from_array[T](array []T) map[int]T { mut mp := map[int]T{} for i, e in array { diff --git a/vlib/maps/maps_test.v b/vlib/maps/maps_test.v index 90091f2983..88a673a5b5 100644 --- a/vlib/maps/maps_test.v +++ b/vlib/maps/maps_test.v @@ -42,7 +42,7 @@ fn test_flat_map() { 4: [5, 6] 7: [8, 9] } - assert flat_map(m1, fn (k int, v []int) []int { + assert flat_map[int, []int, int](m1, fn (k int, v []int) []int { mut a := [k] a << v return a @@ -58,7 +58,7 @@ fn test_to_map() { 4: '4' 5: '5' } - assert to_map(m1, fn (k int, v string) (string, int) { + assert to_map[int, string, string, int](m1, fn (k int, v string) (string, int) { return v, k }) == { '0': 0 diff --git a/vlib/math/mathutil.v b/vlib/math/mathutil.v index 86c599c251..68e9cd1447 100644 --- a/vlib/math/mathutil.v +++ b/vlib/math/mathutil.v @@ -5,18 +5,18 @@ module math // min returns the minimum of `a` and `b` [inline] -pub fn min(a T, b T) T { +pub fn min[T](a T, b T) T { return if a < b { a } else { b } } // max returns the maximum of `a` and `b` [inline] -pub fn max(a T, b T) T { +pub fn max[T](a T, b T) T { return if a > b { a } else { b } } // abs returns the absolute value of `a` [inline] -pub fn abs(a T) T { +pub fn abs[T](a T) T { return if a < 0 { -a } else { a } } diff --git a/vlib/math/mathutil/mathutil.v b/vlib/math/mathutil/mathutil.v index b96f155a44..1ec4da4a77 100644 --- a/vlib/math/mathutil/mathutil.v +++ b/vlib/math/mathutil/mathutil.v @@ -6,20 +6,20 @@ module mathutil [deprecated: 'use math.min instead'] [deprecated_after: '2022-01-19'] [inline] -pub fn min(a T, b T) T { +pub fn min[T](a T, b T) T { return if a < b { a } else { b } } [deprecated: 'use math.max instead'] [deprecated_after: '2022-01-19'] [inline] -pub fn max(a T, b T) T { +pub fn max[T](a T, b T) T { return if a > b { a } else { b } } [deprecated: 'use math.abs instead'] [deprecated_after: '2022-01-19'] [inline] -pub fn abs(a T) T { +pub fn abs[T](a T) T { return if a > 0 { a } else { -a } } diff --git a/vlib/math/stats/stats.v b/vlib/math/stats/stats.v index 2b19e613d5..b51f1b87ca 100644 --- a/vlib/math/stats/stats.v +++ b/vlib/math/stats/stats.v @@ -6,7 +6,7 @@ import math // Frequency of a given number // Based on // https://www.mathsisfun.com/data/frequency-distribution.html -pub fn freq(data []T, val T) int { +pub fn freq[T](data []T, val T) int { if data.len == 0 { return 0 } @@ -23,7 +23,7 @@ pub fn freq(data []T, val T) int { // of the given input array, sum(data)/data.len // Based on // https://www.mathsisfun.com/data/central-measures.html -pub fn mean(data []T) T { +pub fn mean[T](data []T) T { if data.len == 0 { return T(0) } @@ -38,7 +38,7 @@ pub fn mean(data []T) T { // of the given input array, product(data)**1/data.len // Based on // https://www.mathsisfun.com/numbers/geometric-mean.html -pub fn geometric_mean(data []T) T { +pub fn geometric_mean[T](data []T) T { if data.len == 0 { return T(0) } @@ -53,7 +53,7 @@ pub fn geometric_mean(data []T) T { // of the given input array // Based on // https://www.mathsisfun.com/numbers/harmonic-mean.html -pub fn harmonic_mean(data []T) T { +pub fn harmonic_mean[T](data []T) T { if data.len == 0 { return T(0) } @@ -67,7 +67,7 @@ pub fn harmonic_mean(data []T) T { // median returns the middlemost value of the given input array ( input array is assumed to be sorted ) // Based on // https://www.mathsisfun.com/data/central-measures.html -pub fn median(sorted_data []T) T { +pub fn median[T](sorted_data []T) T { if sorted_data.len == 0 { return T(0) } @@ -82,7 +82,7 @@ pub fn median(sorted_data []T) T { // mode calculates the highest occuring value of the given input array // Based on // https://www.mathsisfun.com/data/central-measures.html -pub fn mode(data []T) T { +pub fn mode[T](data []T) T { if data.len == 0 { return T(0) } @@ -102,7 +102,7 @@ pub fn mode(data []T) T { // rms, Root Mean Square, calculates the sqrt of the mean of the squares of the given input array // Based on // https://en.wikipedia.org/wiki/Root_mean_square -pub fn rms(data []T) T { +pub fn rms[T](data []T) T { if data.len == 0 { return T(0) } @@ -118,19 +118,19 @@ pub fn rms(data []T) T { // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn population_variance(data []T) T { +pub fn population_variance[T](data []T) T { if data.len == 0 { return T(0) } - data_mean := mean(data) - return population_variance_mean(data, data_mean) + data_mean := mean[T](data) + return population_variance_mean[T](data, data_mean) } // population_variance_mean is the Measure of Dispersion / Spread // of the given input array, with the provided mean // Based on // https://www.mathsisfun.com/data/standard-deviation.html -pub fn population_variance_mean(data []T, mean T) T { +pub fn population_variance_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } @@ -145,18 +145,18 @@ pub fn population_variance_mean(data []T, mean T) T { // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn sample_variance(data []T) T { +pub fn sample_variance[T](data []T) T { if data.len == 0 { return T(0) } - data_mean := mean(data) - return sample_variance_mean(data, data_mean) + data_mean := mean[T](data) + return sample_variance_mean[T](data, data_mean) } // sample_variance calculates the spread of dataset around the provided mean // Based on // https://www.mathsisfun.com/data/standard-deviation.html -pub fn sample_variance_mean(data []T, mean T) T { +pub fn sample_variance_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } @@ -171,22 +171,22 @@ pub fn sample_variance_mean(data []T, mean T) T { // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn population_stddev(data []T) T { +pub fn population_stddev[T](data []T) T { if data.len == 0 { return T(0) } - return math.sqrt(population_variance(data)) + return math.sqrt(population_variance[T](data)) } // population_stddev_mean calculates how spread out the dataset is, with the provide mean // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn population_stddev_mean(data []T, mean T) T { +pub fn population_stddev_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } - return T(math.sqrt(f64(population_variance_mean(data, mean)))) + return T(math.sqrt(f64(population_variance_mean[T](data, mean)))) } // Measure of Dispersion / Spread @@ -194,11 +194,11 @@ pub fn population_stddev_mean(data []T, mean T) T { // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn sample_stddev(data []T) T { +pub fn sample_stddev[T](data []T) T { if data.len == 0 { return T(0) } - return T(math.sqrt(f64(sample_variance(data)))) + return T(math.sqrt(f64(sample_variance[T](data)))) } // Measure of Dispersion / Spread @@ -206,29 +206,29 @@ pub fn sample_stddev(data []T) T { // Based on // https://www.mathsisfun.com/data/standard-deviation.html [inline] -pub fn sample_stddev_mean(data []T, mean T) T { +pub fn sample_stddev_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } - return T(math.sqrt(f64(sample_variance_mean(data, mean)))) + return T(math.sqrt(f64(sample_variance_mean[T](data, mean)))) } // absdev calculates the average distance between each data point and the mean // Based on // https://en.wikipedia.org/wiki/Average_absolute_deviation [inline] -pub fn absdev(data []T) T { +pub fn absdev[T](data []T) T { if data.len == 0 { return T(0) } - data_mean := mean(data) - return absdev_mean(data, data_mean) + data_mean := mean[T](data) + return absdev_mean[T](data, data_mean) } // absdev_mean calculates the average distance between each data point and the provided mean // Based on // https://en.wikipedia.org/wiki/Average_absolute_deviation -pub fn absdev_mean(data []T, mean T) T { +pub fn absdev_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } @@ -241,16 +241,16 @@ pub fn absdev_mean(data []T, mean T) T { // tts, Sum of squares, calculates the sum over all squared differences between values and overall mean [inline] -pub fn tss(data []T) T { +pub fn tss[T](data []T) T { if data.len == 0 { return T(0) } - data_mean := mean(data) - return tss_mean(data, data_mean) + data_mean := mean[T](data) + return tss_mean[T](data, data_mean) } // tts_mean, Sum of squares, calculates the sum over all squared differences between values and the provided mean -pub fn tss_mean(data []T, mean T) T { +pub fn tss_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } @@ -262,7 +262,7 @@ pub fn tss_mean(data []T, mean T) T { } // min finds the minimum value from the dataset -pub fn min(data []T) T { +pub fn min[T](data []T) T { if data.len == 0 { return T(0) } @@ -276,7 +276,7 @@ pub fn min(data []T) T { } // max finds the maximum value from the dataset -pub fn max(data []T) T { +pub fn max[T](data []T) T { if data.len == 0 { return T(0) } @@ -290,7 +290,7 @@ pub fn max(data []T) T { } // minmax finds the minimum and maximum value from the dataset -pub fn minmax(data []T) (T, T) { +pub fn minmax[T](data []T) (T, T) { if data.len == 0 { return T(0), T(0) } @@ -308,7 +308,7 @@ pub fn minmax(data []T) (T, T) { } // min_index finds the first index of the minimum value -pub fn min_index(data []T) int { +pub fn min_index[T](data []T) int { if data.len == 0 { return 0 } @@ -324,7 +324,7 @@ pub fn min_index(data []T) int { } // max_index finds the first index of the maximum value -pub fn max_index(data []T) int { +pub fn max_index[T](data []T) int { if data.len == 0 { return 0 } @@ -340,7 +340,7 @@ pub fn max_index(data []T) int { } // minmax_index finds the first index of the minimum and maximum value -pub fn minmax_index(data []T) (int, int) { +pub fn minmax_index[T](data []T) (int, int) { if data.len == 0 { return 0, 0 } @@ -365,26 +365,26 @@ pub fn minmax_index(data []T) (int, int) { // Range ( Maximum - Minimum ) of the given input array // Based on // https://www.mathsisfun.com/data/range.html -pub fn range(data []T) T { +pub fn range[T](data []T) T { if data.len == 0 { return T(0) } - min, max := minmax(data) + min, max := minmax[T](data) return max - min } // covariance calculates directional association between datasets // positive value denotes variables move in same direction and negative denotes variables move in opposite directions [inline] -pub fn covariance(data1 []T, data2 []T) T { - mean1 := mean(data1) - mean2 := mean(data2) - return covariance_mean(data1, data2, mean1, mean2) +pub fn covariance[T](data1 []T, data2 []T) T { + mean1 := mean[T](data1) + mean2 := mean[T](data2) + return covariance_mean[T](data1, data2, mean1, mean2) } // covariance_mean computes the covariance of a dataset with means provided // the recurrence relation -pub fn covariance_mean(data1 []T, data2 []T, mean1 T, mean2 T) T { +pub fn covariance_mean[T](data1 []T, data2 []T, mean1 T, mean2 T) T { n := int(math.min(data1.len, data2.len)) if n == 0 { return T(0) @@ -401,15 +401,15 @@ pub fn covariance_mean(data1 []T, data2 []T, mean1 T, mean2 T) T { // lag1_autocorrelation_mean calculates the correlation between values that are one time period apart // of a dataset, based on the mean [inline] -pub fn lag1_autocorrelation(data []T) T { - data_mean := mean(data) - return lag1_autocorrelation_mean(data, data_mean) +pub fn lag1_autocorrelation[T](data []T) T { + data_mean := mean[T](data) + return lag1_autocorrelation_mean[T](data, data_mean) } // lag1_autocorrelation_mean calculates the correlation between values that are one time period apart // of a dataset, using // the recurrence relation -pub fn lag1_autocorrelation_mean(data []T, mean T) T { +pub fn lag1_autocorrelation_mean[T](data []T, mean T) T { if data.len == 0 { return T(0) } @@ -426,15 +426,15 @@ pub fn lag1_autocorrelation_mean(data []T, mean T) T { // kurtosis calculates the measure of the 'tailedness' of the data by finding mean and standard of deviation [inline] -pub fn kurtosis(data []T) T { - data_mean := mean(data) - sd := population_stddev_mean(data, data_mean) - return kurtosis_mean_stddev(data, data_mean, sd) +pub fn kurtosis[T](data []T) T { + data_mean := mean[T](data) + sd := population_stddev_mean[T](data, data_mean) + return kurtosis_mean_stddev[T](data, data_mean, sd) } // kurtosis_mean_stddev calculates the measure of the 'tailedness' of the data // using the fourth moment the deviations, normalized by the sd -pub fn kurtosis_mean_stddev(data []T, mean T, sd T) T { +pub fn kurtosis_mean_stddev[T](data []T, mean T, sd T) T { mut avg := T(0) // find the fourth moment the deviations, normalized by the sd /* we use a recurrence relation to stably update a running value so @@ -449,14 +449,14 @@ pub fn kurtosis_mean_stddev(data []T, mean T, sd T) T { // skew calculates the mean and standard of deviation to find the skew from the data [inline] -pub fn skew(data []T) T { - data_mean := mean(data) - sd := population_stddev_mean(data, data_mean) - return skew_mean_stddev(data, data_mean, sd) +pub fn skew[T](data []T) T { + data_mean := mean[T](data) + sd := population_stddev_mean[T](data, data_mean) + return skew_mean_stddev[T](data, data_mean, sd) } // skew_mean_stddev calculates the skewness of data -pub fn skew_mean_stddev(data []T, mean T, sd T) T { +pub fn skew_mean_stddev[T](data []T, mean T, sd T) T { mut skew := T(0) // find the sum of the cubed deviations, normalized by the sd. /* we use a recurrence relation to stably update a running value so @@ -469,7 +469,7 @@ pub fn skew_mean_stddev(data []T, mean T, sd T) T { return skew } -pub fn quantile(sorted_data []T, f T) T { +pub fn quantile[T](sorted_data []T, f T) T { if sorted_data.len == 0 { return T(0) } diff --git a/vlib/net/conv/conv_test.v b/vlib/net/conv/conv_test.v index 0ad2560830..a503fd3113 100644 --- a/vlib/net/conv/conv_test.v +++ b/vlib/net/conv/conv_test.v @@ -1,6 +1,6 @@ import net.conv -fn check(f fn (a T) T, finv fn (b T) T, x T) { +fn check[T](f fn (a T) T, finv fn (b T) T, x T) { a := f(x) b := finv(a) assert b == x diff --git a/vlib/os/file.c.v b/vlib/os/file.c.v index b7b789eb17..2bcedf12a7 100644 --- a/vlib/os/file.c.v +++ b/vlib/os/file.c.v @@ -588,7 +588,7 @@ fn error_size_of_type_0() IError { } // read_struct reads a single struct of type `T` -pub fn (mut f File) read_struct(mut t T) ! { +pub fn (mut f File) read_struct[T](mut t T) ! { if !f.is_opened { return error_file_not_opened() } @@ -603,7 +603,7 @@ pub fn (mut f File) read_struct(mut t T) ! { } // read_struct_at reads a single struct of type `T` at position specified in file -pub fn (mut f File) read_struct_at(mut t T, pos u64) ! { +pub fn (mut f File) read_struct_at[T](mut t T, pos u64) ! { if !f.is_opened { return error_file_not_opened() } @@ -634,7 +634,7 @@ pub fn (mut f File) read_struct_at(mut t T, pos u64) ! { } // read_raw reads and returns a single instance of type `T` -pub fn (mut f File) read_raw() !T { +pub fn (mut f File) read_raw[T]() !T { if !f.is_opened { return error_file_not_opened() } @@ -651,7 +651,7 @@ pub fn (mut f File) read_raw() !T { } // read_raw_at reads and returns a single instance of type `T` starting at file byte offset `pos` -pub fn (mut f File) read_raw_at(pos u64) !T { +pub fn (mut f File) read_raw_at[T](pos u64) !T { if !f.is_opened { return error_file_not_opened() } @@ -697,7 +697,7 @@ pub fn (mut f File) read_raw_at(pos u64) !T { } // write_struct writes a single struct of type `T` -pub fn (mut f File) write_struct(t &T) ! { +pub fn (mut f File) write_struct[T](t &T) ! { if !f.is_opened { return error_file_not_opened() } @@ -716,7 +716,7 @@ pub fn (mut f File) write_struct(t &T) ! { } // write_struct_at writes a single struct of type `T` at position specified in file -pub fn (mut f File) write_struct_at(t &T, pos u64) ! { +pub fn (mut f File) write_struct_at[T](t &T, pos u64) ! { if !f.is_opened { return error_file_not_opened() } @@ -753,7 +753,7 @@ pub fn (mut f File) write_struct_at(t &T, pos u64) ! { // TODO `write_raw[_at]` implementations are copy-pasted from `write_struct[_at]` // write_raw writes a single instance of type `T` -pub fn (mut f File) write_raw(t &T) ! { +pub fn (mut f File) write_raw[T](t &T) ! { if !f.is_opened { return error_file_not_opened() } @@ -772,7 +772,7 @@ pub fn (mut f File) write_raw(t &T) ! { } // write_raw_at writes a single instance of type `T` starting at file byte offset `pos` -pub fn (mut f File) write_raw_at(t &T, pos u64) ! { +pub fn (mut f File) write_raw_at[T](t &T, pos u64) ! { if !f.is_opened { return error_file_not_opened() } diff --git a/vlib/os/file_test.v b/vlib/os/file_test.v index f8ec8c1ed8..060466d0ad 100644 --- a/vlib/os/file_test.v +++ b/vlib/os/file_test.v @@ -282,10 +282,10 @@ fn test_read_raw() { f.write_raw(another_permission)! f.close() f = os.open_file(tfile, 'r')! - p := f.read_raw()! - b := f.read_raw()! - c := f.read_raw()! - x := f.read_raw()! + p := f.read_raw[Point]()! + b := f.read_raw[u8]()! + c := f.read_raw[Color]()! + x := f.read_raw[Permissions]()! f.close() assert p == another_point @@ -304,13 +304,13 @@ fn test_read_raw_at() { f.close() f = os.open_file(tfile, 'r')! mut at := u64(3) - p := f.read_raw_at(at)! + p := f.read_raw_at[Point](at)! at += sizeof(Point) - b := f.read_raw_at(at)! + b := f.read_raw_at[u8](at)! at += sizeof(u8) - c := f.read_raw_at(at)! + c := f.read_raw_at[Color](at)! at += sizeof(Color) - x := f.read_raw_at(at)! + x := f.read_raw_at[Permissions](at)! at += sizeof(Permissions) f.close() @@ -322,10 +322,10 @@ fn test_read_raw_at() { fn test_read_raw_at_negative_pos() { mut f := os.open_file(tfile, 'r')! - if _ := f.read_raw_at(-1) { + if _ := f.read_raw_at[Point](-1) { assert false } - f.read_raw_at(-234) or { assert err.msg() == 'Invalid argument' } + f.read_raw_at[Point](-234) or { assert err.msg() == 'Invalid argument' } f.close() } @@ -342,11 +342,11 @@ fn test_seek() { // f.seek(i64(sizeof(Point)), .start)! assert f.tell()! == sizeof(Point) - b := f.read_raw()! + b := f.read_raw[u8]()! assert b == another_byte f.seek(i64(sizeof(Color)), .current)! - x := f.read_raw()! + x := f.read_raw[Permissions]()! assert x == another_permission // f.close() diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 68e66fb3aa..121a69d81a 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -598,7 +598,7 @@ pub fn get_raw_stdin() []u8 { } // read_file_array reads an array of `T` values from file `path`. -pub fn read_file_array(path string) []T { +pub fn read_file_array[T](path string) []T { a := T{} tsize := int(sizeof(a)) // prepare for reading, get current file size diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index 6a90159161..0b3037459b 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -706,7 +706,7 @@ fn test_write_file_array_structs() { arr[i] = IntPoint{65 + i, 65 + i + 10} } os.write_file_array(fpath, arr) or { panic(err) } - rarr := os.read_file_array(fpath) + rarr := os.read_file_array[IntPoint](fpath) assert rarr == arr assert rarr.len == maxn // eprintln( rarr.str().replace('\n', ' ').replace('},', '},\n')) diff --git a/vlib/rand/config/config.v b/vlib/rand/config/config.v index 7108d15a9d..eff72ba320 100644 --- a/vlib/rand/config/config.v +++ b/vlib/rand/config/config.v @@ -36,7 +36,7 @@ pub: } // validate_for is a helper function for validating the configuration struct for the given array. -pub fn (config ShuffleConfigStruct) validate_for(a []T) ! { +pub fn (config ShuffleConfigStruct) validate_for[T](a []T) ! { if config.start < 0 || config.start >= a.len { return error("argument 'config.start' must be in range [0, a.len)") } diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index 5371da6c0a..04604d4f3f 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -342,7 +342,7 @@ pub fn (mut rng PRNG) exponential(lambda f64) f64 { // optional and the entire array is shuffled by default. Leave the end as 0 to // shuffle all elements until the end. [direct_array_access] -pub fn (mut rng PRNG) shuffle(mut a []T, config config.ShuffleConfigStruct) ! { +pub fn (mut rng PRNG) shuffle[T](mut a []T, config config.ShuffleConfigStruct) ! { config.validate_for(a)! new_end := if config.end == 0 { a.len } else { config.end } @@ -360,23 +360,23 @@ pub fn (mut rng PRNG) shuffle(mut a []T, config config.ShuffleConfigStruct) ! // shuffle_clone returns a random permutation of the elements in `a`. // The permutation is done on a fresh clone of `a`, so `a` remains unchanged. -pub fn (mut rng PRNG) shuffle_clone(a []T, config config.ShuffleConfigStruct) ![]T { +pub fn (mut rng PRNG) shuffle_clone[T](a []T, config config.ShuffleConfigStruct) ![]T { mut res := a.clone() - rng.shuffle(mut res, config)! + rng.shuffle[T](mut res, config)! return res } // choose samples k elements from the array without replacement. // This means the indices cannot repeat and it restricts the sample size to be less than or equal to the size of the given array. // Note that if the array has repeating elements, then the sample may have repeats as well. -pub fn (mut rng PRNG) choose(array []T, k int) ![]T { +pub fn (mut rng PRNG) choose[T](array []T, k int) ![]T { n := array.len if k > n { return error('Cannot choose ${k} elements without replacement from a ${n}-element array.') } mut results := []T{len: k} mut indices := []int{len: n, init: it} - rng.shuffle(mut indices)! + rng.shuffle[int](mut indices)! for i in 0 .. k { results[i] = array[indices[i]] } @@ -385,7 +385,7 @@ pub fn (mut rng PRNG) choose(array []T, k int) ![]T { // element returns a random element from the given array. // Note that all the positions in the array have an equal chance of being selected. This means that if the array has repeating elements, then the probability of selecting a particular element is not uniform. -pub fn (mut rng PRNG) element(array []T) !T { +pub fn (mut rng PRNG) element[T](array []T) !T { if array.len == 0 { return error('Cannot choose an element from an empty array.') } @@ -394,7 +394,7 @@ pub fn (mut rng PRNG) element(array []T) !T { // sample samples k elements from the array with replacement. // This means the elements can repeat and the size of the sample may exceed the size of the array. -pub fn (mut rng PRNG) sample(array []T, k int) []T { +pub fn (mut rng PRNG) sample[T](array []T, k int) []T { mut results := []T{len: k} for i in 0 .. k { results[i] = array[rng.intn(array.len) or { 0 }] @@ -599,33 +599,33 @@ pub fn ascii(len int) string { // shuffle randomly permutates the elements in `a`. The range for shuffling is // optional and the entire array is shuffled by default. Leave the end as 0 to // shuffle all elements until the end. -pub fn shuffle(mut a []T, config config.ShuffleConfigStruct) ! { - default_rng.shuffle(mut a, config)! +pub fn shuffle[T](mut a []T, config config.ShuffleConfigStruct) ! { + default_rng.shuffle[T](mut a, config)! } // shuffle_clone returns a random permutation of the elements in `a`. // The permutation is done on a fresh clone of `a`, so `a` remains unchanged. -pub fn shuffle_clone(a []T, config config.ShuffleConfigStruct) ![]T { - return default_rng.shuffle_clone(a, config) +pub fn shuffle_clone[T](a []T, config config.ShuffleConfigStruct) ![]T { + return default_rng.shuffle_clone[T](a, config) } // choose samples k elements from the array without replacement. // This means the indices cannot repeat and it restricts the sample size to be less than or equal to the size of the given array. // Note that if the array has repeating elements, then the sample may have repeats as well. -pub fn choose(array []T, k int) ![]T { - return default_rng.choose(array, k) +pub fn choose[T](array []T, k int) ![]T { + return default_rng.choose[T](array, k) } // element returns a random element from the given array. // Note that all the positions in the array have an equal chance of being selected. This means that if the array has repeating elements, then the probability of selecting a particular element is not uniform. -pub fn element(array []T) !T { - return default_rng.element(array) +pub fn element[T](array []T) !T { + return default_rng.element[T](array) } // sample samples k elements from the array with replacement. // This means the elements can repeat and the size of the sample may exceed the size of the array. -pub fn sample(array []T, k int) []T { - return default_rng.sample(array, k) +pub fn sample[T](array []T, k int) []T { + return default_rng.sample[T](array, k) } // bernoulli returns true with a probability p. Note that 0 <= p <= 1. diff --git a/vlib/sync/channel_select_test.v b/vlib/sync/channel_select_test.v index c533c468dd..9a972b3202 100644 --- a/vlib/sync/channel_select_test.v +++ b/vlib/sync/channel_select_test.v @@ -49,10 +49,10 @@ fn do_send_i64(mut ch Channel) { } fn test_select() { - mut chi := new_channel(0) - mut chl := new_channel(1) - mut chb := new_channel(10) - mut recch := new_channel(0) + mut chi := new_channel[int](0) + mut chl := new_channel[i64](1) + mut chb := new_channel[u8](10) + mut recch := new_channel[i64](0) spawn do_rec_i64(mut recch) spawn do_send_int(mut chi) spawn do_send_u8(mut chb) diff --git a/vlib/sync/channels.c.v b/vlib/sync/channels.c.v index 269df09f4b..c70065b907 100644 --- a/vlib/sync/channels.c.v +++ b/vlib/sync/channels.c.v @@ -58,7 +58,7 @@ pub: cap u32 // queue length in #objects } -pub fn new_channel(n u32) &Channel { +pub fn new_channel[T](n u32) &Channel { st := sizeof(T) if isreftype(T) { return new_channel_st(n, st) diff --git a/vlib/sync/channels.js.v b/vlib/sync/channels.js.v index 0dabcb332c..6c43b92676 100644 --- a/vlib/sync/channels.js.v +++ b/vlib/sync/channels.js.v @@ -4,7 +4,7 @@ pub struct Channel { arr array } -pub fn new_channel(n u32) &Channel { +pub fn new_channel[T](n u32) &Channel { return &Channel{arr, new_array()} } diff --git a/vlib/sync/pool/README.md b/vlib/sync/pool/README.md index c1c64fa198..d2b0b70b60 100644 --- a/vlib/sync/pool/README.md +++ b/vlib/sync/pool/README.md @@ -5,7 +5,7 @@ waitgroups, mutexes etc.., you just need to supply a callback function, that will be called once per each item in your input array. After all the work is done in parallel by the worker threads in the pool, -pool.work_on_items will return. You can then call pool.get_results() +pool.work_on_items will return. You can then call pool.get_results[Result]() to retrieve a list of all the results, that the worker callbacks returned for each input item. Example: @@ -17,7 +17,7 @@ pub struct SResult { } fn sprocess(mut pp pool.PoolProcessor, idx int, wid int) &SResult { - item := pp.get_item(idx) + item := pp.get_item[string](idx) println('idx: ${idx}, wid: ${wid}, item: ' + item) return &SResult{item.reverse()} } @@ -26,7 +26,7 @@ fn main() { mut pp := pool.new_pool_processor(callback: sprocess) pp.work_on_items(['1abc', '2abc', '3abc', '4abc', '5abc', '6abc', '7abc']) // optionally, you can iterate over the results too: - for x in pp.get_results() { + for x in pp.get_results[SResult]() { println('result: ${x.s}') } } diff --git a/vlib/sync/pool/pool.v b/vlib/sync/pool/pool.v index 2dddea6756..966b674046 100644 --- a/vlib/sync/pool/pool.v +++ b/vlib/sync/pool/pool.v @@ -72,7 +72,7 @@ pub fn (mut pool PoolProcessor) set_max_jobs(njobs int) { // by the number of available cores on the system. // work_on_items returns *after* all threads finish. // You can optionally call get_results after that. -pub fn (mut pool PoolProcessor) work_on_items(items []T) { +pub fn (mut pool PoolProcessor) work_on_items[T](items []T) { pool.work_on_pointers(unsafe { items.pointers() }) } @@ -117,18 +117,18 @@ fn process_in_thread(mut pool PoolProcessor, task_id int) { // get_item - called by the worker callback. // Retrieves a type safe instance of the currently processed item -pub fn (pool &PoolProcessor) get_item(idx int) T { +pub fn (pool &PoolProcessor) get_item[T](idx int) T { return *(&T(pool.items[idx])) } // get_result - called by the main thread to get a specific result. // Retrieves a type safe instance of the produced result. -pub fn (pool &PoolProcessor) get_result(idx int) T { +pub fn (pool &PoolProcessor) get_result[T](idx int) T { return *(&T(pool.results[idx])) } // get_results - get a list of type safe results in the main thread. -pub fn (pool &PoolProcessor) get_results() []T { +pub fn (pool &PoolProcessor) get_results[T]() []T { mut res := []T{cap: pool.results.len} for i in 0 .. pool.results.len { res << *(&T(pool.results[i])) @@ -137,7 +137,7 @@ pub fn (pool &PoolProcessor) get_results() []T { } // get_results_ref - get a list of type safe results in the main thread. -pub fn (pool &PoolProcessor) get_results_ref() []&T { +pub fn (pool &PoolProcessor) get_results_ref[T]() []&T { mut res := []&T{cap: pool.results.len} for i in 0 .. pool.results.len { res << &T(pool.results[i]) diff --git a/vlib/sync/pool/pool_test.v b/vlib/sync/pool/pool_test.v index 338236cb5e..37563183da 100644 --- a/vlib/sync/pool/pool_test.v +++ b/vlib/sync/pool/pool_test.v @@ -10,14 +10,14 @@ pub struct IResult { } fn worker_s(mut p pool.PoolProcessor, idx int, worker_id int) &SResult { - item := p.get_item(idx) + item := p.get_item[string](idx) println('worker_s worker_id: ${worker_id} | idx: ${idx} | item: ${item}') time.sleep(3 * time.millisecond) return &SResult{'${item} ${item}'} } fn worker_i(mut p pool.PoolProcessor, idx int, worker_id int) &IResult { - item := p.get_item(idx) + item := p.get_item[int](idx) println('worker_i worker_id: ${worker_id} | idx: ${idx} | item: ${item}') time.sleep(5 * time.millisecond) return &IResult{item * 1000} @@ -30,12 +30,12 @@ fn test_work_on_strings() { ) pool_s.work_on_items(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']) - for x in pool_s.get_results() { + for x in pool_s.get_results[SResult]() { println(x.s) assert x.s.len > 1 } println('---------- pool_s.get_results_ref: --------------') - for x in pool_s.get_results_ref() { + for x in pool_s.get_results_ref[SResult]() { println(x.s) assert x.s.len > 1 } @@ -50,12 +50,12 @@ fn test_work_on_ints() { ) pool_i.work_on_items([1, 2, 3, 4, 5, 6, 7, 8]) - for x in pool_i.get_results() { + for x in pool_i.get_results[IResult]() { println(x.i) assert x.i > 100 } println('---------- pool_i.get_results_ref: --------------') - for x in pool_i.get_results_ref() { + for x in pool_i.get_results_ref[IResult]() { println(x.i) assert x.i > 100 } diff --git a/vlib/sync/select_close_test.v b/vlib/sync/select_close_test.v index 505b8c2569..0daa6ab4c5 100644 --- a/vlib/sync/select_close_test.v +++ b/vlib/sync/select_close_test.v @@ -40,10 +40,10 @@ fn do_send_i64(mut ch Channel) { } fn test_select() { - mut chi := new_channel(0) - mut chl := new_channel(1) - mut chb := new_channel(10) - mut recch := new_channel(0) + mut chi := new_channel[int](0) + mut chl := new_channel[i64](1) + mut chb := new_channel[u8](10) + mut recch := new_channel[i64](0) spawn do_rec_i64(mut recch) spawn do_send_int(mut chi) spawn do_send_u8(mut chb) diff --git a/vlib/toml/any.v b/vlib/toml/any.v index bc8f7acf08..3ebec30c07 100644 --- a/vlib/toml/any.v +++ b/vlib/toml/any.v @@ -329,7 +329,7 @@ fn (a Any) value_(value Any, key []string) Any { // reflect returns `T` with `T.`'s value set to the // value of any 1st level TOML key by the same name. -pub fn (a Any) reflect() T { +pub fn (a Any) reflect[T]() T { mut reflected := T{} $for field in T.fields { mut toml_field_name := field.name diff --git a/vlib/toml/tests/encode_and_decode_test.v b/vlib/toml/tests/encode_and_decode_test.v index 6d44474b6c..eb5151e07a 100644 --- a/vlib/toml/tests/encode_and_decode_test.v +++ b/vlib/toml/tests/encode_and_decode_test.v @@ -36,7 +36,7 @@ fn (mut e Employee) from_toml(any toml.Any) { fn test_encode_and_decode() { x := Employee{'Peter', 28, 95000.5, true, .worker} - s := toml.encode(x) + s := toml.encode[Employee](x) eprintln('Employee x: ${s}') assert s == r'name = "Peter" age = 28 @@ -44,7 +44,7 @@ salary = 95000.5 is_human = true title = 2' - y := toml.decode(s) or { + y := toml.decode[Employee](s) or { println(err) assert false return diff --git a/vlib/toml/tests/reflect_test.v b/vlib/toml/tests/reflect_test.v index c4fe248e7e..4ae07e8101 100644 --- a/vlib/toml/tests/reflect_test.v +++ b/vlib/toml/tests/reflect_test.v @@ -62,9 +62,9 @@ mut: fn test_reflect() { toml_doc := toml.parse_text(toml_text) or { panic(err) } - mut user := toml_doc.reflect() - user.bio = toml_doc.value('bio').reflect() - user.remap = toml_doc.value('field_remap').reflect() + mut user := toml_doc.reflect[User]() + user.bio = toml_doc.value('bio').reflect[Bio]() + user.remap = toml_doc.value('field_remap').reflect[FieldRemap]() assert user.name == 'Tom' assert user.age == 45 diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index f96e88cfa0..c4631e763d 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -13,7 +13,7 @@ pub struct Null { } // decode decodes a TOML `string` into the target type `T`. -pub fn decode(toml_txt string) !T { +pub fn decode[T](toml_txt string) !T { doc := parse_text(toml_txt)! mut typ := T{} typ.from_toml(doc.to_any()) @@ -22,7 +22,7 @@ pub fn decode(toml_txt string) !T { // encode encodes the type `T` into a TOML string. // Currently encode expects the method `.to_toml()` exists on `T`. -pub fn encode(typ T) string { +pub fn encode[T](typ T) string { return typ.to_toml() } @@ -194,8 +194,8 @@ pub fn (d Doc) to_any() Any { // reflect returns `T` with `T.`'s value set to the // value of any 1st level TOML key by the same name. -pub fn (d Doc) reflect() T { - return d.to_any().reflect() +pub fn (d Doc) reflect[T]() T { + return d.to_any().reflect[T]() } // value queries a value from the TOML document. diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 8c7cbf0e62..a8c710f4f3 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -108,7 +108,7 @@ fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mo } } if add_para_types { - f.write_string('<') + f.write_string('[') for i, gname in node.generic_names { is_last := i == node.generic_names.len - 1 f.write_string(gname) @@ -116,7 +116,7 @@ fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mo f.write_string(', ') } } - f.write_string('>') + f.write_string(']') } } f.write_string('(') diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 26cf87bfe2..a83d4e6326 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -898,8 +898,8 @@ pub fn (t &Table) array_cname(elem_type Type) string { suffix := if elem_type.is_ptr() { '_ptr'.repeat(elem_type.nr_muls()) } else { '' } opt := if elem_type.has_flag(.optional) { '_option_' } else { '' } res := if elem_type.has_flag(.result) { '_result_' } else { '' } - if elem_type_sym.cname.contains('<') { - type_name := elem_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', '']) + if elem_type_sym.cname.contains('[') { + type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) return 'Array_${opt}${res}${type_name}${suffix}' } else { return 'Array_${opt}${res}${elem_type_sym.cname}${suffix}' @@ -928,8 +928,8 @@ pub fn (t &Table) array_fixed_cname(elem_type Type, size int) string { suffix := if elem_type.is_ptr() { '_ptr${elem_type.nr_muls()}' } else { '' } opt := if elem_type.has_flag(.optional) { '_option_' } else { '' } res := if elem_type.has_flag(.result) { '_result_' } else { '' } - if elem_type_sym.cname.contains('<') { - type_name := elem_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', '']) + if elem_type_sym.cname.contains('[') { + type_name := elem_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) return 'Array_fixed_${opt}${res}${type_name}${suffix}_${size}' } else { return 'Array_fixed_${opt}${res}${elem_type_sym.cname}${suffix}_${size}' @@ -963,11 +963,11 @@ pub fn (t &Table) chan_cname(elem_type Type, is_mut bool) string { [inline] pub fn (t &Table) promise_name(return_type Type) string { if return_type.idx() == void_type_idx { - return 'Promise' + return 'Promise[JS.Any, JS.Any]' } return_type_sym := t.sym(return_type) - return 'Promise<${return_type_sym.name}, JS.Any>' + return 'Promise[${return_type_sym.name}, JS.Any]' } [inline] @@ -1035,8 +1035,8 @@ pub fn (t &Table) map_cname(key_type Type, value_type Type) string { suffix := if value_type.is_ptr() { '_ptr'.repeat(value_type.nr_muls()) } else { '' } opt := if value_type.has_flag(.optional) { '_option_' } else { '' } res := if value_type.has_flag(.result) { '_result_' } else { '' } - if value_type_sym.cname.contains('<') { - type_name := value_type_sym.cname.replace_each(['<', '_T_', ', ', '_', '>', '']) + if value_type_sym.cname.contains('[') { + type_name := value_type_sym.cname.replace_each(['[', '_T_', ', ', '_', ']', '']) return 'Map_${key_type_sym.cname}_${opt}${res}${type_name}${suffix}' } else { return 'Map_${key_type_sym.cname}_${opt}${res}${value_type_sym.cname}${suffix}' @@ -1707,7 +1707,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } Struct, Interface, SumType { if sym.info.is_generic { - mut nrt := '${sym.name}<' + mut nrt := '${sym.name}[' for i in 0 .. sym.info.generic_types.len { if ct := t.resolve_generic_to_concrete(sym.info.generic_types[i], generic_names, concrete_types) @@ -1719,7 +1719,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } } } - nrt += '>' + nrt += ']' mut idx := t.type_idxs[nrt] if idx == 0 { idx = t.add_placeholder_type(nrt, .v) @@ -1839,7 +1839,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr if !ts.info.is_generic { return typ } - nrt = '${ts.name}<' + nrt = '${ts.name}[' c_nrt = '${ts.cname}_T_' for i in 0 .. ts.info.generic_types.len { if ct := t.resolve_generic_to_concrete(ts.info.generic_types[i], generic_names, @@ -1854,7 +1854,7 @@ pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concr } } } - nrt += '>' + nrt += ']' idx := t.type_idxs[nrt] if idx != 0 && t.type_symbols[idx].kind != .placeholder { return new_type(idx).derive(typ).clear_flag(.generic) diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index e49ac4d200..50e209d69d 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1150,7 +1150,7 @@ pub fn (mytable &Table) type_to_code(t Type) string { // clean type name from generics form. From Type -> Type pub fn (t &Table) clean_generics_type_str(typ Type) string { result := t.type_to_str(typ) - return result.all_before('<') + return result.all_before('[') } // import_aliases is a map of imported symbol aliases 'module.Type' => 'Type' @@ -1263,14 +1263,14 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string] if typ.has_flag(.generic) { match sym.info { Struct, Interface, SumType { - res += '<' + res += '[' for i, gtyp in sym.info.generic_types { res += t.sym(gtyp).name if i != sym.info.generic_types.len - 1 { res += ', ' } } - res += '>' + res += ']' } else {} } @@ -1284,15 +1284,15 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string] } .generic_inst { info := sym.info as GenericInst - res = t.shorten_user_defined_typenames(sym.name.all_before('<'), import_aliases) - res += '<' + res = t.shorten_user_defined_typenames(sym.name.all_before('['), import_aliases) + res += '[' for i, ctyp in info.concrete_types { res += t.type_to_str_using_aliases(ctyp, import_aliases) if i != info.concrete_types.len - 1 { res += ', ' } } - res += '>' + res += ']' } .void { if typ.has_flag(.optional) { @@ -1441,8 +1441,8 @@ pub fn (t &TypeSymbol) symbol_name_except_generic() string { mut embed_name := t.name // remove generic part from name // main.Abc => main.Abc - if embed_name.contains('<') { - embed_name = embed_name.all_before('<') + if embed_name.contains('[') { + embed_name = embed_name.all_before('[') } return embed_name } @@ -1452,8 +1452,8 @@ pub fn (t &TypeSymbol) embed_name() string { mut embed_name := t.name.split('.').last() // remove generic part from name // Abc => Abc - if embed_name.contains('<') { - embed_name = embed_name.split('<')[0] + if embed_name.contains('[') { + embed_name = embed_name.split('[')[0] } return embed_name } diff --git a/vlib/v/builder/cbuilder/parallel_cc.v b/vlib/v/builder/cbuilder/parallel_cc.v index 133c2e3a32..2c63e06a37 100644 --- a/vlib/v/builder/cbuilder/parallel_cc.v +++ b/vlib/v/builder/cbuilder/parallel_cc.v @@ -69,7 +69,7 @@ fn parallel_cc(mut b builder.Builder, header string, res string, out_str string, } fn build_parallel_o_cb(mut p pool.PoolProcessor, idx int, wid int) voidptr { - postfix := p.get_item(idx) + postfix := p.get_item[string](idx) sw := time.new_stopwatch() cmd := '${os.quoted_path(cbuilder.cc_compiler)} ${cbuilder.cc_cflags} -c -w -o out_${postfix}.o out_${postfix}.c' res := os.execute(cmd) diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 4b51ad4cc7..dfbab5d98d 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -32,7 +32,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { for name in embed_generic_names { if name !in node_generic_names { struct_generic_names := node_generic_names.join(', ') - c.error('generic type name `${name}` is not mentioned in struct `${node.name}<${struct_generic_names}>`', + c.error('generic type name `${name}` is not mentioned in struct `${node.name}[${struct_generic_names}]`', embed.pos) } } @@ -79,7 +79,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { } if info.generic_types.len > 0 && !field.typ.has_flag(.generic) && info.concrete_types.len == 0 { - c.error('field `${field.name}` type is generic struct, must specify the generic type names, e.g. Foo, Foo', + c.error('field `${field.name}` type is generic struct, must specify the generic type names, e.g. Foo[T], Foo[int]', field.type_pos) } } @@ -162,14 +162,14 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { for name in field_generic_names { if name !in node_generic_names { struct_generic_names := node_generic_names.join(', ') - c.error('generic type name `${name}` is not mentioned in struct `${node.name}<${struct_generic_names}>`', + c.error('generic type name `${name}` is not mentioned in struct `${node.name}[${struct_generic_names}]`', field.type_pos) } } } } if node.generic_types.len == 0 && has_generic_types { - c.error('generic struct declaration must specify the generic type names, e.g. Foo', + c.error('generic struct declaration must specify the generic type names, e.g. Foo[T]', node.pos) } } @@ -264,10 +264,10 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { } } else { if c.table.cur_concrete_types.len == 0 { - c.error('generic struct init must specify type parameter, e.g. Foo', + c.error('generic struct init must specify type parameter, e.g. Foo[int]', node.pos) } else if node.generic_types.len == 0 { - c.error('generic struct init must specify type parameter, e.g. Foo', + c.error('generic struct init must specify type parameter, e.g. Foo[T]', node.pos) } else if node.generic_types.len > 0 && node.generic_types.len != struct_sym.info.generic_types.len { diff --git a/vlib/v/checker/tests/check_err_msg_with_generics.out b/vlib/v/checker/tests/check_err_msg_with_generics.out index 53e78ea384..f572f02d3c 100644 --- a/vlib/v/checker/tests/check_err_msg_with_generics.out +++ b/vlib/v/checker/tests/check_err_msg_with_generics.out @@ -1,6 +1,6 @@ -vlib/v/checker/tests/check_err_msg_with_generics.vv:15:10: error: cannot cast struct `BSTree>>` to `int` +vlib/v/checker/tests/check_err_msg_with_generics.vv:15:10: error: cannot cast struct `BSTree[Result[[]Token, Err[string]]]` to `int` 13 | fn test_err_msg() { - 14 | typ := datatypes.BSTree>>{} + 14 | typ := datatypes.BSTree[Result[[]Token, Err[string]]]{} 15 | println(int(typ)) | ~~~~~~~~ 16 | } @@ -24,4 +24,4 @@ vlib/datatypes/bstree.v:232:17: error: cannot append `T` to `[]T` 232 | result << node.value | ~~~~~ 233 | bst.pre_order_traversal_helper(node.left, mut result) - 234 | bst.pre_order_traversal_helper(node.right, mut result) \ No newline at end of file + 234 | bst.pre_order_traversal_helper(node.right, mut result) diff --git a/vlib/v/checker/tests/check_err_msg_with_generics.vv b/vlib/v/checker/tests/check_err_msg_with_generics.vv index 57da5432de..0299631400 100644 --- a/vlib/v/checker/tests/check_err_msg_with_generics.vv +++ b/vlib/v/checker/tests/check_err_msg_with_generics.vv @@ -1,16 +1,16 @@ import datatypes -type Result = Err | Ok +type Result[T, U] = Err[U] | Ok[T] -struct Ok { +struct Ok[T] { value T } -struct Err { +struct Err[U] { value U } fn test_err_msg() { - typ := datatypes.BSTree>>{} + typ := datatypes.BSTree[Result[[]Token, Err[string]]]{} println(int(typ)) } diff --git a/vlib/v/checker/tests/generic_interface_err.out b/vlib/v/checker/tests/generic_interface_err.out index 774bc6ed00..17f0836633 100644 --- a/vlib/v/checker/tests/generic_interface_err.out +++ b/vlib/v/checker/tests/generic_interface_err.out @@ -1,16 +1,16 @@ vlib/v/checker/tests/generic_interface_err.vv:10:1: warning: unused variable: `i` - 8 | + 8 | 9 | s := Struct{7} 10 | i := Interface(s) | ^ -vlib/v/checker/tests/generic_interface_err.vv:9:6: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generic_interface_err.vv:9:6: error: generic struct init must specify type parameter, e.g. Foo[int] 7 | } - 8 | + 8 | 9 | s := Struct{7} | ~~~~~~~~~ 10 | i := Interface(s) vlib/v/checker/tests/generic_interface_err.vv:10:6: error: can not find method `method` on `Struct`, needed for interface: `Interface` - 8 | + 8 | 9 | s := Struct{7} 10 | i := Interface(s) | ~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/generic_sumtype_invalid_variant.out b/vlib/v/checker/tests/generic_sumtype_invalid_variant.out index 27ffaee2b4..88f1aec58e 100644 --- a/vlib/v/checker/tests/generic_sumtype_invalid_variant.out +++ b/vlib/v/checker/tests/generic_sumtype_invalid_variant.out @@ -1,11 +1,11 @@ -vlib/v/checker/tests/generic_sumtype_invalid_variant.vv:5:10: error: `MultiGeneric` has no variant `u64` +vlib/v/checker/tests/generic_sumtype_invalid_variant.vv:5:10: error: `MultiGeneric[bool, int, string]` has no variant `u64` 3 | fn main() { - 4 | mut m := MultiGeneric(true) + 4 | mut m := MultiGeneric[bool, int, string](true) 5 | if m is u64 { | ~~~ 6 | println('hi') 7 | } -vlib/v/checker/tests/generic_sumtype_invalid_variant.vv:8:10: error: `MultiGeneric` has no variant `X` +vlib/v/checker/tests/generic_sumtype_invalid_variant.vv:8:10: error: `MultiGeneric[bool, int, string]` has no variant `X` 6 | println('hi') 7 | } 8 | if m is X { diff --git a/vlib/v/checker/tests/generic_sumtype_invalid_variant.vv b/vlib/v/checker/tests/generic_sumtype_invalid_variant.vv index 3cde35be74..11dcd3b254 100644 --- a/vlib/v/checker/tests/generic_sumtype_invalid_variant.vv +++ b/vlib/v/checker/tests/generic_sumtype_invalid_variant.vv @@ -1,7 +1,7 @@ -type MultiGeneric = X | Y | Z +type MultiGeneric[X, Y, Z] = X | Y | Z fn main() { - mut m := MultiGeneric(true) + mut m := MultiGeneric[bool, int, string](true) if m is u64 { println('hi') } diff --git a/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.out b/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.out index 3f23d6b4c8..cd47c4147c 100644 --- a/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.out +++ b/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.out @@ -4,10 +4,10 @@ vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv:3:13: error: cann 3 | foo_str(1, x) | ^ 4 | - 5 | foo := Foo{} -vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv:6:11: error: cannot use `[]rune` as `string` in argument 1 to `Foo.info` + 5 | foo := Foo[int]{} +vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv:6:11: error: cannot use `[]rune` as `string` in argument 1 to `Foo[int].info` 4 | - 5 | foo := Foo{} + 5 | foo := Foo[int]{} 6 | foo.info(x) | ^ 7 | } diff --git a/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv b/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv index fdbdf4d15a..09a6e443ed 100644 --- a/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv +++ b/vlib/v/checker/tests/generics_fn_called_multi_args_mismatch.vv @@ -2,16 +2,16 @@ fn main() { x := 'ab'.runes()[..1] foo_str(1, x) - foo := Foo{} + foo := Foo[int]{} foo.info(x) } -fn foo_str(b T, a string) { +fn foo_str[T](b T, a string) { } -struct Foo { +struct Foo[T] { t T } -fn (f Foo) info(a string) { +fn (f Foo[T]) info(a string) { } diff --git a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out index e311bd4f40..3fcb8879da 100644 --- a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out +++ b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.out @@ -1,13 +1,13 @@ vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv:13:32: error: return generic struct in fn declaration must specify the generic type names, e.g. Foo 11 | } 12 | - 13 | pub fn new_channel_struct() GenericChannelStruct { + 13 | pub fn new_channel_struct[T]() GenericChannelStruct { | ~~~~~~~~~~~~~~~~~~~~ 14 | d := GenericChannelStruct{ 15 | ch: chan T{} -vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv:14:7: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv:14:7: error: generic struct init must specify type parameter, e.g. Foo[T] 12 | - 13 | pub fn new_channel_struct() GenericChannelStruct { + 13 | pub fn new_channel_struct[T]() GenericChannelStruct { 14 | d := GenericChannelStruct{ | ~~~~~~~~~~~~~~~~~~~~~ 15 | ch: chan T{} diff --git a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv index 0f9a5d5f91..68dc50ef5f 100644 --- a/vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv +++ b/vlib/v/checker/tests/generics_fn_return_generic_struct_err.vv @@ -1,4 +1,4 @@ -struct GenericChannelStruct { +struct GenericChannelStruct[T] { ch chan T } @@ -7,10 +7,10 @@ struct Simple { } fn main() { - new_channel_struct() + new_channel_struct[Simple]() } -pub fn new_channel_struct() GenericChannelStruct { +pub fn new_channel_struct[T]() GenericChannelStruct { d := GenericChannelStruct{ ch: chan T{} } diff --git a/vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.out b/vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.out index 4651a6a798..5d7d1e6669 100644 --- a/vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.out +++ b/vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.vv:56:13: error: cannot use `Maybe` as `Maybe` in argument 1 to `Maybe.or` +vlib/v/checker/tests/generics_method_sumtype_arg_mismatch.vv:56:13: error: cannot use `Maybe[string]` as `Maybe[int]` in argument 1 to `Maybe[int].or` 54 | b := some('abc') 55 | 56 | c := a.@or(b) diff --git a/vlib/v/checker/tests/generics_struct_decl_no_mention_err.out b/vlib/v/checker/tests/generics_struct_decl_no_mention_err.out index 163688e135..81cb286e82 100644 --- a/vlib/v/checker/tests/generics_struct_decl_no_mention_err.out +++ b/vlib/v/checker/tests/generics_struct_decl_no_mention_err.out @@ -1,12 +1,12 @@ -vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv:4:2: error: generic type name `T` is not mentioned in struct `Foo` +vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv:4:2: error: generic type name `T` is not mentioned in struct `Foo[U]` 2 | - 3 | struct Foo { - 4 | Bar + 3 | struct Foo[U] { + 4 | Bar[T] | ~~~~~~ 5 | foo U 6 | bar P -vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv:6:6: error: generic type name `P` is not mentioned in struct `Foo` - 4 | Bar +vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv:6:6: error: generic type name `P` is not mentioned in struct `Foo[U]` + 4 | Bar[T] 5 | foo U 6 | bar P | ^ diff --git a/vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv b/vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv index b2573ca46c..da7c003cfd 100644 --- a/vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv +++ b/vlib/v/checker/tests/generics_struct_decl_no_mention_err.vv @@ -1,10 +1,10 @@ fn main() {} -struct Foo { - Bar +struct Foo[U] { + Bar[T] foo U bar P } -struct Bar { +struct Bar[T] { } diff --git a/vlib/v/checker/tests/generics_struct_declaration_err.out b/vlib/v/checker/tests/generics_struct_declaration_err.out index bd3b2c3476..eb8063f62d 100644 --- a/vlib/v/checker/tests/generics_struct_declaration_err.out +++ b/vlib/v/checker/tests/generics_struct_declaration_err.out @@ -1,7 +1,7 @@ -vlib/v/checker/tests/generics_struct_declaration_err.vv:5:1: error: generic struct declaration must specify the generic type names, e.g. Foo +vlib/v/checker/tests/generics_struct_declaration_err.vv:5:1: error: generic struct declaration must specify the generic type names, e.g. Foo[T] 3 | } 4 | 5 | struct MyGenericChannelStruct { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 6 | GenericChannelStruct + 6 | GenericChannelStruct[T] 7 | msg string diff --git a/vlib/v/checker/tests/generics_struct_declaration_err.vv b/vlib/v/checker/tests/generics_struct_declaration_err.vv index ef8fe6be2f..2035154ac6 100644 --- a/vlib/v/checker/tests/generics_struct_declaration_err.vv +++ b/vlib/v/checker/tests/generics_struct_declaration_err.vv @@ -1,9 +1,9 @@ -struct GenericChannelStruct { +struct GenericChannelStruct[T] { ch chan T } struct MyGenericChannelStruct { - GenericChannelStruct + GenericChannelStruct[T] msg string } @@ -12,11 +12,11 @@ struct Simple { } fn main() { - new_channel_struct() + new_channel_struct[Simple]() } -pub fn new_channel_struct() GenericChannelStruct { - d := GenericChannelStruct{ +pub fn new_channel_struct[T]() GenericChannelStruct[T] { + d := GenericChannelStruct[T]{ ch: chan T{} } diff --git a/vlib/v/checker/tests/generics_struct_field_fn_args_err.out b/vlib/v/checker/tests/generics_struct_field_fn_args_err.out index a883d2eadd..73614ee618 100644 --- a/vlib/v/checker/tests/generics_struct_field_fn_args_err.out +++ b/vlib/v/checker/tests/generics_struct_field_fn_args_err.out @@ -26,21 +26,21 @@ vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:30:24: error: expected | ~~ 31 | 32 | println(fun1.call(true)) -vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:32:20: error: cannot use `bool` as `int` in argument 1 to `Fun.call` +vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:32:20: error: cannot use `bool` as `int` in argument 1 to `Fun[fn (int) int].call` 30 | println(fun1.call(42, 43)) 31 | 32 | println(fun1.call(true)) | ~~~~ 33 | println(fun1.call('text')) 34 | println(fun1.call(22.2)) -vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:33:20: error: cannot use `string` as `int` in argument 1 to `Fun.call` +vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:33:20: error: cannot use `string` as `int` in argument 1 to `Fun[fn (int) int].call` 31 | 32 | println(fun1.call(true)) 33 | println(fun1.call('text')) | ~~~~~~ 34 | println(fun1.call(22.2)) 35 | } -vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:34:20: error: cannot use `float literal` as `int` in argument 1 to `Fun.call` +vlib/v/checker/tests/generics_struct_field_fn_args_err.vv:34:20: error: cannot use `float literal` as `int` in argument 1 to `Fun[fn (int) int].call` 32 | println(fun1.call(true)) 33 | println(fun1.call('text')) 34 | println(fun1.call(22.2)) diff --git a/vlib/v/checker/tests/generics_struct_field_type_err.out b/vlib/v/checker/tests/generics_struct_field_type_err.out index 4f844c4bd7..ca8b4f5666 100644 --- a/vlib/v/checker/tests/generics_struct_field_type_err.out +++ b/vlib/v/checker/tests/generics_struct_field_type_err.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/generics_struct_field_type_err.vv:4:9: error: field `next` type is generic struct, must specify the generic type names, e.g. Foo, Foo +vlib/v/checker/tests/generics_struct_field_type_err.vv:4:9: error: field `next` type is generic struct, must specify the generic type names, e.g. Foo[T], Foo[int] 2 | mut: 3 | value T 4 | next &LL = unsafe { 0 } diff --git a/vlib/v/checker/tests/generics_struct_init_err.out b/vlib/v/checker/tests/generics_struct_init_err.out index 62402f8129..399fd6474c 100644 --- a/vlib/v/checker/tests/generics_struct_init_err.out +++ b/vlib/v/checker/tests/generics_struct_init_err.out @@ -1,55 +1,55 @@ -vlib/v/checker/tests/generics_struct_init_err.vv:58:8: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:58:8: error: generic struct init must specify type parameter, e.g. Foo[int] 56 | ret = holder_call_12(neg, 3) 57 | assert ret == -3 58 | ret = FnHolder1{neg}.call(4) | ~~~~~~~~~~~~~~ 59 | assert ret == -4 60 | -vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct init must specify type parameter, e.g. Foo[int] 65 | ret = holder_call_22(neg, 5) 66 | assert ret == -5 67 | ret = FnHolder2{neg}.call(6) | ~~~~~~~~~~~~~~ 68 | assert ret == -6 69 | } -vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo[T] 20 | - 21 | fn holder_call_1(func T, a int) int { + 21 | fn holder_call_1[T](func T, a int) int { 22 | h := FnHolder1{func} | ~~~~~~~~~~~~~~~ 23 | return h.call(a) 24 | } -vlib/v/checker/tests/generics_struct_init_err.vv:27:7: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:27:7: error: generic struct init must specify type parameter, e.g. Foo[T] 25 | - 26 | fn holder_call_2(func T, a int) int { + 26 | fn holder_call_2[T](func T, a int) int { 27 | h := FnHolder2{func} | ~~~~~~~~~~~~~~~ 28 | return h.call(a) 29 | } -vlib/v/checker/tests/generics_struct_init_err.vv:33:7: error: generic struct init must specify type parameter, e.g. Foo - 31 | fn holder_call_11(func T, a int) int { +vlib/v/checker/tests/generics_struct_init_err.vv:33:7: error: generic struct init must specify type parameter, e.g. Foo[T] + 31 | fn holder_call_11[T](func T, a int) int { 32 | f := func 33 | h := FnHolder1{f} | ~~~~~~~~~~~~ 34 | return h.call(a) 35 | } -vlib/v/checker/tests/generics_struct_init_err.vv:39:7: error: generic struct init must specify type parameter, e.g. Foo - 37 | fn holder_call_21(func T, a int) int { +vlib/v/checker/tests/generics_struct_init_err.vv:39:7: error: generic struct init must specify type parameter, e.g. Foo[T] + 37 | fn holder_call_21[T](func T, a int) int { 38 | f := func 39 | h := FnHolder2{f} | ~~~~~~~~~~~~ 40 | return h.call(a) 41 | } -vlib/v/checker/tests/generics_struct_init_err.vv:44:9: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:44:9: error: generic struct init must specify type parameter, e.g. Foo[T] 42 | - 43 | fn holder_call_12(func T, a int) int { + 43 | fn holder_call_12[T](func T, a int) int { 44 | return FnHolder1{func}.call(a) | ~~~~~~~~~~~~~~~ 45 | } 46 | -vlib/v/checker/tests/generics_struct_init_err.vv:48:9: error: generic struct init must specify type parameter, e.g. Foo +vlib/v/checker/tests/generics_struct_init_err.vv:48:9: error: generic struct init must specify type parameter, e.g. Foo[T] 46 | - 47 | fn holder_call_22(func T, a int) int { + 47 | fn holder_call_22[T](func T, a int) int { 48 | return FnHolder2{func}.call(a) | ~~~~~~~~~~~~~~~ 49 | } diff --git a/vlib/v/checker/tests/generics_struct_init_err.vv b/vlib/v/checker/tests/generics_struct_init_err.vv index 41167992e7..622ec6fd3c 100644 --- a/vlib/v/checker/tests/generics_struct_init_err.vv +++ b/vlib/v/checker/tests/generics_struct_init_err.vv @@ -2,49 +2,49 @@ fn neg(a int) int { return -a } -struct FnHolder1 { +struct FnHolder1[T] { func T } -fn (self FnHolder1) call(a int) int { +fn (self FnHolder1[T]) call(a int) int { return self.func(a) } -struct FnHolder2 { +struct FnHolder2[T] { func fn (int) int } -fn (self FnHolder2) call(a int) int { +fn (self FnHolder2[T]) call(a int) int { return self.func(a) } -fn holder_call_1(func T, a int) int { +fn holder_call_1[T](func T, a int) int { h := FnHolder1{func} return h.call(a) } -fn holder_call_2(func T, a int) int { +fn holder_call_2[T](func T, a int) int { h := FnHolder2{func} return h.call(a) } -fn holder_call_11(func T, a int) int { +fn holder_call_11[T](func T, a int) int { f := func h := FnHolder1{f} return h.call(a) } -fn holder_call_21(func T, a int) int { +fn holder_call_21[T](func T, a int) int { f := func h := FnHolder2{f} return h.call(a) } -fn holder_call_12(func T, a int) int { +fn holder_call_12[T](func T, a int) int { return FnHolder1{func}.call(a) } -fn holder_call_22(func T, a int) int { +fn holder_call_22[T](func T, a int) int { return FnHolder2{func}.call(a) } diff --git a/vlib/v/checker/tests/generics_undefined_operation.out b/vlib/v/checker/tests/generics_undefined_operation.out index 49ed8004e4..52fd6b3e04 100644 --- a/vlib/v/checker/tests/generics_undefined_operation.out +++ b/vlib/v/checker/tests/generics_undefined_operation.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/generics_undefined_operation.vv:12:5: error: undefined operation `V2d` * `V2d` - 10 | v3 := V2d{4, 6} +vlib/v/checker/tests/generics_undefined_operation.vv:12:5: error: undefined operation `V2d[int]` * `V2d[int]` + 10 | v3 := V2d[int]{4, 6} 11 | 12 | if v1 * v2 == v3 { | ~~~~~~~ diff --git a/vlib/v/checker/tests/generics_undefined_operation.vv b/vlib/v/checker/tests/generics_undefined_operation.vv index 28184f2640..c991417290 100644 --- a/vlib/v/checker/tests/generics_undefined_operation.vv +++ b/vlib/v/checker/tests/generics_undefined_operation.vv @@ -1,13 +1,13 @@ -struct V2d { +struct V2d[T] { mut: x T y T } fn main() { - v1 := V2d{2, 2} - v2 := V2d{2, 3} - v3 := V2d{4, 6} + v1 := V2d[int]{2, 2} + v2 := V2d[int]{2, 3} + v3 := V2d[int]{4, 6} if v1 * v2 == v3 { } diff --git a/vlib/v/checker/tests/interface_generic_err.out b/vlib/v/checker/tests/interface_generic_err.out index bae6c4f407..71b13a7407 100644 --- a/vlib/v/checker/tests/interface_generic_err.out +++ b/vlib/v/checker/tests/interface_generic_err.out @@ -3,8 +3,8 @@ vlib/v/checker/tests/interface_generic_err.vv:8:1: warning: unused variable: `wh 7 | what := What{} 8 | why := Why(what) | ~~~ -vlib/v/checker/tests/interface_generic_err.vv:7:9: error: generic struct init must specify type parameter, e.g. Foo - 5 | +vlib/v/checker/tests/interface_generic_err.vv:7:9: error: generic struct init must specify type parameter, e.g. Foo[int] + 5 | 6 | // no segfault without generic 7 | what := What{} | ~~~~~~ diff --git a/vlib/v/checker/tests/interface_generic_err.vv b/vlib/v/checker/tests/interface_generic_err.vv index 7c6b2b4286..717fef55ec 100644 --- a/vlib/v/checker/tests/interface_generic_err.vv +++ b/vlib/v/checker/tests/interface_generic_err.vv @@ -1,7 +1,7 @@ -struct What {} +struct What[T] {} // with or without generic -interface Why {} +interface Why[T] {} // no segfault without generic what := What{} diff --git a/vlib/v/checker/tests/struct_cast_to_struct_generic_err.out b/vlib/v/checker/tests/struct_cast_to_struct_generic_err.out index b6ee544b4d..a139939c9a 100644 --- a/vlib/v/checker/tests/struct_cast_to_struct_generic_err.out +++ b/vlib/v/checker/tests/struct_cast_to_struct_generic_err.out @@ -1,12 +1,12 @@ vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv:11:7: warning: casting to struct is deprecated, use e.g. `Struct{...expr}` instead 9 | fn main() { - 10 | abc := Abc{} + 10 | abc := Abc[int]{} 11 | _ := Xyz(abc) | ~~~~~~~~ 12 | } -vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv:11:7: error: cannot convert struct `Abc` to struct `Xyz` +vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv:11:7: error: cannot convert struct `Abc[int]` to struct `Xyz` 9 | fn main() { - 10 | abc := Abc{} + 10 | abc := Abc[int]{} 11 | _ := Xyz(abc) | ~~~~~~~~ 12 | } diff --git a/vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv b/vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv index ce81ba52f4..0783814f7c 100644 --- a/vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv +++ b/vlib/v/checker/tests/struct_cast_to_struct_generic_err.vv @@ -1,4 +1,4 @@ -struct Abc { +struct Abc[T] { name T } @@ -7,6 +7,6 @@ struct Xyz { } fn main() { - abc := Abc{} + abc := Abc[int]{} _ := Xyz(abc) } diff --git a/vlib/v/checker/tests/undefined_type_on_sumtype.out b/vlib/v/checker/tests/undefined_type_on_sumtype.out index be991a6caf..d87f974bfa 100644 --- a/vlib/v/checker/tests/undefined_type_on_sumtype.out +++ b/vlib/v/checker/tests/undefined_type_on_sumtype.out @@ -1,13 +1,13 @@ vlib/v/checker/tests/undefined_type_on_sumtype.vv:30:4: warning: unused variable: `rx` 28 | match r { - 29 | Some { + 29 | Some[ParseRes] { 30 | rx := r.value | ~~ 31 | } - 32 | None {} + 32 | None[ParseRes] {} vlib/v/checker/tests/undefined_type_on_sumtype.vv:1:17: error: unknown type `Token`. -Did you mean `Ok<[]Token>`? - 1 | type ParseRes = Result<[]Token, ParseErr> +Did you mean `Ok[[]Token]`? + 1 | type ParseRes = Result[[]Token, ParseErr] | ~~~~~~~~~~~~~~~~~~~~~~~~~ - 2 | + 2 | 3 | // Token type is unknown diff --git a/vlib/v/checker/tests/undefined_type_on_sumtype.vv b/vlib/v/checker/tests/undefined_type_on_sumtype.vv index 51b836d89f..dc91ef01d0 100644 --- a/vlib/v/checker/tests/undefined_type_on_sumtype.vv +++ b/vlib/v/checker/tests/undefined_type_on_sumtype.vv @@ -1,34 +1,34 @@ -type ParseRes = Result<[]Token, ParseErr> +type ParseRes = Result[[]Token, ParseErr] // Token type is unknown -//struct Token {} +// struct Token {} struct ParseErr {} -type Opt = None | Some +type Opt[T] = None[T] | Some[T] -struct None {} +struct None[T] {} -struct Some { +struct Some[T] { value T } -type Result = Err | Ok +type Result[T, U] = Err[U] | Ok[T] -struct Ok { +struct Ok[T] { value T } -struct Err { +struct Err[U] { value U } fn test_report() { - r := Opt(None{}) + r := Opt[ParseRes](None[ParseRes]{}) match r { - Some { + Some[ParseRes] { rx := r.value } - None {} + None[ParseRes] {} } } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index df026ce85c..1f5ea33e33 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -201,10 +201,10 @@ fn (mut f Fmt) write_language_prefix(lang ast.Language) { fn (mut f Fmt) write_generic_types(gtypes []ast.Type) { if gtypes.len > 0 { - f.write('<') + f.write('[') gtypes_string := gtypes.map(f.table.type_to_str(it)).join(', ') f.write(gtypes_string) - f.write('>') + f.write(']') } } @@ -248,14 +248,14 @@ pub fn (mut f Fmt) short_module(name string) string { if name in f.mod2syms { return f.mod2syms[name] } - if name.ends_with('>') { - generic_levels := name.trim_string_right('>').split('<') + if name.ends_with(']') { + generic_levels := name.trim_string_right(']').split('[') mut res := '${f.short_module(generic_levels[0])}' for i in 1 .. generic_levels.len { genshorts := generic_levels[i].split(', ').map(f.short_module(it)).join(', ') - res += '<${genshorts}' + res += '[${genshorts}' } - res += '>' + res += ']' return res } vals := name.split('.') @@ -295,7 +295,7 @@ pub fn (mut f Fmt) mark_types_import_as_used(typ ast.Type) { f.mark_types_import_as_used(concrete_typ) } } - name := sym.name.split('<')[0] // take `Type` from `Type` + name := sym.name.split('[')[0] // take `Type` from `Type[T]` f.mark_import_as_used(name) } @@ -1777,7 +1777,7 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) { fn (mut f Fmt) write_generic_call_if_require(node ast.CallExpr) { if node.concrete_types.len > 0 { - f.write('<') + f.write('[') for i, concrete_type in node.concrete_types { mut name := f.table.type_to_str_using_aliases(concrete_type, f.mod2alias) tsym := f.table.sym(concrete_type) @@ -1792,7 +1792,7 @@ fn (mut f Fmt) write_generic_call_if_require(node ast.CallExpr) { f.write(', ') } } - f.write('>') + f.write(']') } } diff --git a/vlib/v/fmt/tests/comptime_field_selector_keep.vv b/vlib/v/fmt/tests/comptime_field_selector_keep.vv index e9752dee84..1f122b491e 100644 --- a/vlib/v/fmt/tests/comptime_field_selector_keep.vv +++ b/vlib/v/fmt/tests/comptime_field_selector_keep.vv @@ -8,7 +8,7 @@ fn (f Foo) print() { println('test') } -fn test() { +fn test[T]() { mut t := T{} t.name = '2' $for f in T.fields { @@ -19,5 +19,5 @@ fn test() { } fn main() { - test() + test[Foo]() } diff --git a/vlib/v/fmt/tests/comptime_field_selector_parentheses_keep.vv b/vlib/v/fmt/tests/comptime_field_selector_parentheses_keep.vv index e9752dee84..1f122b491e 100644 --- a/vlib/v/fmt/tests/comptime_field_selector_parentheses_keep.vv +++ b/vlib/v/fmt/tests/comptime_field_selector_parentheses_keep.vv @@ -8,7 +8,7 @@ fn (f Foo) print() { println('test') } -fn test() { +fn test[T]() { mut t := T{} t.name = '2' $for f in T.fields { @@ -19,5 +19,5 @@ fn test() { } fn main() { - test() + test[Foo]() } diff --git a/vlib/v/fmt/tests/comptime_keep.vv b/vlib/v/fmt/tests/comptime_keep.vv index 96206dddb9..2952acc3c3 100644 --- a/vlib/v/fmt/tests/comptime_keep.vv +++ b/vlib/v/fmt/tests/comptime_keep.vv @@ -66,7 +66,7 @@ fn (mut a App) my_method(p string) Result { return Result{} } -fn handle_conn(mut app T) { +fn handle_conn[T](mut app T) { $for method in T.methods { $if method.return_type is Result { app.$method('abc', 'def') @@ -76,7 +76,7 @@ fn handle_conn(mut app T) { fn comptime_call_dollar_method() { mut app := App{} - handle_conn(mut app) + handle_conn[App](mut app) } fn (mut app App) create() vweb.Result { diff --git a/vlib/v/fmt/tests/fn_return_generic_struct_keep.vv b/vlib/v/fmt/tests/fn_return_generic_struct_keep.vv index abbc861ee4..39003ab011 100644 --- a/vlib/v/fmt/tests/fn_return_generic_struct_keep.vv +++ b/vlib/v/fmt/tests/fn_return_generic_struct_keep.vv @@ -1,4 +1,4 @@ -pub struct Optional { +pub struct Optional[T] { mut: value T some bool @@ -8,32 +8,32 @@ pub struct Foo { foo int } -pub fn (f Foo) new_some(value T) Optional { +pub fn (f Foo) new_some[T](value T) Optional[T] { return Optional{ value: value some: true } } -pub fn (f Foo) some(opt Optional) bool { +pub fn (f Foo) some[T](opt Optional[T]) bool { return opt.some } -pub fn (f Foo) get(opt Optional) T { +pub fn (f Foo) get[T](opt Optional[T]) T { return opt.value } -pub fn (f Foo) set(mut opt Optional, value T) { +pub fn (f Foo) set[T](mut opt Optional[T], value T) { opt.value = value opt.some = true } fn main() { foo := Foo{} - mut o := foo.new_some(23) - println(foo.some(o)) - assert foo.some(o) == true - foo.set(mut o, 42) - println(foo.get(o)) - assert foo.get(o) == 42 + mut o := foo.new_some[int](23) + println(foo.some[int](o)) + assert foo.some[int](o) == true + foo.set[int](mut o, 42) + println(foo.get[int](o)) + assert foo.get[int](o) == 42 } diff --git a/vlib/v/fmt/tests/generic_recursive_structs_keep.vv b/vlib/v/fmt/tests/generic_recursive_structs_keep.vv index a8704c5749..ae0005be23 100644 --- a/vlib/v/fmt/tests/generic_recursive_structs_keep.vv +++ b/vlib/v/fmt/tests/generic_recursive_structs_keep.vv @@ -1,20 +1,20 @@ -pub struct Node { +pub struct Node[T] { value T - points_to []&Node + points_to []&Node[T] } fn main() { - mid := &Node{ + mid := &Node[string]{ value: 'Middle' } - finish := &Node{ + finish := &Node[string]{ value: 'Finish' } - graph := &Node{ + graph := &Node[string]{ value: 'Start' points_to: [ - &Node{ + &Node[string]{ value: 'TopLeft' points_to: [ finish, diff --git a/vlib/v/fmt/tests/generic_struct_init_keep.vv b/vlib/v/fmt/tests/generic_struct_init_keep.vv index 8dcccf0074..ce06bafad4 100644 --- a/vlib/v/fmt/tests/generic_struct_init_keep.vv +++ b/vlib/v/fmt/tests/generic_struct_init_keep.vv @@ -1,9 +1,9 @@ module x -struct Ok { +struct Ok[T] { foo []T } fn test_fmt() { - r := Ok<[]Token>{[]} + r := Ok[[]Token]{[]} } diff --git a/vlib/v/fmt/tests/generic_structs_keep.vv b/vlib/v/fmt/tests/generic_structs_keep.vv index ecbdaf042d..c676fbed08 100644 --- a/vlib/v/fmt/tests/generic_structs_keep.vv +++ b/vlib/v/fmt/tests/generic_structs_keep.vv @@ -1,15 +1,15 @@ -struct Foo { +struct Foo[T] { pub: data T } -fn (f Foo) value() string { +fn (f Foo[int]) value() string { return f.data.str() } type DB = string -struct Repo { +struct Repo[T, U] { db DB pub mut: model T @@ -27,16 +27,16 @@ pub mut: } fn main() { - foo_int := Foo{2} + foo_int := Foo[int]{2} assert foo_int.value() == '2' println(foo_int) // - x := Repo{'abc', 3, 1.5} + x := Repo[int, f64]{'abc', 3, 1.5} println(x.db) println(x.model) println(x.permission) // - mut a := Repo{ + mut a := Repo[User, Permission]{ model: User{ name: 'joe' } diff --git a/vlib/v/fmt/tests/generic_structs_using_mod_keep.vv b/vlib/v/fmt/tests/generic_structs_using_mod_keep.vv index dbe2a2f9bf..89127a55a1 100644 --- a/vlib/v/fmt/tests/generic_structs_using_mod_keep.vv +++ b/vlib/v/fmt/tests/generic_structs_using_mod_keep.vv @@ -1,8 +1,8 @@ import v.fmt.tests.obj -struct GenericStruct { +struct GenericStruct[A, B] { } fn main() { - _ := GenericStruct{} + _ := GenericStruct[obj.Test, obj.Test]{} } diff --git a/vlib/v/fmt/tests/generics_cascade_types_keep.vv b/vlib/v/fmt/tests/generics_cascade_types_keep.vv index 3e30adc357..a1dc66db01 100644 --- a/vlib/v/fmt/tests/generics_cascade_types_keep.vv +++ b/vlib/v/fmt/tests/generics_cascade_types_keep.vv @@ -1,4 +1,4 @@ -struct Foo { +struct Foo[T] { pub: data T } @@ -7,7 +7,7 @@ struct Foo1 {} struct Foo2 {} -fn multi_generic_args(t T, v V) bool { +fn multi_generic_args[T, V](t T, v V) bool { return true } @@ -21,7 +21,7 @@ fn main() { assert b1 && b2 // generic - assert multi_generic_args(0, 's') - assert multi_generic_args(Foo1{}, Foo2{}) - assert multi_generic_args, Foo>(Foo{}, Foo{}) + assert multi_generic_args[int, string](0, 's') + assert multi_generic_args[Foo1, Foo2](Foo1{}, Foo2{}) + assert multi_generic_args[Foo[int], Foo[int]](Foo[int]{}, Foo[int]{}) } diff --git a/vlib/v/fmt/tests/generics_keep.vv b/vlib/v/fmt/tests/generics_keep.vv index ffecd309b7..84f5659fd3 100644 --- a/vlib/v/fmt/tests/generics_keep.vv +++ b/vlib/v/fmt/tests/generics_keep.vv @@ -1,28 +1,28 @@ import mymod { Data, ImpNode } -fn foobar_mymod(inode ImpNode) ImpNode { +fn foobar_mymod[U](inode ImpNode[U]) ImpNode[U] { return ImpNode{} } -fn simple() T { +fn simple[T]() T { return T{} } struct Foo {} -fn (_ Foo) simple() T { +fn (_ Foo) simple[T]() T { return T{} } -struct GenericStruct { - v Data, B> +struct GenericStruct[A, B] { + v Data[Data[A], B] } -fn proper_generics(gs GenericStruct) GenericStruct { +fn proper_generics(gs GenericStruct[A, B]) GenericStruct[A, B] { return gs } fn main() { - simple() - Foo{}.simple() + simple[int]() + Foo{}.simple[int]() } diff --git a/vlib/v/fmt/tests/import_selective_expected.vv b/vlib/v/fmt/tests/import_selective_expected.vv index 93e5b87613..2926f1aff9 100644 --- a/vlib/v/fmt/tests/import_selective_expected.vv +++ b/vlib/v/fmt/tests/import_selective_expected.vv @@ -51,8 +51,8 @@ fn (s Struct) method(v StructMethodArg) StructMethodRet { return StructMethodRet{} } -fn (s Struct) method_generic(v StructMethodArgGeneric) StructMethodRetGeneric { - return StructMethodRet{} +fn (s Struct) method_generic[T](v StructMethodArgGeneric[T]) StructMethodRetGeneric[T] { + return StructMethodRet[T]{} } interface Interface { @@ -70,10 +70,10 @@ fn f(v FnArg) FnRet { return FnRet{} } -fn f2(v Generic) Generic {} +fn f2(v Generic[FnArgTypeParam1, FnArgTypeParam2]) Generic[FnRetTypeParam1, FnRetTypeParam2] {} -fn f_generic(v FnArgGeneric) FnRetGeneric { - return FnRetGeneric{} +fn f_generic[T](v FnArgGeneric[T]) FnRetGeneric[T] { + return FnRetGeneric[T]{} } struct App { diff --git a/vlib/v/fmt/tests/import_selective_keep.vv b/vlib/v/fmt/tests/import_selective_keep.vv index 5a7603eec4..7d3cd8bac5 100644 --- a/vlib/v/fmt/tests/import_selective_keep.vv +++ b/vlib/v/fmt/tests/import_selective_keep.vv @@ -7,10 +7,10 @@ fn keep_imported_enum_map_key() { bm := map[MouseButton]string{} } -fn generic() {} +fn generic[T]() {} fn main() { _ := Duration(10) // keep cast type assert *(&f64(&byte(&num) + __offsetof(Complex, re))) == 1.0 - generic() + generic[Test]() } diff --git a/vlib/v/fmt/tests/import_with_symbol_of_struct_keep.vv b/vlib/v/fmt/tests/import_with_symbol_of_struct_keep.vv index 22b6bc145d..c05d3aec48 100644 --- a/vlib/v/fmt/tests/import_with_symbol_of_struct_keep.vv +++ b/vlib/v/fmt/tests/import_with_symbol_of_struct_keep.vv @@ -1,5 +1,5 @@ import datatypes { Stack } fn main() { - stack := Stack{} + stack := Stack[int]{} } diff --git a/vlib/v/fmt/tests/multi_generic_test_keep.vv b/vlib/v/fmt/tests/multi_generic_test_keep.vv index f8da457a8e..78059cb34d 100644 --- a/vlib/v/fmt/tests/multi_generic_test_keep.vv +++ b/vlib/v/fmt/tests/multi_generic_test_keep.vv @@ -1,2 +1,2 @@ -fn test() { +fn test[A, B, D, E]() { } diff --git a/vlib/v/fmt/tests/string_interpolation_keep.vv b/vlib/v/fmt/tests/string_interpolation_keep.vv index 242e240acc..5df184b172 100644 --- a/vlib/v/fmt/tests/string_interpolation_keep.vv +++ b/vlib/v/fmt/tests/string_interpolation_keep.vv @@ -14,6 +14,6 @@ fn main() { println('(${some_struct.@type}, ${some_struct.y})') _ := 'CastExpr ${int(d.e).str()}' println('${f[0..4].bytestr()}') - _ := '${generic_fn()}' - _ := '${foo.generic_method()}' + _ := '${generic_fn[int]()}' + _ := '${foo.generic_method[int]()}' } diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 32b28ffb1a..795ac0aaef 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -354,8 +354,8 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam } if clean_interface_v_type_name.contains('_T_') { clean_interface_v_type_name = - clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' + clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + + ']' } clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name) fn_builder.writeln('static string indent_${str_fn_name}(${styp} x, int indent_count) { /* gen_str_for_interface */') @@ -421,8 +421,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_ } if clean_sum_type_v_type_name.contains('_T_') { clean_sum_type_v_type_name = - clean_sum_type_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' + clean_sum_type_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + + ']' } clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name) } @@ -831,8 +831,8 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ // use something different than g.typ for styp clean_struct_v_type_name = - clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' + clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + + ']' } clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) // generate ident / indent length = 4 spaces diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index b1a495cb09..edc8d08271 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -332,7 +332,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string, pp.work_on_items(files) global_g.timers.start('cgen unification') // tg = thread gen - for g in pp.get_results_ref() { + for g in pp.get_results_ref[Gen]() { global_g.embedded_files << g.embedded_files global_g.out.write(g.out) or { panic(err) } global_g.cheaders.write(g.cheaders) or { panic(err) } @@ -603,7 +603,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string, } fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen { - file := p.get_item<&ast.File>(idx) + file := p.get_item[&ast.File](idx) mut global_g := &Gen(p.get_shared_context()) mut g := &Gen{ file: file @@ -991,8 +991,8 @@ fn (mut g Gen) generic_fn_name(types []ast.Type, before string) string { if types.len == 0 { return before } - // Using _T_ to differentiate between get and get_string - // `foo()` => `foo_T_int()` + // Using _T_ to differentiate between get[string] and get_string + // `foo[int]()` => `foo_T_int()` mut name := before + '_T' for typ in types { name += '_' + strings.repeat_string('__ptr__', typ.nr_muls()) + g.typ(typ.set_nr_muls(0)) @@ -1551,7 +1551,7 @@ pub fn (mut g Gen) write_multi_return_types() { if sym.kind != .multi_return { continue } - if sym.cname.contains('<') { + if sym.cname.contains('[') { continue } info := sym.mr_info() diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index e7ccdfc51d..1c79b5cf23 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -342,8 +342,8 @@ fn (mut g JsGen) gen_str_for_interface(info ast.Interface, styp string, str_fn_n } if clean_interface_v_type_name.contains('_T_') { clean_interface_v_type_name = - clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' + clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + + ']' } clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name) fn_builder.writeln('function indent_${str_fn_name}(x,indent_count) { /* gen_str_for_interface */') @@ -699,8 +699,8 @@ fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name st // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ // use something different than g.typ for styp clean_struct_v_type_name = - clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' + clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + + ']' } clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) // generate ident / indent length = 4 spaces diff --git a/vlib/v/mathutil/mathutil.v b/vlib/v/mathutil/mathutil.v index c9e39900fc..13f1023019 100644 --- a/vlib/v/mathutil/mathutil.v +++ b/vlib/v/mathutil/mathutil.v @@ -4,16 +4,16 @@ module mathutil [inline] -pub fn min(a T, b T) T { +pub fn min[T](a T, b T) T { return if a < b { a } else { b } } [inline] -pub fn max(a T, b T) T { +pub fn max[T](a T, b T) T { return if a > b { a } else { b } } [inline] -pub fn abs(a T) T { +pub fn abs[T](a T) T { return if a > 0 { a } else { -a } } diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index ffd1b3e649..beb6213e89 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -675,7 +675,7 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type { start_pos := p.tok.pos() p.next() p.inside_generic_params = true - bs_name += '<' + bs_name += '[' bs_cname += '_T_' mut concrete_types := []ast.Type{} mut is_instance := false @@ -710,7 +710,7 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type { concrete_types_pos := start_pos.extend(p.tok.pos()) p.next() p.inside_generic_params = false - bs_name += '>' + bs_name += ']' // fmt operates on a per-file basis, so is_instance might be not set correctly. Thus it's ignored. if (is_instance || p.pref.is_fmt) && concrete_types.len > 0 { mut gt_idx := p.table.find_type_idx(bs_name) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index bff82e7754..a65c004ac7 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2168,16 +2168,24 @@ fn (p &Parser) is_generic_struct_init() bool { return true } else { mut i := 2 + mut nested_sbr_count := 0 for { cur_tok := p.peek_token(i) - if cur_tok.kind == .eof || cur_tok.kind !in [.amp, .dot, .comma, .name, .lsbr, .rsbr] { + if cur_tok.kind == .eof + || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] { break } - if cur_tok.kind == .rsbr { - if p.peek_token(i + 1).kind == .lcbr { - return true + if cur_tok.kind == .lsbr { + nested_sbr_count++ + } else if cur_tok.kind == .rsbr { + if nested_sbr_count > 0 { + nested_sbr_count-- + } else { + if p.peek_token(i + 1).kind == .lcbr { + return true + } + break } - break } i++ } @@ -2243,17 +2251,25 @@ fn (p &Parser) is_generic_call() bool { } } else if p.peek_tok.kind == .lsbr { mut i := 3 + mut nested_sbr_count := 0 for { cur_tok := p.peek_token(i) if cur_tok.kind == .eof - || cur_tok.kind !in [.amp, .dot, .comma, .name, .lsbr, .rsbr] { + || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] { break } + if cur_tok.kind == .lsbr { + nested_sbr_count++ + } if cur_tok.kind == .rsbr { - if p.peek_token(i + 1).kind == .lpar { - return true + if nested_sbr_count > 0 { + nested_sbr_count-- + } else { + if p.peek_token(i + 1).kind == .lpar { + return true + } + break } - break } i++ } diff --git a/vlib/v/tests/array_to_string_test.v b/vlib/v/tests/array_to_string_test.v index eafd5d916e..502f13fc69 100644 --- a/vlib/v/tests/array_to_string_test.v +++ b/vlib/v/tests/array_to_string_test.v @@ -1,4 +1,4 @@ -fn array_array_array(len int, value T) [][][]T { +fn array_array_array[T](len int, value T) [][][]T { return [][][]T{len: len, init: [][]T{len: len, init: []T{len: len, init: value}}} } @@ -22,7 +22,7 @@ fn test_array_to_string_conversion() { assert f.str() == '[66, 32, 126, 10, 13, 5, 18, 127, 255]' // https://github.com/vlang/v/issues/8036 - g := array_array_array(2, 2) + g := array_array_array[int](2, 2) assert g.str() == '[[[2, 2], [2, 2]], [[2, 2], [2, 2]]]' } diff --git a/vlib/v/tests/assembly/asm_test.amd64.v b/vlib/v/tests/assembly/asm_test.amd64.v index 11c957293b..e8e7d9eee8 100644 --- a/vlib/v/tests/assembly/asm_test.amd64.v +++ b/vlib/v/tests/assembly/asm_test.amd64.v @@ -223,7 +223,7 @@ fn test_asm_generic() { assert i == 137 } -fn generic_asm(var &T) T { +fn generic_asm[T](var &T) T { mut ret := T(14) unsafe { asm volatile amd64 { diff --git a/vlib/v/tests/assembly/asm_test.i386.v b/vlib/v/tests/assembly/asm_test.i386.v index dedf6698e7..cc9683e129 100644 --- a/vlib/v/tests/assembly/asm_test.i386.v +++ b/vlib/v/tests/assembly/asm_test.i386.v @@ -174,7 +174,7 @@ fn test_asm_generic() { assert u64(b) == 137 } -fn generic_asm(var &T) T { +fn generic_asm[T](var &T) T { mut ret := T(14) unsafe { asm volatile amd64 { diff --git a/vlib/v/tests/bench/math_big_gcd/bench_euclid.v b/vlib/v/tests/bench/math_big_gcd/bench_euclid.v index 4346481179..9a2f3f8e37 100644 --- a/vlib/v/tests/bench/math_big_gcd/bench_euclid.v +++ b/vlib/v/tests/bench/math_big_gcd/bench_euclid.v @@ -228,9 +228,9 @@ fn bench_euclid_vs_binary(test_config PrimeCfg, heap bool, predicate_fn fn (ps P // during later testing. // mut casted_sets := if heap { gcd_primes.map(unsafe { - DataI(&PrimeSet(&it)).cast() + DataI(&PrimeSet(&it)).cast[HeapData]() }) } else { gcd_primes.map(unsafe { - DataI(&PrimeSet(&it)).cast() + DataI(&PrimeSet(&it)).cast[StackData]() }) } // ready use the primes in the benchmark diff --git a/vlib/v/tests/bench/math_big_gcd/prime/maker.v b/vlib/v/tests/bench/math_big_gcd/prime/maker.v index 3ac3205051..ce2f8dcea3 100644 --- a/vlib/v/tests/bench/math_big_gcd/prime/maker.v +++ b/vlib/v/tests/bench/math_big_gcd/prime/maker.v @@ -11,7 +11,7 @@ pub interface DataI { from_primeset(PrimeSet) DataI } -pub fn (di DataI) cast() DataI { +pub fn (di DataI) cast[T]() DataI { return T{}.from_primeset(di.to_primeset()) } diff --git a/vlib/v/tests/c_array_test.v b/vlib/v/tests/c_array_test.v index 6642c05539..34b875e6f9 100644 --- a/vlib/v/tests/c_array_test.v +++ b/vlib/v/tests/c_array_test.v @@ -9,7 +9,7 @@ fn C.gen_c_int_array(size int) voidptr fn test_carray_to_varray() { size := 10 mut c_array := C.gen_c_array(size) - v_u8_array := unsafe { arrays.carray_to_varray(c_array, size) } + v_u8_array := unsafe { arrays.carray_to_varray[u8](c_array, size) } unsafe { C.free(c_array) } assert v_u8_array.len == size for i, elem in v_u8_array { @@ -17,7 +17,7 @@ fn test_carray_to_varray() { } c_int_array := C.gen_c_int_array(size) - v_int_array := unsafe { arrays.carray_to_varray(c_int_array, size) } + v_int_array := unsafe { arrays.carray_to_varray[int](c_int_array, size) } unsafe { C.free(c_int_array) } assert v_int_array.len == size for i, elem in v_int_array { diff --git a/vlib/v/tests/cast_in_comptime_if_test.v b/vlib/v/tests/cast_in_comptime_if_test.v index 7214d3691a..851e3d05d2 100644 --- a/vlib/v/tests/cast_in_comptime_if_test.v +++ b/vlib/v/tests/cast_in_comptime_if_test.v @@ -2,7 +2,7 @@ fn test_cast_in_comptime_if() { generic_bool(true) } -fn generic_bool(val T) { +fn generic_bool[T](val T) { $if T is bool { println(u8(val)) assert u8(val) == 1 diff --git a/vlib/v/tests/checks_for_operator_overrides_should_happen_on_the_concrete_types_when_using_generics_test.v b/vlib/v/tests/checks_for_operator_overrides_should_happen_on_the_concrete_types_when_using_generics_test.v index aad29e0729..cdde2227b1 100644 --- a/vlib/v/tests/checks_for_operator_overrides_should_happen_on_the_concrete_types_when_using_generics_test.v +++ b/vlib/v/tests/checks_for_operator_overrides_should_happen_on_the_concrete_types_when_using_generics_test.v @@ -16,7 +16,7 @@ fn (a Item) == (b Item) bool { // Issue https://github.com/vlang/v/issues/13318 fn test_comparison_operator_override_works_with_generic_datatypes() { - mut heap := datatypes.MinHeap{} + mut heap := datatypes.MinHeap[Item]{} heap.insert(Item{10}) assert heap.peek()?.priority == 10 heap.insert(Item{100}) diff --git a/vlib/v/tests/comptime_field_selector_test.v b/vlib/v/tests/comptime_field_selector_test.v index cd7d8076bd..39695bb622 100644 --- a/vlib/v/tests/comptime_field_selector_test.v +++ b/vlib/v/tests/comptime_field_selector_test.v @@ -5,7 +5,7 @@ mut: name string } -fn comptime_field_selector_read() []string { +fn comptime_field_selector_read[T]() []string { mut t := T{} t.name = '2' t.test = '1' @@ -19,10 +19,10 @@ fn comptime_field_selector_read() []string { } fn test_comptime_field_selector_read() { - assert comptime_field_selector_read() == ['1', '2'] + assert comptime_field_selector_read[Foo]() == ['1', '2'] } -fn comptime_field_selector_write() T { +fn comptime_field_selector_write[T]() T { mut t := T{} $for f in T.fields { $if f.typ is string { @@ -36,7 +36,7 @@ fn comptime_field_selector_write() T { } fn test_comptime_field_selector_write() { - res := comptime_field_selector_write() + res := comptime_field_selector_write[Foo]() assert res.immutable == 1 assert res.test == '1' assert res.name == '1' @@ -46,7 +46,7 @@ struct Foo2 { f Foo } -fn nested_with_parentheses() T { +fn nested_with_parentheses[T]() T { mut t := T{} $for f in T.fields { $if f.typ is Foo { @@ -57,6 +57,6 @@ fn nested_with_parentheses() T { } fn test_nested_with_parentheses() { - res := nested_with_parentheses() + res := nested_with_parentheses[Foo2]() assert res.f.test == '1' } diff --git a/vlib/v/tests/comptime_for_in_field_selector_test.v b/vlib/v/tests/comptime_for_in_field_selector_test.v index f41ea28f3c..00379bb9d4 100644 --- a/vlib/v/tests/comptime_for_in_field_selector_test.v +++ b/vlib/v/tests/comptime_for_in_field_selector_test.v @@ -1,4 +1,4 @@ -fn print_field_values(s T) { +fn print_field_values[T](s T) { mut value_list := []string{} mut value_type_list := []string{} mut var_value_list := []string{} @@ -55,5 +55,5 @@ fn test_comptime_for_in_field_selector() { email: 'simon@gmail.com' age: 15 } - print_field_values(bar) + print_field_values[Foo](bar) } diff --git a/vlib/v/tests/comptime_for_in_field_with_generic_fn_test.v b/vlib/v/tests/comptime_for_in_field_with_generic_fn_test.v index 71bbbcc273..0ba3bb8ecf 100644 --- a/vlib/v/tests/comptime_for_in_field_with_generic_fn_test.v +++ b/vlib/v/tests/comptime_for_in_field_with_generic_fn_test.v @@ -13,7 +13,7 @@ struct Child { age int } -fn inspect(t T) string { +fn inspect[T](t T) string { mut output_str := '' println('${T.name}') $for field in T.fields { diff --git a/vlib/v/tests/comptime_generic_test.v b/vlib/v/tests/comptime_generic_test.v index b19479e032..27d3ba4c33 100644 --- a/vlib/v/tests/comptime_generic_test.v +++ b/vlib/v/tests/comptime_generic_test.v @@ -4,12 +4,12 @@ fn test_comptime_generic() { } [inline] -pub fn func1(t &T) { - func2(t) +pub fn func1[T](t &T) { + func2[T](t) } [inline] -pub fn func2(t &T) { +pub fn func2[T](t &T) { $if T is $Array { unsafe { for i in 0 .. t.len { diff --git a/vlib/v/tests/comptime_if_expr_generic_typ_is_type_test.v b/vlib/v/tests/comptime_if_expr_generic_typ_is_type_test.v index 63d61ff21a..94f8efd909 100644 --- a/vlib/v/tests/comptime_if_expr_generic_typ_is_type_test.v +++ b/vlib/v/tests/comptime_if_expr_generic_typ_is_type_test.v @@ -1,6 +1,6 @@ module main -fn write(out T) string { +fn write[T](out T) string { $if T.typ is bool { println('FOO') return 'FOO' @@ -13,6 +13,6 @@ fn write(out T) string { fn test_comptime_if_expr_generic_typ_is_type() { mut val := false - ret := write(val) + ret := write[bool](val) assert ret == 'FOO' } diff --git a/vlib/v/tests/comptime_if_expr_test.v b/vlib/v/tests/comptime_if_expr_test.v index 93e3d380ae..fff4f61011 100644 --- a/vlib/v/tests/comptime_if_expr_test.v +++ b/vlib/v/tests/comptime_if_expr_test.v @@ -29,7 +29,7 @@ fn test_ct_expressions() { } } -fn generic_t_is() O { +fn generic_t_is[O]() O { $if O is string { return "It's a string!" } $else { @@ -41,11 +41,11 @@ fn generic_t_is() O { struct GenericTIsTest {} fn test_generic_t_is() { - assert generic_t_is() == "It's a string!" - assert generic_t_is() == GenericTIsTest{} + assert generic_t_is[string]() == "It's a string!" + assert generic_t_is[GenericTIsTest]() == GenericTIsTest{} } -fn generic_t_is2() ?T { +fn generic_t_is2[T]() ?T { $if T is string { return "It's a string!" } $else { @@ -54,11 +54,11 @@ fn generic_t_is2() ?T { } fn test_generic_t_is2() { - res := generic_t_is2() or { + res := generic_t_is2[string]() or { assert false '' } - res2 := generic_t_is2() or { + res2 := generic_t_is2[GenericTIsTest]() or { assert false GenericTIsTest{} } @@ -66,7 +66,7 @@ fn test_generic_t_is2() { assert res2 == GenericTIsTest{} } -fn generic_t_is3(raw_data string) ?T { +fn generic_t_is3[T](raw_data string) ?T { $if T is string { return '' } @@ -74,14 +74,14 @@ fn generic_t_is3(raw_data string) ?T { } fn test_generic_t_is3() { - res := generic_t_is3('') or { + res := generic_t_is3[GenericTIsTest]('') or { assert false GenericTIsTest{} } assert res == GenericTIsTest{} } -fn generic_t_is_with_else(raw_data string) ?T { +fn generic_t_is_with_else[T](raw_data string) ?T { $if T is string { return raw_data } $else { @@ -90,19 +90,19 @@ fn generic_t_is_with_else(raw_data string) ?T { } fn test_generic_t_is_with_else() { - res := generic_t_is_with_else('') or { + res := generic_t_is_with_else[GenericTIsTest]('') or { assert false GenericTIsTest{} } assert res == GenericTIsTest{} - str := generic_t_is_with_else('test') or { + str := generic_t_is_with_else[string]('test') or { assert false '' } assert str == 'test' } -fn generic_t_is_with_else_if() []string { +fn generic_t_is_with_else_if[T]() []string { mut fields := []string{} $for field in T.fields { $if field.typ is string { @@ -120,6 +120,6 @@ struct User { } fn test_generic_t_is_with_else_if() { - x := generic_t_is_with_else_if() + x := generic_t_is_with_else_if[User]() assert x == ['name', 'age'] } diff --git a/vlib/v/tests/comptime_if_generic_shift_test.v b/vlib/v/tests/comptime_if_generic_shift_test.v index 8d366ed752..52de5267db 100644 --- a/vlib/v/tests/comptime_if_generic_shift_test.v +++ b/vlib/v/tests/comptime_if_generic_shift_test.v @@ -1,4 +1,4 @@ -fn generic(val T) T { +fn generic[T](val T) T { $if T is u64 { println(val << 1) return val << 1 diff --git a/vlib/v/tests/comptime_if_is_interface_test.v b/vlib/v/tests/comptime_if_is_interface_test.v index 76ceb32f6e..ca50c597c2 100644 --- a/vlib/v/tests/comptime_if_is_interface_test.v +++ b/vlib/v/tests/comptime_if_is_interface_test.v @@ -11,7 +11,7 @@ mut: count u8 } -fn (mut self App) next(input T) string { +fn (mut self App) next[T](input T) string { $if T is Something { return 'Something' } $else $if T is f64 { diff --git a/vlib/v/tests/comptime_if_is_test.v b/vlib/v/tests/comptime_if_is_test.v index 0f2f28f35f..aae291cfa8 100644 --- a/vlib/v/tests/comptime_if_is_test.v +++ b/vlib/v/tests/comptime_if_is_test.v @@ -1,4 +1,4 @@ -fn f() int { +fn f[T]() int { $if T is int { return 1 } @@ -10,11 +10,11 @@ fn f() int { } fn test_generic_is() { - assert f() == 1 - assert f() == -1 + assert f[int]() == 1 + assert f[bool]() == -1 } -fn g(t T) int { +fn g[T](t T) int { $if T is u8 || T is i8 { return 1 } diff --git a/vlib/v/tests/comptime_kinds_test.v b/vlib/v/tests/comptime_kinds_test.v index a581add2f8..f54ad3df12 100644 --- a/vlib/v/tests/comptime_kinds_test.v +++ b/vlib/v/tests/comptime_kinds_test.v @@ -1,4 +1,4 @@ -fn assert_map() { +fn assert_map[T]() { $if T is $Map { assert true } $else { @@ -6,7 +6,7 @@ fn assert_map() { } } -fn assert_array() { +fn assert_array[T]() { $if T is $Array { assert true } $else { @@ -14,7 +14,7 @@ fn assert_array() { } } -fn assert_struct() { +fn assert_struct[T]() { $if T is $Struct { assert true } $else { @@ -22,7 +22,7 @@ fn assert_struct() { } } -fn assert_not_struct() { +fn assert_not_struct[T]() { $if T is $Struct { assert false } $else { @@ -30,7 +30,7 @@ fn assert_not_struct() { } } -fn assert_not_map() { +fn assert_not_map[T]() { $if T is $Map { assert false } $else { @@ -38,7 +38,7 @@ fn assert_not_map() { } } -fn assert_not_array() { +fn assert_not_array[T]() { $if T is $Array { assert false } $else { @@ -53,32 +53,32 @@ struct Bc {} struct Cd {} fn test_kind_map() { - assert_map() - assert_map() - assert_map() + assert_map[map[int]int]() + assert_map[map[string]int]() + assert_map[map[i64]i8]() - assert_not_map() - assert_not_map() - assert_not_map<[]int>() + assert_not_map[Abc]() + assert_not_map[int]() + assert_not_map[[]int]() } fn test_kind_array() { - assert_array<[]int>() - assert_array<[]f32>() - assert_array<[]string>() + assert_array[[]int]() + assert_array[[]f32]() + assert_array[[]string]() - assert_not_array() - assert_not_array() - assert_not_array() - assert_not_array() + assert_not_array[Abc]() + assert_not_array[string]() + assert_not_array[int]() + assert_not_array[map[int]int]() } fn test_kind_struct() { - assert_struct() - assert_struct() - assert_struct() + assert_struct[Abc]() + assert_struct[Bc]() + assert_struct[Cd]() - assert_not_struct() - assert_not_struct<[]int>() - assert_not_struct() + assert_not_struct[int]() + assert_not_struct[[]int]() + assert_not_struct[map[int]int]() } diff --git a/vlib/v/tests/for_in_iterator_of_generic_struct_1_test.v b/vlib/v/tests/for_in_iterator_of_generic_struct_1_test.v index c605370ec1..5a82d8ffb6 100644 --- a/vlib/v/tests/for_in_iterator_of_generic_struct_1_test.v +++ b/vlib/v/tests/for_in_iterator_of_generic_struct_1_test.v @@ -1,11 +1,11 @@ -struct Split { +struct Split[T] { arr []T pred fn (T) bool mut: idx int } -fn (mut iter Split) next() ?[]T { +fn (mut iter Split[T]) next() ?[]T { start := iter.idx for iter.idx < iter.arr.len { if iter.pred(iter.arr[iter.idx]) { @@ -17,13 +17,13 @@ fn (mut iter Split) next() ?[]T { return none } -fn split(arr []T, pred fn (T) bool) Split { - return Split{arr, pred, 0} +fn split[T](arr []T, pred fn (T) bool) Split[T] { + return Split[T]{arr, pred, 0} } fn test_for_in_iterator_of_generic_struct() { items := [0, 1, 2, 3, 4, 5, 6, 7, 8] - mut iter := split(items, fn (item int) bool { + mut iter := split[int](items, fn (item int) bool { return item % 3 == 0 }) iter.next() or {} diff --git a/vlib/v/tests/for_in_iterator_of_generic_struct_2_test.v b/vlib/v/tests/for_in_iterator_of_generic_struct_2_test.v index 511f4f39f7..89f8f795b9 100644 --- a/vlib/v/tests/for_in_iterator_of_generic_struct_2_test.v +++ b/vlib/v/tests/for_in_iterator_of_generic_struct_2_test.v @@ -1,31 +1,31 @@ -pub struct Item { +pub struct Item[V] { pub: value V } -pub struct Iter { +pub struct Iter[V] { arr []V mut: ix int } -pub fn (mut iter Iter) next() ?Item { +pub fn (mut iter Iter[V]) next() ?Item[V] { if iter.ix >= iter.arr.len { return none } val := iter.arr[iter.ix] iter.ix += 1 - return Item{val} + return Item[V]{val} } -fn iterator(arr []V) Iter { - return Iter{arr, 0} +fn iterator[V](arr []V) Iter[V] { + return Iter[V]{arr, 0} } fn test_for_in_iterator_of_generic_struct() { mut ret := []int{} - mut x := iterator([1, 2, 3, 4, 5]) + mut x := iterator[int]([1, 2, 3, 4, 5]) for item in x { println(item.value) ret << item.value diff --git a/vlib/v/tests/for_t_fields_with_comptime_if_test.v b/vlib/v/tests/for_t_fields_with_comptime_if_test.v index 19c9aae362..4879f5369d 100644 --- a/vlib/v/tests/for_t_fields_with_comptime_if_test.v +++ b/vlib/v/tests/for_t_fields_with_comptime_if_test.v @@ -4,7 +4,7 @@ struct Abc { c int } -fn decode() T { +fn decode[T]() T { mut x := T{} $for field in T.fields { $if field.typ is u8 { @@ -20,7 +20,7 @@ fn decode() T { } fn test_decode() { - abc := decode() + abc := decode[Abc]() assert abc.a == 5 assert abc.b == 5 assert abc.c == 3 @@ -32,7 +32,7 @@ struct Abc2 { a_string string } -fn decode2() T { +fn decode2[T]() T { mut x := T{} $for field in T.fields { $if field.typ is u8 { @@ -47,7 +47,7 @@ fn decode2() T { } fn test_decode2() { - abc := decode2() + abc := decode2[Abc2]() assert abc.an_int == -1 assert abc.a_byte == 0xff assert abc.a_string == 'hi' diff --git a/vlib/v/tests/generic_arrays_sum_test.v b/vlib/v/tests/generic_arrays_sum_test.v index f167e3261e..d7523c1768 100644 --- a/vlib/v/tests/generic_arrays_sum_test.v +++ b/vlib/v/tests/generic_arrays_sum_test.v @@ -14,14 +14,14 @@ fn (p1 Point) + (p2 Point) Point { } fn test_generic_arrays_sum() { - ret1 := arrays.sum([Point{ x: 1, y: 1 }, Point{ + ret1 := arrays.sum[Point]([Point{ x: 1, y: 1 }, Point{ x: 2 y: 2 }]) or { Point{} } println(ret1) assert ret1 == Point{3, 3} - ret2 := arrays.sum([1, 2, 3, 4]) or { 0 } + ret2 := arrays.sum[int]([1, 2, 3, 4]) or { 0 } println(ret2) assert ret2 == 10 } diff --git a/vlib/v/tests/generic_chan_test.v b/vlib/v/tests/generic_chan_test.v index a7aaf057d3..fb2a069ccc 100644 --- a/vlib/v/tests/generic_chan_test.v +++ b/vlib/v/tests/generic_chan_test.v @@ -1,4 +1,4 @@ -fn mk_chan(f fn () T) chan T { +fn mk_chan[T](f fn () T) chan T { gench := chan T{cap: 1} // // This does not work, yet // go fn(ch2 chan T, f2 fn() T) { @@ -13,7 +13,7 @@ fn g(x f64, y f64) f64 { } fn test_generic_chan_return() { - ch := mk_chan(fn () f64 { + ch := mk_chan[f64](fn () f64 { return g(3, 4) }) ch <- 13.4 diff --git a/vlib/v/tests/generic_complex_sumtype_test.v b/vlib/v/tests/generic_complex_sumtype_test.v index abd136d1c0..0d6f0fc972 100644 --- a/vlib/v/tests/generic_complex_sumtype_test.v +++ b/vlib/v/tests/generic_complex_sumtype_test.v @@ -1,39 +1,39 @@ struct Empty {} -struct Node { +struct Node[T] { value T - left Tree - right Tree + left Tree[T] + right Tree[T] } -type Tree = Empty | Node +type Tree[T] = Empty | Node[T] // return size(number of nodes) of BST -fn size(tree Tree) int { +fn size[T](tree Tree[T]) int { return match tree { Empty { 0 } - Node { 1 + size(tree.left) + size(tree.right) } + Node[T] { 1 + size[T](tree.left) + size[T](tree.right) } } } // insert a value to BST -fn insert(tree Tree, x T) Tree { +fn insert[T](tree Tree[T], x T) Tree[T] { return match tree { Empty { - Node{x, tree, tree} + Node[T]{x, tree, tree} } - Node { + Node[T] { if x == tree.value { tree } else if x < tree.value { - Node{ + Node[T]{ ...tree - left: insert(tree.left, x) + left: insert[T](tree.left, x) } } else { - Node{ + Node[T]{ ...tree - right: insert(tree.right, x) + right: insert[T](tree.right, x) } } } @@ -41,80 +41,80 @@ fn insert(tree Tree, x T) Tree { } // whether able to find a value in BST -fn search(tree Tree, x T) bool { +fn search[T](tree Tree[T], x T) bool { return match tree { Empty { false } - Node { + Node[T] { if x == tree.value { true } else if x < tree.value { - search(tree.left, x) + search[T](tree.left, x) } else { - search(tree.right, x) + search[T](tree.right, x) } } } } // find the minimal value of a BST -fn min(tree Tree) T { +fn min[T](tree Tree[T]) T { return match tree { Empty { 1e100 } - Node { - if tree.value < min(tree.left) { + Node[T] { + if tree.value < min[T](tree.left) { tree.value } else { - min(tree.left) + min[T](tree.left) } } } } // delete a value in BST (if nonexistant do nothing) -fn delete(tree Tree, x T) Tree { +fn delete[T](tree Tree[T], x T) Tree[T] { return match tree { Empty { tree } - Node { - if tree.left is Node && tree.right is Node { + Node[T] { + if tree.left is Node[T] && tree.right is Node[T] { if x < tree.value { - Node{ + Node[T]{ ...tree - left: delete(tree.left, x) + left: delete[T](tree.left, x) } } else if x > tree.value { - Node{ + Node[T]{ ...tree - right: delete(tree.right, x) + right: delete[T](tree.right, x) } } else { - Node{ + Node[T]{ ...tree - value: min(tree.right) - right: delete(tree.right, min(tree.right)) + value: min[T](tree.right) + right: delete[T](tree.right, min[T](tree.right)) } } - } else if tree.left is Node { + } else if tree.left is Node[T] { if x == tree.value { tree.left } else { - Node{ + Node[T]{ ...tree - left: delete(tree.left, x) + left: delete[T](tree.left, x) } } } else { if x == tree.value { tree.right } else { - Node{ + Node[T]{ ...tree - right: delete(tree.right, x) + right: delete[T](tree.right, x) } } } @@ -123,7 +123,7 @@ fn delete(tree Tree, x T) Tree { } fn test_generics_complex_sumtype() { - mut tree := Tree(Empty{}) + mut tree := Tree[f64](Empty{}) input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7] for i in input { tree = insert(tree, i) diff --git a/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v b/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v index 1dd408b15d..d3aa7d6332 100644 --- a/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v +++ b/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v @@ -13,7 +13,7 @@ struct Container { concrete_b Any } -fn cast_struct(any_struct Any) &T { +fn cast_struct[T](any_struct Any) &T { if any_struct is T { return any_struct } @@ -21,8 +21,8 @@ fn cast_struct(any_struct Any) &T { } fn test_generic_empty_interface_to_multi_struct() { - concrete_a := cast_struct(ConcreteA{12345}) - concrete_b := cast_struct(ConcreteB{54321}) + concrete_a := cast_struct[ConcreteA](ConcreteA{12345}) + concrete_b := cast_struct[ConcreteB](ConcreteB{54321}) println(concrete_a.a) println(concrete_b.b) assert concrete_a.a == 12345 diff --git a/vlib/v/tests/generic_empty_interface_to_struct_test.v b/vlib/v/tests/generic_empty_interface_to_struct_test.v index 783da30bbe..c6792151bd 100644 --- a/vlib/v/tests/generic_empty_interface_to_struct_test.v +++ b/vlib/v/tests/generic_empty_interface_to_struct_test.v @@ -8,7 +8,7 @@ struct Container { concrete Any } -fn (container &Container) get_first_struct() ?&T { +fn (container &Container) get_first_struct[T]() ?&T { concrete := container.concrete if concrete is T { println(concrete.a) @@ -20,6 +20,6 @@ fn (container &Container) get_first_struct() ?&T { fn test_generic_empty_interface_to_struct() { concrete := Concrete{12345} container := Container{concrete} - cast_concrete := container.get_first_struct() or { &Concrete{} } + cast_concrete := container.get_first_struct[Concrete]() or { &Concrete{} } assert 12345 == cast_concrete.a } diff --git a/vlib/v/tests/generic_fn_assign_generics_struct_test.v b/vlib/v/tests/generic_fn_assign_generics_struct_test.v index 0239f59fc8..590dea4329 100644 --- a/vlib/v/tests/generic_fn_assign_generics_struct_test.v +++ b/vlib/v/tests/generic_fn_assign_generics_struct_test.v @@ -1,9 +1,9 @@ -struct Test { +struct Test[T] { v T } -fn get_test(v T) Test { - return Test{ +fn get_test[T](v T) Test[T] { + return Test[T]{ v: v } } @@ -27,38 +27,38 @@ fn test_generics_assign_generics_struct() { } // test generics assign generics struct_init -struct Node { +struct Node[T] { pub mut: val T - next &Node = 0 + next &Node[T] = 0 } -fn new() &Node { - return &Node{} +fn new[T]() &Node[T] { + return &Node[T]{} } -fn (mut n Node) add(val T) { - node := &Node{val, 0} +fn (mut n Node[T]) add(val T) { + node := &Node[T]{val, 0} n.next = node } fn test_generic_fn_assign_generic_struct_init() { - mut list1 := new() + mut list1 := new[int]() list1.add(100) println(list1.next) assert list1.next.val == 100 - mut list2 := new() + mut list2 := new[f64]() list2.add(2.22) println(list2.next) assert list2.next.val == 2.22 - mut list3 := new() + mut list3 := new[bool]() list3.add(false) println(list3.next) assert list3.next.val == false - mut list4 := new() + mut list4 := new[string]() list4.add('aaa') println(list4.next) assert list4.next.val == 'aaa' diff --git a/vlib/v/tests/generic_fn_call_with_reference_argument_test.v b/vlib/v/tests/generic_fn_call_with_reference_argument_test.v index bc62ee4e56..161d4e16fb 100644 --- a/vlib/v/tests/generic_fn_call_with_reference_argument_test.v +++ b/vlib/v/tests/generic_fn_call_with_reference_argument_test.v @@ -1,12 +1,12 @@ -struct Type { +struct Type[T] { value T } -struct ContainerType { - typ &Type +struct ContainerType[T] { + typ &Type[T] } -fn (instance &ContainerType) contains(typ &Type) bool { +fn (instance &ContainerType[T]) contains(typ &Type[T]) bool { println(typ) if instance.typ == typ { return true @@ -16,8 +16,8 @@ fn (instance &ContainerType) contains(typ &Type) bool { } fn test_generic_fn_call_with_reference_argument() { - con := ContainerType{ - typ: &Type{0} + con := ContainerType[int]{ + typ: &Type[int]{0} } ret := con.contains(con.typ) println(con) diff --git a/vlib/v/tests/generic_fn_cast_to_alias_test.v b/vlib/v/tests/generic_fn_cast_to_alias_test.v index af3db1e529..3c082902b1 100644 --- a/vlib/v/tests/generic_fn_cast_to_alias_test.v +++ b/vlib/v/tests/generic_fn_cast_to_alias_test.v @@ -2,12 +2,12 @@ module main type VkPresentModeKHR = u32 -fn create_c_array(len u32) &T { +fn create_c_array[T](len u32) &T { return unsafe { &T(malloc(int(sizeof(T) * len))) } } fn test_generic_fn_cast_to_alias() { - arr_vk := create_c_array(5) + arr_vk := create_c_array[VkPresentModeKHR](5) println(typeof(arr_vk).name) assert typeof(arr_vk).name == '&VkPresentModeKHR' diff --git a/vlib/v/tests/generic_fn_infer_fixed_array_test.v b/vlib/v/tests/generic_fn_infer_fixed_array_test.v index 3174b105da..f2d6c7db48 100644 --- a/vlib/v/tests/generic_fn_infer_fixed_array_test.v +++ b/vlib/v/tests/generic_fn_infer_fixed_array_test.v @@ -1,4 +1,4 @@ -fn get_element(arr [3]T) string { +fn get_element[T](arr [3]T) string { return '${arr[1]}' } diff --git a/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v b/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v index 2b121f7b71..c82cc6627a 100644 --- a/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v +++ b/vlib/v/tests/generic_fn_infer_fn_type_argument_test.v @@ -26,6 +26,6 @@ fn test_generic_fn_infer_fn_type_argument() { } // [noah04 #14214] code -fn fmap(func fn (I) O, list []I) []O { +fn fmap[I, O](func fn (I) O, list []I) []O { return []O{len: list.len, init: func(list[it])} } diff --git a/vlib/v/tests/generic_fn_infer_fn_type_using_ref_arg_test.v b/vlib/v/tests/generic_fn_infer_fn_type_using_ref_arg_test.v index a809d45b00..f6ec501b2b 100644 --- a/vlib/v/tests/generic_fn_infer_fn_type_using_ref_arg_test.v +++ b/vlib/v/tests/generic_fn_infer_fn_type_using_ref_arg_test.v @@ -5,7 +5,7 @@ fn test_generic_fn_infer_fn_type_using_ref_arg() { assert ret } -fn call_generic_fn(cb fn (&T) bool, input T) bool { +fn call_generic_fn[T](cb fn (&T) bool, input T) bool { dump(cb(&input)) ret := cb(&input) return ret diff --git a/vlib/v/tests/generic_fn_infer_map_test.v b/vlib/v/tests/generic_fn_infer_map_test.v index 7da684a958..069fc7d296 100644 --- a/vlib/v/tests/generic_fn_infer_map_test.v +++ b/vlib/v/tests/generic_fn_infer_map_test.v @@ -1,4 +1,4 @@ -fn print_map(x map[K]V) string { +fn print_map[K, V](x map[K]V) string { println(x) return '${x}' } diff --git a/vlib/v/tests/generic_fn_infer_modifier_test.v b/vlib/v/tests/generic_fn_infer_modifier_test.v index 0901aa3476..9ac2987a7d 100644 --- a/vlib/v/tests/generic_fn_infer_modifier_test.v +++ b/vlib/v/tests/generic_fn_infer_modifier_test.v @@ -1,8 +1,8 @@ -fn f_array(a []T) T { +fn f_array[T](a []T) T { return a[0] } -fn g_array(mut a []T) { +fn g_array[T](mut a []T) { a[0] = a[1] } diff --git a/vlib/v/tests/generic_fn_infer_multi_paras_test.v b/vlib/v/tests/generic_fn_infer_multi_paras_test.v index 8b63fedd2a..1d82a01402 100644 --- a/vlib/v/tests/generic_fn_infer_multi_paras_test.v +++ b/vlib/v/tests/generic_fn_infer_multi_paras_test.v @@ -13,7 +13,7 @@ pub mut: var_three Two_data } -fn get_keys_and_values(mut keys []string, mut values []string, mut data T) ([]string, []string, T) { +fn get_keys_and_values[T](mut keys []string, mut values []string, mut data T) ([]string, []string, T) { $for field in T.fields { $if field.typ is string { keys << field.name @@ -23,7 +23,7 @@ fn get_keys_and_values(mut keys []string, mut values []string, mut data T) ([ return keys, values, data } -fn awesome(mut data T) { +fn awesome[T](mut data T) { mut keys := []string{} mut values := []string{} keys, values, data = get_keys_and_values(mut keys, mut values, mut data) diff --git a/vlib/v/tests/generic_fn_infer_nested_generic_fn_test.v b/vlib/v/tests/generic_fn_infer_nested_generic_fn_test.v index 927ec5062a..3445ccf25d 100644 --- a/vlib/v/tests/generic_fn_infer_nested_generic_fn_test.v +++ b/vlib/v/tests/generic_fn_infer_nested_generic_fn_test.v @@ -9,10 +9,10 @@ fn test_generics_fn_infer_nested_generic_fn() { } fn load_item_spawns(mut spawns []ItemSpawn) { - walk('./data/items/spawns/', mut spawns) + walk[ItemSpawn]('./data/items/spawns/', mut spawns) } -fn parse_json(file string, mut array []T) { +fn parse_json[T](file string, mut array []T) { data := os.read_file(file) or { panic('error reading file ${file}') return @@ -26,7 +26,7 @@ fn parse_json(file string, mut array []T) { } } -fn walk(path string, mut array []T) { +fn walk[T](path string, mut array []T) { if !os.is_dir(path) { return } diff --git a/vlib/v/tests/generic_fn_infer_nested_struct_test.v b/vlib/v/tests/generic_fn_infer_nested_struct_test.v index 19de4a4227..08574df976 100644 --- a/vlib/v/tests/generic_fn_infer_nested_struct_test.v +++ b/vlib/v/tests/generic_fn_infer_nested_struct_test.v @@ -1,19 +1,19 @@ -struct Item { +struct Item[T] { value T } -fn (i Item) unwrap() T { +fn (i Item[T]) unwrap() T { return i.value } -fn process(i Item) { +fn process[T](i Item[T]) { n := i.unwrap() println(n) assert n == 5 } fn test_generic_fn_infer_nested_struct() { - item := Item{ + item := Item[int]{ value: 5 } process(item) diff --git a/vlib/v/tests/generic_fn_infer_struct_test.v b/vlib/v/tests/generic_fn_infer_struct_test.v index ec32f301a6..8eda263b43 100644 --- a/vlib/v/tests/generic_fn_infer_struct_test.v +++ b/vlib/v/tests/generic_fn_infer_struct_test.v @@ -1,19 +1,19 @@ -struct Node { +struct Node[T] { data T } -fn foo(n Node) string { +fn foo[T](n Node[T]) string { return '${n}' } fn test_generics_fn_infer_struct() { - ret1 := foo(Node{}) + ret1 := foo(Node[int]{}) println(ret1) - assert ret1.contains('Node{') + assert ret1.contains('Node[int]{') assert ret1.contains('data: 0') - ret2 := foo(Node{}) + ret2 := foo(Node[u8]{}) println(ret2) - assert ret2.contains('Node{') + assert ret2.contains('Node[u8]{') assert ret2.contains('data: 0') } diff --git a/vlib/v/tests/generic_fn_infer_test.v b/vlib/v/tests/generic_fn_infer_test.v index dd040cc8c2..768bd81205 100644 --- a/vlib/v/tests/generic_fn_infer_test.v +++ b/vlib/v/tests/generic_fn_infer_test.v @@ -1,7 +1,7 @@ -fn call(v T) { +fn call[T](v T) { } -fn simple(p T) T { +fn simple[T](p T) T { return p } @@ -13,13 +13,13 @@ fn test_infer() { } fn test_explicit_calls_should_also_work() { - call(2) + call[int](2) assert true - simple(5) + simple[int](5) assert true } -fn get_type_name(x T) string { +fn get_type_name[T](x T) string { return T.name } @@ -29,7 +29,7 @@ fn test_literal() { } // -fn choose4(a T, b T, c T, d T) T { +fn choose4[T](a T, b T, c T, d T) T { // Note: a similar construct is used in prime31's via engine return a } @@ -37,6 +37,6 @@ fn choose4(a T, b T, c T, d T) T { fn test_calling_generic_fn_with_many_params() { x := choose4(1, 2, 3, 4) assert x == 1 - y := choose4('abc', 'xyz', 'def', 'ghi') + y := choose4[string]('abc', 'xyz', 'def', 'ghi') assert y == 'abc' } diff --git a/vlib/v/tests/generic_fn_infer_variadic_test.v b/vlib/v/tests/generic_fn_infer_variadic_test.v index 01c4e4e3e3..5e6f7f8b5b 100644 --- a/vlib/v/tests/generic_fn_infer_variadic_test.v +++ b/vlib/v/tests/generic_fn_infer_variadic_test.v @@ -1,4 +1,4 @@ -fn generic(items ...T) string { +fn generic[T](items ...T) string { return '${items}' } diff --git a/vlib/v/tests/generic_fn_multi_return_test.v b/vlib/v/tests/generic_fn_multi_return_test.v index 02f8f50301..1fcff007b7 100644 --- a/vlib/v/tests/generic_fn_multi_return_test.v +++ b/vlib/v/tests/generic_fn_multi_return_test.v @@ -1,5 +1,5 @@ fn test_generic_fn_multi_return() { - mut a1 := GenRef{32, 99} + mut a1 := GenRef[u32, u32]{32, 99} b1, c1 := a1.generic_reference() or { assert false return @@ -9,7 +9,7 @@ fn test_generic_fn_multi_return() { println(c1) assert *c1 == 99 - mut a2 := GenRef{322, 999} + mut a2 := GenRef[u64, u64]{322, 999} b2, c2 := a2.generic_reference() or { assert false return @@ -19,7 +19,7 @@ fn test_generic_fn_multi_return() { println(c2) assert *c2 == 999 - mut a3 := GenRef{22, 77} + mut a3 := GenRef[i32, u64]{22, 77} b3, c3 := a3.generic_reference() or { assert false return @@ -29,7 +29,7 @@ fn test_generic_fn_multi_return() { println(c3) assert *c3 == 77 - mut a4 := GenRef{2.2, 777} + mut a4 := GenRef[f64, u64]{2.2, 777} b4, c4 := a4.generic_reference() or { assert false return @@ -40,12 +40,12 @@ fn test_generic_fn_multi_return() { assert *c4 == 777 } -struct GenRef { +struct GenRef[K, V] { key K val V } -fn (mut self GenRef) generic_reference() ?(K, &V) { +fn (mut self GenRef[K, V]) generic_reference() ?(K, &V) { if false { return none } diff --git a/vlib/v/tests/generic_fn_returning_type_with_T_test.v b/vlib/v/tests/generic_fn_returning_type_with_T_test.v index 4f6c6c35fd..1a23d48a63 100644 --- a/vlib/v/tests/generic_fn_returning_type_with_T_test.v +++ b/vlib/v/tests/generic_fn_returning_type_with_T_test.v @@ -6,7 +6,7 @@ struct Tensor { x int } -fn new_tensor(data BuildData) Tensor { +fn new_tensor[T](data BuildData) Tensor { println('data: ${data}') x := T(data.x) println(x) @@ -14,12 +14,12 @@ fn new_tensor(data BuildData) Tensor { } fn test_generic_function_returning_type_starting_with_t() { - ft := new_tensor(x: 123) + ft := new_tensor[f64](x: 123) println(ft) assert typeof(ft).name == 'Tensor' assert '${ft}' == 'Tensor{\n x: 123\n}' // - it := new_tensor(x: 456) + it := new_tensor[int](x: 456) println(it) assert typeof(it).name == 'Tensor' assert '${it}' == 'Tensor{\n x: 456\n}' @@ -27,14 +27,14 @@ fn test_generic_function_returning_type_starting_with_t() { // the following verifies that returning a generic type T // works at the same time as returning a type starting with T -fn new_t(o T) T { +fn new_t[T](o T) T { x := T(o) return x } fn test_generic_function_returning_t_type() { - f := new_t(1.23) - i := new_t(456) + f := new_t[f64](1.23) + i := new_t[int](456) assert '${f}' == '1.23' assert '${i}' == '456' } diff --git a/vlib/v/tests/generic_fn_typeof_name_test.v b/vlib/v/tests/generic_fn_typeof_name_test.v index 93b08e09b6..d47d6140f9 100644 --- a/vlib/v/tests/generic_fn_typeof_name_test.v +++ b/vlib/v/tests/generic_fn_typeof_name_test.v @@ -1,6 +1,6 @@ struct Client {} -fn add_handler(handler fn (mut Client, T)) string { +fn add_handler[T](handler fn (mut Client, T)) string { return typeof(handler).name } @@ -9,7 +9,7 @@ fn on_message(mut client Client, event string) { } fn test_generics_fn_typeof_name() { - ret := add_handler(on_message) + ret := add_handler[string](on_message) println(ret) assert ret == 'fn (mut Client, string)' } @@ -19,42 +19,42 @@ struct Test1 {} struct Test2 {} -fn print_type() string { +fn print_type[T]() string { name := T.name println(name) return name } fn test_no_paras_generics_fn_typeof_name() { - mut ret := print_type() + mut ret := print_type[Test1]() assert ret == 'Test1' - ret = print_type() + ret = print_type[Test2]() assert ret == 'Test2' - ret = print_type() + ret = print_type[int]() assert ret == 'int' - ret = print_type() + ret = print_type[f32]() assert ret == 'f32' - ret = print_type() + ret = print_type[bool]() assert ret == 'bool' } // test generic method receiver typeof name -struct Num { +struct Num[T] { num T } -fn (num Num) test(v T) { +fn (num Num[T]) test(v T) { println(typeof(num).name) - assert typeof(num).name == 'Num' + assert typeof(num).name == 'Num[int]' println(typeof(v).name) assert typeof(v).name == 'int' } fn test_generic_method_receiver_typeof_name() { - num := Num{3} + num := Num[int]{3} num.test(100) } diff --git a/vlib/v/tests/generic_fn_upper_name_type_test.v b/vlib/v/tests/generic_fn_upper_name_type_test.v index c2da577386..f15192dcc5 100644 --- a/vlib/v/tests/generic_fn_upper_name_type_test.v +++ b/vlib/v/tests/generic_fn_upper_name_type_test.v @@ -6,13 +6,13 @@ struct YY { y int } -fn show_result(x T, y U) bool { +fn show_result[T, U](x T, y U) bool { return true } fn test_generic_fn_upper_name_type() { - assert show_result(1, false) - assert show_result('s', XX{}) - assert show_result(XX{}, 's') - assert show_result(XX{}, YY{}) + assert show_result[int, bool](1, false) + assert show_result[string, XX]('s', XX{}) + assert show_result[XX, string](XX{}, 's') + assert show_result[XX, YY](XX{}, YY{}) } diff --git a/vlib/v/tests/generic_fn_using_generic_type_in_if_test.v b/vlib/v/tests/generic_fn_using_generic_type_in_if_test.v index bd316fa934..dab635ee63 100644 --- a/vlib/v/tests/generic_fn_using_generic_type_in_if_test.v +++ b/vlib/v/tests/generic_fn_using_generic_type_in_if_test.v @@ -3,7 +3,7 @@ fn test_generic_fn_using_generic_type_in_if() { assert ret == 'true' } -fn generic_bool(val T) string { +fn generic_bool[T](val T) string { $if T is bool { if val { println('is true') diff --git a/vlib/v/tests/generic_fn_with_anon_fn_test.v b/vlib/v/tests/generic_fn_with_anon_fn_test.v index ef43c07aef..c0de6cef15 100644 --- a/vlib/v/tests/generic_fn_with_anon_fn_test.v +++ b/vlib/v/tests/generic_fn_with_anon_fn_test.v @@ -1,4 +1,4 @@ -fn foo() string { +fn foo[T]() string { x := fn () string { return 'ok' } @@ -6,6 +6,6 @@ fn foo() string { } fn test_generic_fn_with_anon_fn() { - ret := foo() + ret := foo[int]() assert ret == 'ok' } diff --git a/vlib/v/tests/generic_fn_with_comptime_for_test.v b/vlib/v/tests/generic_fn_with_comptime_for_test.v index 17a9cb7aca..6ab7c20d15 100644 --- a/vlib/v/tests/generic_fn_with_comptime_for_test.v +++ b/vlib/v/tests/generic_fn_with_comptime_for_test.v @@ -1,4 +1,4 @@ -fn fn_a(data T, depth int, nl bool) { +fn fn_a[T](data T, depth int, nl bool) { for _ in 0 .. depth { print('\t') } diff --git a/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v b/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v index c75f4a338e..398c7fef5a 100644 --- a/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v +++ b/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v @@ -1,10 +1,10 @@ -pub struct EncodeOptions { +pub struct EncodeOptions[T] { payload T key string algorithm string = 'HS256' } -pub fn encode(options EncodeOptions) !string { +pub fn encode[T](options EncodeOptions[T]) !string { return 'test' } diff --git a/vlib/v/tests/generic_functions_with_normal_function_test.v b/vlib/v/tests/generic_functions_with_normal_function_test.v index aa1543df13..86939e6cc5 100644 --- a/vlib/v/tests/generic_functions_with_normal_function_test.v +++ b/vlib/v/tests/generic_functions_with_normal_function_test.v @@ -1,4 +1,4 @@ -fn get(typ T) T { +fn get[T](typ T) T { return typ } @@ -8,5 +8,5 @@ fn get_string(typ string) string { fn test_generic_with_same_type() { assert get_string('') == 'boom' - assert get('hello') == 'hello' + assert get[string]('hello') == 'hello' } diff --git a/vlib/v/tests/generic_interface_infer_test.v b/vlib/v/tests/generic_interface_infer_test.v index 75300da280..82fc997554 100644 --- a/vlib/v/tests/generic_interface_infer_test.v +++ b/vlib/v/tests/generic_interface_infer_test.v @@ -1,20 +1,20 @@ -struct Struct { +struct Struct[T] { value int x T } -fn (s Struct) method() T { +fn (s Struct[T]) method() T { return s.x + s.x } -interface Interface { +interface Interface[T] { method() T } fn test_infer_generic_interface() { - s := Struct{7, 5} + s := Struct[u32]{7, 5} println(s) - i := Interface(s) + i := Interface[u32](s) println(i) assert i.method() == 10 } diff --git a/vlib/v/tests/generic_interface_test.v b/vlib/v/tests/generic_interface_test.v index 05a0723a85..a11871c6da 100644 --- a/vlib/v/tests/generic_interface_test.v +++ b/vlib/v/tests/generic_interface_test.v @@ -1,43 +1,43 @@ -interface Gettable { +interface Gettable[T] { get() T } -struct Animal { +struct Animal[T] { metadata T } -fn (a Animal) get() T { +fn (a Animal[T]) get[T]() T { return a.metadata } // different struct implementing the same interface: -struct Mineral { +struct Mineral[T] { value T } -fn (m Mineral) get() T { +fn (m Mineral[T]) get[T]() T { return m.value } //// -fn extract(xs []Gettable) []T { +fn extract[T](xs []Gettable[T]) []T { return xs.map(it.get()) } -fn extract_basic(xs Gettable) T { +fn extract_basic[T](xs Gettable[T]) T { return xs.get() } fn test_extract() { - a := Animal{123} - b := Animal{456} - c := Mineral{789} + a := Animal[int]{123} + b := Animal[int]{456} + c := Mineral[int]{789} - arr := [Gettable(a), Gettable(b), Gettable(c)] - assert typeof(arr).name == '[]Gettable' + arr := [Gettable[int](a), Gettable[int](b), Gettable[int](c)] + assert typeof(arr).name == '[]Gettable[int]' - x := extract(arr) + x := extract[int](arr) assert x == [123, 456, 789] } @@ -54,9 +54,9 @@ fn test_extract() { // } fn test_extract_basic() { - a := Animal{123} - b := Animal{456} - c := Mineral{789} + a := Animal[int]{123} + b := Animal[int]{456} + c := Mineral[int]{789} aa := extract_basic(a) bb := extract_basic(b) @@ -65,18 +65,18 @@ fn test_extract_basic() { } ////// -interface Iterator { +interface Iterator[T] { mut: next() ?T } -struct NumberIterator { +struct NumberIterator[T] { limit T mut: val T } -fn (mut i NumberIterator) next() ?T { +fn (mut i NumberIterator[T]) next[T]() ?T { if i.val >= i.limit { return none } @@ -85,7 +85,7 @@ fn (mut i NumberIterator) next() ?T { } fn test_iterator_implementation() { - mut i := Iterator(NumberIterator{ + mut i := Iterator[int](NumberIterator[int]{ limit: 10 }) for { diff --git a/vlib/v/tests/generic_method_with_variadic_generic_args_test.v b/vlib/v/tests/generic_method_with_variadic_generic_args_test.v index 492a698523..762c1e6bb6 100644 --- a/vlib/v/tests/generic_method_with_variadic_generic_args_test.v +++ b/vlib/v/tests/generic_method_with_variadic_generic_args_test.v @@ -1,16 +1,16 @@ -struct Foo { +struct Foo[T] { mut: arr []T } -fn (mut foo Foo) push(items ...T) { +fn (mut foo Foo[T]) push[T](items ...T) { for item in items { foo.arr << item } } fn test_generic_method_with_variadic_args() { - mut f := Foo{} + mut f := Foo[int]{} f.push(1, 2, 3, 5, 8, 13, 21, 34, 55) println(f.arr) assert f.arr == [1, 2, 3, 5, 8, 13, 21, 34, 55] diff --git a/vlib/v/tests/generic_operator_overload_test.v b/vlib/v/tests/generic_operator_overload_test.v index 8395c0184e..5ac303e4e7 100644 --- a/vlib/v/tests/generic_operator_overload_test.v +++ b/vlib/v/tests/generic_operator_overload_test.v @@ -1,19 +1,19 @@ -struct Matrix { +struct Matrix[T] { row int col int mut: data [][]T } -fn from_array(arr [][]T) Matrix { - return Matrix{ +fn from_array[T](arr [][]T) Matrix[T] { + return Matrix[T]{ row: arr.len col: arr[0].len data: arr.clone() } } -fn (m1 Matrix) + (m2 Matrix) Matrix { +fn (m1 Matrix[T]) + (m2 Matrix[T]) Matrix[T] { if m1.row != m2.row || m1.col != m2.col { panic('Addition can only be performed on matrix with same size') } @@ -26,11 +26,11 @@ fn (m1 Matrix) + (m2 Matrix) Matrix { return res } -fn (m1 Matrix) == (m2 Matrix) bool { +fn (m1 Matrix[T]) == (m2 Matrix[T]) bool { return m1.row == m2.row && m1.col == m2.col && m1.data == m2.data } -fn (m1 Matrix) < (m2 Matrix) bool { +fn (m1 Matrix[T]) < (m2 Matrix[T]) bool { return m1.row < m2.row && m1.col < m2.col } diff --git a/vlib/v/tests/generic_struct_init_with_generic_cast_test.v b/vlib/v/tests/generic_struct_init_with_generic_cast_test.v index 14b6036943..bcaae56dcd 100644 --- a/vlib/v/tests/generic_struct_init_with_generic_cast_test.v +++ b/vlib/v/tests/generic_struct_init_with_generic_cast_test.v @@ -1,4 +1,4 @@ -pub struct Range { +pub struct Range[T] { start T end T [required] step T = T(1) @@ -7,12 +7,12 @@ mut: } fn test_generic_struct_init_with_generic_cast() { - r1 := Range{ + r1 := Range[int]{ end: 10 } println(r1) - r2 := Range{ + r2 := Range[f64]{ end: 2.2 } println(r2) diff --git a/vlib/v/tests/generic_sumtype_cast_test.v b/vlib/v/tests/generic_sumtype_cast_test.v index b52b9a175a..6703502795 100644 --- a/vlib/v/tests/generic_sumtype_cast_test.v +++ b/vlib/v/tests/generic_sumtype_cast_test.v @@ -2,49 +2,49 @@ module main struct Empty {} -struct Node { +struct Node[T] { value T mut: - next Tree + next Tree[T] } -type Tree = Empty | Node +type Tree[T] = Empty | Node[T] -fn create() Tree { +fn create[T]() Tree[T] { empty := Empty{} - mut curr := Node{10, empty} + mut curr := Node[T]{10, empty} for _ in 0 .. 10 { - curr.next = Node{20, empty} + curr.next = Node[T]{20, empty} } return curr } -fn create_node(args []T) Tree { +fn create_node[T](args []T) Tree[T] { empty := Empty{} if args.len == 0 { return empty } - mut curr := Node{args[0], empty} + mut curr := Node[T]{args[0], empty} for i := 1; i < args.len; i += 1 { - curr.next = Node{args[i], empty} - curr = curr.next as Node + curr.next = Node[T]{args[i], empty} + curr = curr.next as Node[T] } return curr } -fn merge_nodes(head Tree) Tree { +fn merge_nodes[T](head Tree[T]) Tree[T] { println('${head}') return Empty{} } fn test_generic_sumtype_cast() { - node := create_node([0, 3, 1, 0, 4, 5, 2, 0]) + node := create_node[int]([0, 3, 1, 0, 4, 5, 2, 0]) merge_nodes(node) - create() + create[int]() assert true } diff --git a/vlib/v/tests/generic_sumtype_init_in_generic_fn_call_test.v b/vlib/v/tests/generic_sumtype_init_in_generic_fn_call_test.v index d95410cf5d..c488ffd3ad 100644 --- a/vlib/v/tests/generic_sumtype_init_in_generic_fn_call_test.v +++ b/vlib/v/tests/generic_sumtype_init_in_generic_fn_call_test.v @@ -1,8 +1,8 @@ -pub type Result = Ok | string +pub type Result[S] = Ok[S] | string -pub fn (x Result) unwrap() ?S { +pub fn (x Result[S]) unwrap[S]() ?S { match x { - Ok { + Ok[S] { return x.value } string { @@ -11,16 +11,16 @@ pub fn (x Result) unwrap() ?S { } } -struct Ok { +struct Ok[S] { value S } -pub fn ok(value S) Result { - return Ok{value} +pub fn ok[S](value S) Result[S] { + return Ok[S]{value} } fn test_generic_symtype_init_in_generic_fn_call() { - x := ok(42) + x := ok[int](42) ret := x.unwrap() or { 0 } println(ret) diff --git a/vlib/v/tests/generic_sumtype_insts_test.v b/vlib/v/tests/generic_sumtype_insts_test.v index 49e890ed55..c31e9126fa 100644 --- a/vlib/v/tests/generic_sumtype_insts_test.v +++ b/vlib/v/tests/generic_sumtype_insts_test.v @@ -1,16 +1,16 @@ -struct Foo { +struct Foo[T] { x T } -struct Bar { +struct Bar[T] { x T } -type MyType = Bar | Foo +type MyType[T] = Bar[T] | Foo[T] fn test_generic_sumtype_insts() { - f := Foo{'hi'} - t := MyType(f) + f := Foo[string]{'hi'} + t := MyType[string](f) println(t.type_name()) - assert t.type_name() == 'Foo' + assert t.type_name() == 'Foo[string]' } diff --git a/vlib/v/tests/generic_sumtype_method_test.v b/vlib/v/tests/generic_sumtype_method_test.v index 1e564a1d76..576690a667 100644 --- a/vlib/v/tests/generic_sumtype_method_test.v +++ b/vlib/v/tests/generic_sumtype_method_test.v @@ -1,28 +1,28 @@ struct Empty {} -struct Node { +struct Node[T] { value T - left Leaf - right Leaf + left Leaf[T] + right Leaf[T] } -type Leaf = Empty | Node +type Leaf[T] = Empty | Node[T] // return size(number of nodes) of BST -fn (leaf Leaf) size() int { +fn (leaf Leaf[T]) size[T]() int { return match leaf { Empty { 0 } - Node { 1 + leaf.left.size() + leaf.right.size() } + Node[T] { 1 + leaf.left.size() + leaf.right.size() } } } fn test_generic_sumtype_method() { - r := Node{ + r := Node[int]{ value: 20 left: Empty{} right: Empty{} } - tree := Leaf(Node{ + tree := Leaf[int](Node[int]{ value: 10 left: Empty{} right: r diff --git a/vlib/v/tests/generic_sumtype_of_alias_generic_struct_test.v b/vlib/v/tests/generic_sumtype_of_alias_generic_struct_test.v index a1a95af070..e8764ff89b 100644 --- a/vlib/v/tests/generic_sumtype_of_alias_generic_struct_test.v +++ b/vlib/v/tests/generic_sumtype_of_alias_generic_struct_test.v @@ -2,19 +2,19 @@ struct Shared { val int } -struct AA { +struct AA[T] { Shared } -type AAint = AA -type AAbool = AA +type AAint = AA[int] +type AAbool = AA[bool] -struct BB { +struct BB[T] { Shared } -type BBint = BB -type BBbool = BB +type BBint = BB[int] +type BBbool = BB[bool] type CC = AAbool | AAint | BBbool | BBint diff --git a/vlib/v/tests/generic_sumtype_str_test.v b/vlib/v/tests/generic_sumtype_str_test.v index 4627550bca..c952c6da6d 100644 --- a/vlib/v/tests/generic_sumtype_str_test.v +++ b/vlib/v/tests/generic_sumtype_str_test.v @@ -2,9 +2,9 @@ module main struct None {} -pub type Maybe = None | T +pub type Maybe[T] = None | T -pub fn (m Maybe) str() string { +pub fn (m Maybe[T]) str[T]() string { return if m is T { x := m as T 'Some(${x})' @@ -13,8 +13,8 @@ pub fn (m Maybe) str() string { } } -pub fn some(v T) Maybe { - return Maybe(v) +pub fn some[T](v T) Maybe[T] { + return Maybe[T](v) } fn test_generic_sumtype_str() { diff --git a/vlib/v/tests/generic_sumtype_test.v b/vlib/v/tests/generic_sumtype_test.v index 216d0913d4..ad6994f4e9 100644 --- a/vlib/v/tests/generic_sumtype_test.v +++ b/vlib/v/tests/generic_sumtype_test.v @@ -1,16 +1,16 @@ struct None {} // not named `Option` to avoid conflicts with the built-in type: -type MyOption = Error | None | T +type MyOption[T] = Error | None | T -fn unwrap_if(o MyOption) T { +fn unwrap_if[T](o MyOption[T]) T { if o is T { return o } panic('no value') } -fn unwrap_match(o MyOption) string { +fn unwrap_match[T](o MyOption[T]) string { match o { None { return 'none' @@ -25,43 +25,43 @@ fn unwrap_match(o MyOption) string { } fn test_generic_sumtype_unwrapping() { - y := MyOption(false) + y := MyOption[bool](false) assert unwrap_if(y) == false assert unwrap_match(y) == 'value' } fn test_generic_sumtype_auto_str() { - x := MyOption('hi') - y := MyOption(None{}) - assert '${x}, ${y}' == "MyOption('hi'), MyOption(None{})" + x := MyOption[string]('hi') + y := MyOption[bool](None{}) + assert '${x}, ${y}' == "MyOption[string]('hi'), MyOption[bool](None{})" } -struct Foo { +struct Foo[T] { x T } -struct Bar { +struct Bar[T] { x T } -type MyType = Bar | Foo +type MyType[T] = Bar[T] | Foo[T] fn test_generic_struct_members() { // TODO: this is currently needed to properly resolve that variant's type: - _ = Bar{''} + _ = Bar[string]{''} - f := Foo{'hi'} - t := MyType(f) - assert t.type_name() == 'Foo' + f := Foo[string]{'hi'} + t := MyType[string](f) + assert t.type_name() == 'Foo[string]' // accessing a field common to all variants, just like with a normal sumtype: assert t.x == 'hi' } -type MultiGeneric = X | Y | Z +type MultiGeneric[X, Y, Z] = X | Y | Z fn test_multi_generic_type() { - mut m := MultiGeneric(1234) + mut m := MultiGeneric[bool, int, string](1234) m = 'hi' match m { bool { diff --git a/vlib/v/tests/generics_T_typ_test.v b/vlib/v/tests/generics_T_typ_test.v index 5ee165d179..861acd1e83 100644 --- a/vlib/v/tests/generics_T_typ_test.v +++ b/vlib/v/tests/generics_T_typ_test.v @@ -6,7 +6,7 @@ mut: typ int } -fn make_any(obj T) Any { +fn make_any[T](obj T) Any { tsize := int(sizeof(T)) mut a := Any{ typ: T.typ @@ -18,7 +18,7 @@ fn make_any(obj T) Any { return a } -fn cast(obj Any) ?T { +fn cast[T](obj Any) ?T { if T.typ == obj.typ { return *&T(obj.data) } @@ -29,26 +29,26 @@ fn test_any_values() { arr := [make_any(true), make_any(false), make_any(7), make_any('cat'), make_any([3.1415926535])] for elm in arr { - if b := cast(elm) { + if b := cast[bool](elm) { println(!b) - } else if i := cast(elm) { + } else if i := cast[int](elm) { println(i + 1) - } else if s := cast(elm) { + } else if s := cast[string](elm) { println(s + '!') - } else if f := cast<[]f64>(elm) { + } else if f := cast[[]f64](elm) { println(f[0]) } } - if b := cast(arr[0]) { + if b := cast[bool](arr[0]) { assert b == true } - if b := cast(arr[1]) { + if b := cast[bool](arr[1]) { assert b == false } - if s := cast(arr[3]) { + if s := cast[string](arr[3]) { assert s == 'cat' } - if f := cast<[]f64>(arr[4]) { + if f := cast[[]f64](arr[4]) { assert math.veryclose(f[0], 3.1415926535) } } diff --git a/vlib/v/tests/generics_anon_fn_decl_with_type_only_arg_test.v b/vlib/v/tests/generics_anon_fn_decl_with_type_only_arg_test.v index 1d80a5824d..566aa8b71c 100644 --- a/vlib/v/tests/generics_anon_fn_decl_with_type_only_arg_test.v +++ b/vlib/v/tests/generics_anon_fn_decl_with_type_only_arg_test.v @@ -1,5 +1,5 @@ fn test_generics_anon_fn_decl_with_type_only_arg() { - ret := func_b(11, 22, add) + ret := func_b[int](11, 22, add) println(ret) assert ret == 33 } @@ -8,6 +8,6 @@ fn add(a int, b int) int { return a + b } -fn func_b(x T, y T, f fn (T, T) T) T { +fn func_b[T](x T, y T, f fn (T, T) T) T { return f(x, y) } diff --git a/vlib/v/tests/generics_array_append_test.v b/vlib/v/tests/generics_array_append_test.v index e54ccf98f6..f6eaf31072 100644 --- a/vlib/v/tests/generics_array_append_test.v +++ b/vlib/v/tests/generics_array_append_test.v @@ -1,4 +1,4 @@ -fn g(arr []T) { +fn g[T](arr []T) { mut r := []T{} r << arr assert arr.len > 0 diff --git a/vlib/v/tests/generics_array_builtin_method_call_test.v b/vlib/v/tests/generics_array_builtin_method_call_test.v index b6be6ded5e..8c50f0ad29 100644 --- a/vlib/v/tests/generics_array_builtin_method_call_test.v +++ b/vlib/v/tests/generics_array_builtin_method_call_test.v @@ -1,9 +1,9 @@ -struct Container { +struct Container[T] { mut: items []T } -fn (mut c Container) pop() ?T { +fn (mut c Container[T]) pop() ?T { return c.items.pop() } @@ -13,7 +13,7 @@ struct Item { } fn test_generic_array_pop_call() { - mut a1 := Container{ + mut a1 := Container[int]{ items: [11, 22] } println(a1) @@ -23,7 +23,7 @@ fn test_generic_array_pop_call() { item1 := Item{'a', 1} item2 := Item{'b', 2} - mut a2 := Container{ + mut a2 := Container[Item]{ items: [item1, item2] } println(a2) diff --git a/vlib/v/tests/generics_array_delete_test.v b/vlib/v/tests/generics_array_delete_test.v index be89c5a5bf..a0e3d673a0 100644 --- a/vlib/v/tests/generics_array_delete_test.v +++ b/vlib/v/tests/generics_array_delete_test.v @@ -1,9 +1,9 @@ -struct Set { +struct Set[T] { mut: field []T } -fn (mut s Set) add(value T) bool { +fn (mut s Set[T]) add[T](value T) bool { mut result := false if value !in s.field { @@ -14,7 +14,7 @@ fn (mut s Set) add(value T) bool { return result } -fn (mut s Set) remove(value T) bool { +fn (mut s Set[T]) remove[T](value T) bool { mut result := false if value in s.field { @@ -28,7 +28,7 @@ fn (mut s Set) remove(value T) bool { fn test_generics_array_delete() { // int - mut set1 := Set{} + mut set1 := Set[int]{} mut added := set1.add(4) println(added) @@ -48,7 +48,7 @@ fn test_generics_array_delete() { assert removed // f64 - mut set2 := Set{} + mut set2 := Set[f64]{} added = set2.add(4.4) println(added) @@ -68,7 +68,7 @@ fn test_generics_array_delete() { assert removed // string - mut set3 := Set{} + mut set3 := Set[string]{} added = set3.add('aaa') println(added) diff --git a/vlib/v/tests/generics_array_init_test.v b/vlib/v/tests/generics_array_init_test.v index f902230a4c..70ae8a3fef 100644 --- a/vlib/v/tests/generics_array_init_test.v +++ b/vlib/v/tests/generics_array_init_test.v @@ -1,22 +1,22 @@ -fn get_arr_v1(num N, val T) []T { +fn get_arr_v1[N, T](num N, val T) []T { return []T{len: num, init: val} } -fn get_arr_v2(num N, val T) []T { +fn get_arr_v2[N, T](num N, val T) []T { return []T{len: int(num), init: val} } -fn get_arr_v3(num N, val T) []T { +fn get_arr_v3[N, T](num N, val T) []T { tmp := num return []T{len: tmp, init: val} } -fn get_arr_v4(num N, val T) []T { +fn get_arr_v4[N, T](num N, val T) []T { tmp := num + 0 return []T{len: tmp, init: val} } -fn get_arr_v5(num N, val T) []T { +fn get_arr_v5[N, T](num N, val T) []T { tmp := 0 + num return []T{len: tmp, init: val} } diff --git a/vlib/v/tests/generics_array_map_with_generic_callback_test.v b/vlib/v/tests/generics_array_map_with_generic_callback_test.v index 98fb90a5c5..7566d9c857 100644 --- a/vlib/v/tests/generics_array_map_with_generic_callback_test.v +++ b/vlib/v/tests/generics_array_map_with_generic_callback_test.v @@ -1,11 +1,11 @@ fn test_generics_array_map_with_generic_callback() { mut a := []Sth{} - a = arr_generic(buggy_cb) + a = arr_generic[Sth](buggy_cb) println(a) assert a.len == 0 } -fn arr_generic(cb fn (int) T) []T { +fn arr_generic[T](cb fn (int) T) []T { return []int{}.map(cb(it)) } diff --git a/vlib/v/tests/generics_array_of_interface_method_call_test.v b/vlib/v/tests/generics_array_of_interface_method_call_test.v index 100399b124..46da849a14 100644 --- a/vlib/v/tests/generics_array_of_interface_method_call_test.v +++ b/vlib/v/tests/generics_array_of_interface_method_call_test.v @@ -1,4 +1,4 @@ -struct Array { +struct Array[T] { pub mut: elements []T } @@ -18,7 +18,7 @@ pub fn (s1 String) equals(s2 IObject) bool { return false } -pub fn (mut m Array) contains(e T) bool { +pub fn (mut m Array[T]) contains(e T) bool { for mut element in m.elements { if element.equals(e) { return true @@ -29,7 +29,7 @@ pub fn (mut m Array) contains(e T) bool { fn test_generic_array_of_interface_method_call() { s := String{'hello'} - mut a := Array{[s]} + mut a := Array[IObject]{[s]} ret := a.contains(IObject(s)) println(ret) assert ret diff --git a/vlib/v/tests/generics_array_typedef_test.v b/vlib/v/tests/generics_array_typedef_test.v index a6d183b2c9..4db167590b 100644 --- a/vlib/v/tests/generics_array_typedef_test.v +++ b/vlib/v/tests/generics_array_typedef_test.v @@ -1,15 +1,15 @@ -struct Node { +struct Node[T] { mut: data T - next &Node = unsafe { nil } + next &Node[T] = unsafe { nil } } -struct SinglyLinkedList { +struct SinglyLinkedList[T] { mut: - first_node &Node = unsafe { nil } + first_node &Node[T] = unsafe { nil } } -fn init_singlylinkedlist(nodes []Node) SinglyLinkedList { +fn init_singlylinkedlist[T](nodes []Node[T]) SinglyLinkedList[T] { mut current_node := &nodes[0] for i in 0 .. nodes.len - 1 { @@ -17,13 +17,13 @@ fn init_singlylinkedlist(nodes []Node) SinglyLinkedList { current_node.next = &nodes[i + 1] } - return SinglyLinkedList{&nodes[0]} + return SinglyLinkedList[T]{&nodes[0]} } fn test_generic_array_typedef() { - sll := init_singlylinkedlist([Node{ data: 1 }, Node{ + sll := init_singlylinkedlist[int]([Node[int]{ data: 1 }, Node[int]{ data: 2 - }, Node{ + }, Node[int]{ data: 798 }]) println(sll.first_node.next) diff --git a/vlib/v/tests/generics_assign_reference_generic_struct_test.v b/vlib/v/tests/generics_assign_reference_generic_struct_test.v index bef0f09499..e4a3703a67 100644 --- a/vlib/v/tests/generics_assign_reference_generic_struct_test.v +++ b/vlib/v/tests/generics_assign_reference_generic_struct_test.v @@ -1,20 +1,20 @@ -pub struct List { +pub struct List[T] { pub mut: - head &ListNode = unsafe { nil } + head &ListNode[T] = unsafe { nil } } -pub struct ListNode { +pub struct ListNode[T] { pub mut: value T - next &ListNode = unsafe { nil } + next &ListNode[T] = unsafe { nil } } -pub fn list_new() List { - return List{} +pub fn list_new[T]() List[T] { + return List[T]{} } -pub fn (mut l List) add(value T) { - mut node := &ListNode{value, 0} +pub fn (mut l List[T]) add(value T) { + mut node := &ListNode[T]{value, 0} if unsafe { l.head == 0 } { l.head = node } else { @@ -24,22 +24,22 @@ pub fn (mut l List) add(value T) { } fn test_generic_assign_reference_generic_struct() { - mut list1 := list_new() + mut list1 := list_new[string]() list1.add('hello') println(list1.head.value) assert list1.head.value == 'hello' - mut list2 := list_new() + mut list2 := list_new[int]() list2.add(100) println(list2.head.value) assert list2.head.value == 100 - mut list3 := list_new() + mut list3 := list_new[f64]() list3.add(22.2) println(list3.head.value) assert list3.head.value == 22.2 - mut list4 := list_new() + mut list4 := list_new[bool]() list4.add(true) println(list4.head.value) assert list4.head.value == true diff --git a/vlib/v/tests/generics_call_with_reference_arg_test.v b/vlib/v/tests/generics_call_with_reference_arg_test.v index 9373a8cd12..7bd7f19081 100644 --- a/vlib/v/tests/generics_call_with_reference_arg_test.v +++ b/vlib/v/tests/generics_call_with_reference_arg_test.v @@ -1,20 +1,20 @@ -struct MyStruct { +struct MyStruct[T] { mut: pos int buffer []&T } -fn (mut s MyStruct) add(e &T) bool { +fn (mut s MyStruct[T]) add(e &T) bool { s.buffer[0] = unsafe { e } return true } -fn fill(mut s MyStruct) { +fn fill(mut s MyStruct[i64]) { s.add(&i64(123)) } fn test_generics_call_with_reference_arg() { - mut s := MyStruct{ + mut s := MyStruct[i64]{ pos: 1 buffer: []&i64{len: 2} } diff --git a/vlib/v/tests/generics_closure_fn_direct_call_test.v b/vlib/v/tests/generics_closure_fn_direct_call_test.v index 192d99fa0d..e31af17232 100644 --- a/vlib/v/tests/generics_closure_fn_direct_call_test.v +++ b/vlib/v/tests/generics_closure_fn_direct_call_test.v @@ -1,8 +1,8 @@ pub struct App { } -pub fn (mut app App) register(service T) { - fn [service] () { +pub fn (mut app App) register[T](service T) { + fn [service] [T]() { println(service) }() } diff --git a/vlib/v/tests/generics_closure_fn_test.v b/vlib/v/tests/generics_closure_fn_test.v index e9905ab095..dcbb1cfbd0 100644 --- a/vlib/v/tests/generics_closure_fn_test.v +++ b/vlib/v/tests/generics_closure_fn_test.v @@ -1,5 +1,5 @@ -fn setter(mut m map[T]int) fn (T, int) { - return fn [mut m] (x T, k int) { +fn setter[T](mut m map[T]int) fn (T, int) { + return fn [mut m] [T](x T, k int) { m[x] = k } } diff --git a/vlib/v/tests/generics_fn_return_generic_interface_test.v b/vlib/v/tests/generics_fn_return_generic_interface_test.v index a19a4a2f00..6d21ba7135 100644 --- a/vlib/v/tests/generics_fn_return_generic_interface_test.v +++ b/vlib/v/tests/generics_fn_return_generic_interface_test.v @@ -1,15 +1,15 @@ -interface Iter { +interface Iter[T] { mut: next() ?T } -struct ArrayIter { +struct ArrayIter[T] { data []T mut: index int } -fn (mut i ArrayIter) next() ?T { +fn (mut i ArrayIter[T]) next[T]() ?T { if i.data.len == 0 { return none } @@ -17,8 +17,8 @@ fn (mut i ArrayIter) next() ?T { return i.data[i.index] } -fn iter(arr []T) Iter { - return ArrayIter{ +fn iter[T](arr []T) Iter[T] { + return ArrayIter[T]{ data: arr index: 0 } diff --git a/vlib/v/tests/generics_fn_return_types_with_generic_struct_test.v b/vlib/v/tests/generics_fn_return_types_with_generic_struct_test.v index 774958df90..b971d95b7b 100644 --- a/vlib/v/tests/generics_fn_return_types_with_generic_struct_test.v +++ b/vlib/v/tests/generics_fn_return_types_with_generic_struct_test.v @@ -1,32 +1,32 @@ -struct Abcd { +struct Abcd[T] { } -fn iterators_array() []&Abcd { - return []&Abcd{} +fn iterators_array[T]() []&Abcd[T] { + return []&Abcd[T]{} } fn test_generic_fn_return_array_of_generic_struct() { - a := iterators_array() + a := iterators_array[f64]() println(a) assert '${a}' == '[]' } -fn iterators_chan() chan Abcd { - return chan Abcd{} +fn iterators_chan[T]() chan Abcd[T] { + return chan Abcd[T]{} } fn test_generic_fn_return_chan_of_generic_struct() { - a := iterators_chan() + a := iterators_chan[f64]() println(a) - assert typeof(a).name == 'chan Abcd' + assert typeof(a).name == 'chan Abcd[f64]' } -fn iterators_map() map[string]&Abcd { - return map[string]&Abcd{} +fn iterators_map[T]() map[string]&Abcd[T] { + return map[string]&Abcd[T]{} } fn test_generic_fn_return_map_of_generic_struct() { - a := iterators_map() + a := iterators_map[f64]() println(a) assert '${a}' == '{}' } diff --git a/vlib/v/tests/generics_for_in_iterate_test.v b/vlib/v/tests/generics_for_in_iterate_test.v index 888677bf25..e56a881eeb 100644 --- a/vlib/v/tests/generics_for_in_iterate_test.v +++ b/vlib/v/tests/generics_for_in_iterate_test.v @@ -1,31 +1,31 @@ -pub struct Vec { +pub struct Vec[T] { mut: data &T [required] cap usize [required] len usize [required] } -pub fn new() Vec { - return Vec{ +pub fn new[T]() Vec[T] { + return Vec[T]{ data: unsafe { nil } cap: 0 len: 0 } } -pub fn (ar &Vec) iter() Iter { - return Iter{ +pub fn (ar &Vec[T]) iter() Iter[T] { + return Iter[T]{ v: unsafe { ar } } } -pub struct Iter { +pub struct Iter[T] { mut: - v &Vec [required] + v &Vec[T] [required] pos usize } -pub fn (mut iter Iter) next() ?&T { +pub fn (mut iter Iter[T]) next() ?&T { if iter.pos >= iter.v.len { return none } @@ -36,14 +36,14 @@ pub fn (mut iter Iter) next() ?&T { } fn test_generics_for_in_iterate() { - mut goods := new() + mut goods := new[int]() goods.call_generic_fn(fn (a &int) bool { return *a > 1 }) assert true } -fn (arr Vec) call_generic_fn(cb fn (&T) bool) { +fn (arr Vec[T]) call_generic_fn(cb fn (&T) bool) { for val in arr.iter() { println(cb(val)) } diff --git a/vlib/v/tests/generics_from_modules/genericmodule/take.v b/vlib/v/tests/generics_from_modules/genericmodule/take.v index 4fad996519..c39d6443ff 100644 --- a/vlib/v/tests/generics_from_modules/genericmodule/take.v +++ b/vlib/v/tests/generics_from_modules/genericmodule/take.v @@ -1,6 +1,6 @@ module genericmodule -pub fn take(a bool, b T, c T) T { +pub fn take[T](a bool, b T, c T) T { if a { return b } diff --git a/vlib/v/tests/generics_from_modules/inference_test.v b/vlib/v/tests/generics_from_modules/inference_test.v index e18a7707b4..0d7445bb61 100644 --- a/vlib/v/tests/generics_from_modules/inference_test.v +++ b/vlib/v/tests/generics_from_modules/inference_test.v @@ -3,10 +3,10 @@ module main import v.tests.generics_from_modules.genericmodule fn test_generic_function_from_another_module() { - v1 := genericmodule.take(true, 10, 20) + v1 := genericmodule.take[int](true, 10, 20) assert typeof(v1).name == 'int' assert v1 == 10 - v2 := genericmodule.take(false, 10, 20) + v2 := genericmodule.take[int](false, 10, 20) assert v2 == 20 } diff --git a/vlib/v/tests/generics_in_big_struct_method_test.v b/vlib/v/tests/generics_in_big_struct_method_test.v index c86a596efc..6da0ed83cd 100644 --- a/vlib/v/tests/generics_in_big_struct_method_test.v +++ b/vlib/v/tests/generics_in_big_struct_method_test.v @@ -16,7 +16,7 @@ pub fn (p Product) save() string { return do_something(p) } -fn do_something(p T) string { +fn do_something[T](p T) string { return 'whatever' } diff --git a/vlib/v/tests/generics_in_generics_test.v b/vlib/v/tests/generics_in_generics_test.v index 4c11f5c264..9c34b243f6 100644 --- a/vlib/v/tests/generics_in_generics_test.v +++ b/vlib/v/tests/generics_in_generics_test.v @@ -1,9 +1,9 @@ -fn gen_fn2(e T) string { +fn gen_fn2[T](e T) string { return '${e.str()}' } -fn gen_fn(e T) string { - return gen_fn2(e) +fn gen_fn[T](e T) string { + return gen_fn2[T](e) } fn test_generics_in_generics() { diff --git a/vlib/v/tests/generics_indirect_test.v b/vlib/v/tests/generics_indirect_test.v index 33e06b7bb4..5d5a8a87f4 100644 --- a/vlib/v/tests/generics_indirect_test.v +++ b/vlib/v/tests/generics_indirect_test.v @@ -8,7 +8,7 @@ pub fn current() &Local { return zzz } -pub fn store(var &T, value T) { +pub fn store[T](var &T, value T) { eprintln('store ${voidptr(var)} <- ${value}') unsafe { *var = value diff --git a/vlib/v/tests/generics_interface_decl_test.v b/vlib/v/tests/generics_interface_decl_test.v index e96aa8dcb6..451fdea18e 100644 --- a/vlib/v/tests/generics_interface_decl_test.v +++ b/vlib/v/tests/generics_interface_decl_test.v @@ -2,19 +2,19 @@ interface Depends { depends() []Depends } -struct Signal { +struct Signal[T] { } -fn (x Signal) depends() []Depends { +fn (x Signal[T]) depends() []Depends { return [] } -struct Add { - a Signal - b Signal +struct Add[T] { + a Signal[T] + b Signal[T] } -fn (a Add) depends() []Depends { +fn (a Add[T]) depends() []Depends { return [a.a, a.b] } diff --git a/vlib/v/tests/generics_interface_method_test.v b/vlib/v/tests/generics_interface_method_test.v index 7f2b966339..34454f21a4 100644 --- a/vlib/v/tests/generics_interface_method_test.v +++ b/vlib/v/tests/generics_interface_method_test.v @@ -1,9 +1,9 @@ -interface Iter { +interface Iter[T] { mut: next() ?T } -fn (mut it Iter) collect() []T { +fn (mut it Iter[T]) collect[T]() []T { mut data := []T{} for { val := it.next() or { break } @@ -12,13 +12,13 @@ fn (mut it Iter) collect() []T { return data } -struct ArrayIter { +struct ArrayIter[T] { data []T mut: index int } -fn (mut it ArrayIter) next() ?T { +fn (mut it ArrayIter[T]) next[T]() ?T { if it.index >= it.data.len { return none } @@ -29,7 +29,7 @@ fn (mut it ArrayIter) next() ?T { } fn test_generics_interface_method() { - mut iter := Iter(ArrayIter{ + mut iter := Iter[int](ArrayIter[int]{ data: [1, 2, 3] }) assert iter.collect() == [1, 2, 3] diff --git a/vlib/v/tests/generics_interface_with_generic_sumtype_test.v b/vlib/v/tests/generics_interface_with_generic_sumtype_test.v index 97759014b2..558b5d899c 100644 --- a/vlib/v/tests/generics_interface_with_generic_sumtype_test.v +++ b/vlib/v/tests/generics_interface_with_generic_sumtype_test.v @@ -1,17 +1,17 @@ // optional.v struct NonValue {} -pub type Optional = NonValue | T +pub type Optional[T] = NonValue | T -pub fn (self Optional) is_some() bool { +pub fn (self Optional[T]) is_some[T]() bool { return self is T } -pub fn (self Optional) is_none() bool { +pub fn (self Optional[T]) is_none[T]() bool { return !self.is_some() } -pub fn (self Optional) expect(msg string) T { +pub fn (self Optional[T]) expect[T](msg string) T { if self.is_some() { return self as T } else { @@ -19,11 +19,11 @@ pub fn (self Optional) expect(msg string) T { } } -pub fn (self Optional) unwrap() T { +pub fn (self Optional[T]) unwrap[T]() T { return self.expect('unwrap on a none value') } -pub fn (self Optional) unwrap_or(default T) T { +pub fn (self Optional[T]) unwrap_or[T](default T) T { if self.is_some() { return self as T } else { @@ -31,7 +31,7 @@ pub fn (self Optional) unwrap_or(default T) T { } } -pub fn (self Optional) unwrap_or_else(else_fn fn () T) T { +pub fn (self Optional[T]) unwrap_or_else[T](else_fn fn () T) T { if self.is_some() { return self as T } else { @@ -39,21 +39,21 @@ pub fn (self Optional) unwrap_or_else(else_fn fn () T) T { } } -pub fn some(value T) Optional { - return Optional(value as T) +pub fn some[T](value T) Optional[T] { + return Optional[T](value as T) } -pub fn null() Optional { - return Optional(NonValue{}) +pub fn null[T]() Optional[T] { + return Optional[T](NonValue{}) } // iter.v -pub interface Iterator { +pub interface Iterator[T] { mut: - next() Optional + next() Optional[T] } -pub fn (mut self Iterator) count() int { +pub fn (mut self Iterator[T]) count[T]() int { mut count := 0 for self.next().is_some() { count += 1 @@ -61,21 +61,21 @@ pub fn (mut self Iterator) count() int { return count } -struct EmptyIter { +struct EmptyIter[T] { value NonValue } -fn (mut self EmptyIter) next() Optional { - return Optional(self.value) +fn (mut self EmptyIter[T]) next[T]() Optional[T] { + return Optional[T](self.value) } // iter_test.v fn test_generics_interface_with_generic_sumtype() { - mut iter1 := EmptyIter{} + mut iter1 := EmptyIter[u32]{} println(iter1) assert iter1.next().is_none() - mut iter2 := Iterator(iter1) + mut iter2 := Iterator[u32](iter1) println(iter2) assert iter2.count() == 0 } diff --git a/vlib/v/tests/generics_interface_with_multi_generic_structs_test.v b/vlib/v/tests/generics_interface_with_multi_generic_structs_test.v index 719e3d1152..6470081a71 100644 --- a/vlib/v/tests/generics_interface_with_multi_generic_structs_test.v +++ b/vlib/v/tests/generics_interface_with_multi_generic_structs_test.v @@ -1,21 +1,21 @@ -interface Iter { +interface Iter[T] { mut: next() ?T } -fn (it Iter) skip(n int) Iter { - return SkipIter{ +fn (it Iter[T]) skip[T](n int) Iter[T] { + return SkipIter[T]{ n: n } } -struct ArrIter { +struct ArrIter[T] { data []T mut: index int } -fn (mut it ArrIter) next() ?T { +fn (mut it ArrIter[T]) next[T]() ?T { if it.index >= it.data.len { return none } @@ -25,13 +25,13 @@ fn (mut it ArrIter) next() ?T { return it.data[it.index] } -struct SkipIter { +struct SkipIter[T] { mut: n int - iter Iter + iter Iter[T] } -fn (mut it SkipIter) next() ?T { +fn (mut it SkipIter[T]) next[T]() ?T { for it.n > 0 { it.iter.next()? it.n-- @@ -40,7 +40,7 @@ fn (mut it SkipIter) next() ?T { } fn test_generics_interface_with_multi_generic_structs() { - mut x := Iter(ArrIter{ + mut x := Iter[int](ArrIter[int]{ data: [1, 2, 3] }) println(x) diff --git a/vlib/v/tests/generics_interface_with_multi_generic_types_test.v b/vlib/v/tests/generics_interface_with_multi_generic_types_test.v index 368a0584a4..271a57e445 100644 --- a/vlib/v/tests/generics_interface_with_multi_generic_types_test.v +++ b/vlib/v/tests/generics_interface_with_multi_generic_types_test.v @@ -1,16 +1,16 @@ -interface Iter { +interface Iter[T, U] { mut: next() ?(T, U) } -struct ArrIter { +struct ArrIter[T, U] { t []T u []U mut: index int } -fn (mut it ArrIter) next() ?(T, U) { +fn (mut it ArrIter[T, U]) next[T, U]() ?(T, U) { if it.index >= it.t.len || it.index >= it.u.len { return none } @@ -20,15 +20,15 @@ fn (mut it ArrIter) next() ?(T, U) { return it.t[it.index], it.u[it.index] } -fn iter(t []T, u []U) Iter { - return ArrIter{ +fn iter[T, U](t []T, u []U) Iter[T, U] { + return ArrIter[T, U]{ t: t u: u } } fn test_generics_interface_with_multi_generic_types() { - mut x := iter([1, 2, 3], ['foo', 'bar', 'baz']) + mut x := iter[int, string]([1, 2, 3], ['foo', 'bar', 'baz']) ret := 0 a, b := x.next() or { ret, '' } println(a) diff --git a/vlib/v/tests/generics_interface_with_non_generic_method_test.v b/vlib/v/tests/generics_interface_with_non_generic_method_test.v index eb1586b29c..644b9c6b9f 100644 --- a/vlib/v/tests/generics_interface_with_non_generic_method_test.v +++ b/vlib/v/tests/generics_interface_with_non_generic_method_test.v @@ -1,6 +1,6 @@ module main -interface TypeFactory { +interface TypeFactory[T] { get_type(type_name string) T } @@ -26,30 +26,30 @@ struct RawNode { type_name string } -struct Node { - factory TypeFactory +struct Node[T] { + factory TypeFactory[T] type_name NodeType raw_node RawNode } -fn new_node(factory TypeFactory, raw_node RawNode) ?Node { - return Node{ +fn new_node[T](factory TypeFactory[T], raw_node RawNode) ?Node[T] { + return Node[T]{ factory: factory type_name: factory.get_type(raw_node.type_name) raw_node: raw_node } } -fn program(factory TypeFactory) ? { - root1 := new_node(factory, RawNode{'literal'})? +fn program[T](factory TypeFactory[T]) ? { + root1 := new_node[T](factory, RawNode{'literal'})? println(root1) assert root1.type_name == .literal - root2 := new_node(root1.factory, RawNode{'expression'})? + root2 := new_node[T](root1.factory, RawNode{'expression'})? println(root2) assert root2.type_name == .expression } fn test_generic_interface_with_non_generic_method() { - program(&EnumTypeFactory{})? + program[NodeType](&EnumTypeFactory{})? } diff --git a/vlib/v/tests/generics_map_with_generic_type_key_test.v b/vlib/v/tests/generics_map_with_generic_type_key_test.v index 23ab8b8a04..201ec72e18 100644 --- a/vlib/v/tests/generics_map_with_generic_type_key_test.v +++ b/vlib/v/tests/generics_map_with_generic_type_key_test.v @@ -1,4 +1,4 @@ -fn counts(variables []T) map[T]int { +fn counts[T](variables []T) map[T]int { mut tally := map[T]int{} for var in variables { tally[var]++ diff --git a/vlib/v/tests/generics_method_on_alias_struct_receiver_test.v b/vlib/v/tests/generics_method_on_alias_struct_receiver_test.v index baa45a770d..70248ac3cc 100644 --- a/vlib/v/tests/generics_method_on_alias_struct_receiver_test.v +++ b/vlib/v/tests/generics_method_on_alias_struct_receiver_test.v @@ -6,7 +6,7 @@ pub fn (base Base) hello() string { type Message = Base -fn hello(hello_impl T) string { +fn hello[T](hello_impl T) string { return hello_impl.hello() } diff --git a/vlib/v/tests/generics_method_on_generic_structs_test.v b/vlib/v/tests/generics_method_on_generic_structs_test.v index 8be2e09768..90916fe204 100644 --- a/vlib/v/tests/generics_method_on_generic_structs_test.v +++ b/vlib/v/tests/generics_method_on_generic_structs_test.v @@ -5,20 +5,20 @@ struct Foo { a int } -struct Bar { +struct Bar[T] { a int } -fn (b Bar) pop() {} +fn (b Bar[T]) pop() {} fn test_bar_foo_works_even_when_datatypes_is_imported_that_also_has_pop_methods() { - mut a := Bar{} + mut a := Bar[Foo]{} println(a) assert true } fn test_datatypes_can_be_used_without_interfering_with_local_generic_structs() { - mut stack := datatypes.Stack{} + mut stack := datatypes.Stack[int]{} stack.push(1) println(stack) assert true diff --git a/vlib/v/tests/generics_method_on_nested_struct2_test.v b/vlib/v/tests/generics_method_on_nested_struct2_test.v index 2ea8b7d960..a2b441801c 100644 --- a/vlib/v/tests/generics_method_on_nested_struct2_test.v +++ b/vlib/v/tests/generics_method_on_nested_struct2_test.v @@ -1,13 +1,13 @@ -struct Outer { +struct Outer[T] { mut: - inner Inner + inner Inner[T] } -struct Inner { +struct Inner[T] { val T } -fn (mut i Inner) next(input S) f64 { +fn (mut i Inner[T]) next[S](input S) f64 { $if S is f32 { return 32 } $else { @@ -16,7 +16,7 @@ fn (mut i Inner) next(input S) f64 { } } -fn (mut o Outer) next(input S) f64 { +fn (mut o Outer[T]) next[S](input S) f64 { $if S is f32 { return o.inner.next(input) } $else { @@ -26,8 +26,8 @@ fn (mut o Outer) next(input S) f64 { } fn test_generics_method_on_nested_struct() { - mut outer := Outer{ - inner: Inner{ + mut outer := Outer[f64]{ + inner: Inner[f64]{ val: 1.1 } } diff --git a/vlib/v/tests/generics_method_on_nested_struct_test.v b/vlib/v/tests/generics_method_on_nested_struct_test.v index c428cc4f74..540355a85b 100644 --- a/vlib/v/tests/generics_method_on_nested_struct_test.v +++ b/vlib/v/tests/generics_method_on_nested_struct_test.v @@ -1,13 +1,13 @@ -struct Outer { +struct Outer[T] { mut: - inner Inner + inner Inner[T] } -struct Inner { +struct Inner[T] { val T } -fn (mut i Inner) next(input S) f64 { +fn (mut i Inner[T]) next[S](input S) f64 { $if S is f32 { return 32 } $else { @@ -17,16 +17,16 @@ fn (mut i Inner) next(input S) f64 { } fn test_generics_method_on_nested_struct() { - mut outer := Outer{ - inner: Inner{ + mut outer := Outer[f64]{ + inner: Inner[f64]{ val: 1.1 } } - r1 := outer.inner.next(99.0) + r1 := outer.inner.next[f32](99.0) println(r1) assert r1 == 32.0 - r2 := outer.inner.next(99.0) + r2 := outer.inner.next[f64, f32](99.0) println(r2) assert r2 == 32.0 diff --git a/vlib/v/tests/generics_method_on_receiver_aliases_types_test.v b/vlib/v/tests/generics_method_on_receiver_aliases_types_test.v index 7f5b022c7e..746678739d 100644 --- a/vlib/v/tests/generics_method_on_receiver_aliases_types_test.v +++ b/vlib/v/tests/generics_method_on_receiver_aliases_types_test.v @@ -1,14 +1,14 @@ module main -struct Container { +struct Container[T] { value T } -fn (c Container) id() int { +fn (c Container[T]) id() int { return 1 } -type Text = Container +type Text = Container[string] fn test_generic_method_on_receiver_aliases_type() { t := Text{'test'} diff --git a/vlib/v/tests/generics_method_on_receiver_types_test.v b/vlib/v/tests/generics_method_on_receiver_types_test.v index 61e0e7723b..6aa5b7759f 100644 --- a/vlib/v/tests/generics_method_on_receiver_types_test.v +++ b/vlib/v/tests/generics_method_on_receiver_types_test.v @@ -1,25 +1,25 @@ -struct Abc { +struct Abc[T] { value T } -fn (s Abc) get_value() T { +fn (s Abc[T]) get_value() T { return s.value } fn test_generics_method_on_receiver_types() { - s1 := Abc{'hello'} + s1 := Abc[string]{'hello'} println(s1.get_value()) assert s1.get_value() == 'hello' - s2 := Abc{22} + s2 := Abc[int]{22} println(s2.get_value()) assert s2.get_value() == 22 - s3 := Abc{1.1} + s3 := Abc[f64]{1.1} println(s3.get_value()) assert s3.get_value() == 1.1 - s4 := Abc{true} + s4 := Abc[bool]{true} println(s4.get_value()) assert s4.get_value() == true } diff --git a/vlib/v/tests/generics_method_ordering_test.v b/vlib/v/tests/generics_method_ordering_test.v index ab3fe364c0..5c2ea4f6cb 100644 --- a/vlib/v/tests/generics_method_ordering_test.v +++ b/vlib/v/tests/generics_method_ordering_test.v @@ -1,27 +1,27 @@ -struct Foo { +struct Foo[T] { x int } -fn (f Foo) pop() { +fn (f Foo[T]) pop() { println('hey') } -struct Bar { +struct Bar[T] { y int } // Note: Bar.foo before Bar.pop, should not cause a V compiler panic -fn (b Bar) foo() bool { +fn (b Bar[T]) foo() bool { return true } -fn (b Bar) pop() { +fn (b Bar[T]) pop() { println(b.foo()) } // fn dummy() { println(Bar{}) } fn test_foo() { - dump(Foo{}) + dump(Foo[int]{}) assert true } diff --git a/vlib/v/tests/generics_method_returning_optional_test.v b/vlib/v/tests/generics_method_returning_optional_test.v index 6299dda26a..237c30fb2d 100644 --- a/vlib/v/tests/generics_method_returning_optional_test.v +++ b/vlib/v/tests/generics_method_returning_optional_test.v @@ -1,6 +1,6 @@ import json -pub struct NotificationMessage { +pub struct NotificationMessage[T] { pub: method string params T @@ -8,18 +8,18 @@ pub: struct Abc {} -pub fn (x &Abc) notification_at() !NotificationMessage { - return json.decode(NotificationMessage, '{}') +pub fn (x &Abc) notification_at[T]() !NotificationMessage[T] { + return json.decode(NotificationMessage[T], '{}') } -pub fn (x &Abc) generic_method(method_name string) !NotificationMessage { - return x.notification_at() +pub fn (x &Abc) generic_method[T](method_name string) !NotificationMessage[T] { + return x.notification_at[T]() } struct Res {} pub fn (mut x Abc) diagnostics() !Res { - got := x.generic_method('xyz')! + got := x.generic_method[Res]('xyz')! return got.params } diff --git a/vlib/v/tests/generics_method_str_overload_test.v b/vlib/v/tests/generics_method_str_overload_test.v index 5dbdf2f061..0251548534 100644 --- a/vlib/v/tests/generics_method_str_overload_test.v +++ b/vlib/v/tests/generics_method_str_overload_test.v @@ -1,27 +1,27 @@ -struct Gen { +struct Gen[G] { data G id int size int } -fn (g Gen) str() string { +fn (g Gen[G]) str() string { return 'Gen<${G.name}>{${g.id}, ${g.data}, ${g.size}}' } fn test_generics_method_str_overload() { - mut g1 := Gen{'aaa', 0, 10} + mut g1 := Gen[string]{'aaa', 0, 10} println(g1) assert '${g1}' == 'Gen{0, aaa, 10}' - mut g2 := Gen{22, 0, 10} + mut g2 := Gen[int]{22, 0, 10} println(g2) assert '${g2}' == 'Gen{0, 22, 10}' - mut g3 := Gen{2.22, 0, 10} + mut g3 := Gen[f64]{2.22, 0, 10} println(g3) assert '${g3}' == 'Gen{0, 2.22, 10}' - mut g4 := Gen{true, 0, 10} + mut g4 := Gen[bool]{true, 0, 10} println(g4) assert '${g4}' == 'Gen{0, true, 10}' } diff --git a/vlib/v/tests/generics_method_test.v b/vlib/v/tests/generics_method_test.v index 8b5c2c2316..ae4aae0b15 100644 --- a/vlib/v/tests/generics_method_test.v +++ b/vlib/v/tests/generics_method_test.v @@ -4,14 +4,14 @@ mut: y int } -fn (mut p Point) translate(x T, y T) { +fn (mut p Point) translate[T](x T, y T) { p.x += x p.y += y } fn test_generic_method() { mut pot := Point{} - pot.translate(1, 3) + pot.translate[int](1, 3) pot.translate(1, 3) println(pot) assert pot == Point{ @@ -25,7 +25,7 @@ mut: name string } -fn (mut p Person) show(name string, data T) string { +fn (mut p Person) show[T](name string, data T) string { p.name = name return 'name: ${p.name}, data: ${data}' } @@ -38,13 +38,13 @@ fn test_generic_method_with_fixed_arg_type() { struct Foo {} -fn (v Foo) new() T { +fn (v Foo) new[T]() T { return T{} } fn test_generic_method_with_map_type() { foo := Foo{} - mut a := foo.new() + mut a := foo.new[map[string]string]() assert a == map[string]string{} assert a.len == 0 a['a'] = 'a' @@ -54,7 +54,7 @@ fn test_generic_method_with_map_type() { fn test_generic_method_with_array_type() { foo := Foo{} - mut a := foo.new<[]string>() + mut a := foo.new[[]string]() assert a == []string{} assert a.len == 0 a << 'a' @@ -64,7 +64,7 @@ fn test_generic_method_with_array_type() { fn test_generic_method_with_struct_type() { foo := Foo{} - mut a := foo.new() + mut a := foo.new[Person]() a.name = 'a' assert a.name == 'a' } diff --git a/vlib/v/tests/generics_method_with_generic_anon_fn_argument_test.v b/vlib/v/tests/generics_method_with_generic_anon_fn_argument_test.v index 773f1b45bb..c1230cc4a5 100644 --- a/vlib/v/tests/generics_method_with_generic_anon_fn_argument_test.v +++ b/vlib/v/tests/generics_method_with_generic_anon_fn_argument_test.v @@ -1,7 +1,7 @@ -struct Foo { +struct Foo[T] { } -fn (f Foo) do(name string, d fn (T), v T) T { +fn (f Foo[T]) do(name string, d fn (T), v T) T { println('running ' + name) d(v) println('ran ' + name) @@ -9,13 +9,13 @@ fn (f Foo) do(name string, d fn (T), v T) T { } fn test_generics_method_with_generic_anon_fn_argument() { - f1 := Foo{} + f1 := Foo[string]{} r1 := f1.do('foo', fn (s string) { println('s value is ' + s) }, 'bar') assert r1 == 'bar' - f2 := Foo{} + f2 := Foo[int]{} r2 := f2.do('bar', fn (s int) { println('s value is ${s}') }, 22) diff --git a/vlib/v/tests/generics_method_with_multi_types_test.v b/vlib/v/tests/generics_method_with_multi_types_test.v index 1ca3cbbeb8..141a1ec23d 100644 --- a/vlib/v/tests/generics_method_with_multi_types_test.v +++ b/vlib/v/tests/generics_method_with_multi_types_test.v @@ -6,11 +6,11 @@ struct Some { i int } -struct App { +struct App[M] { f M } -fn (mut self App) next1(input T) f64 { +fn (mut self App[M]) next1[M, T](input T) f64 { $if M is Something { return 0 } $else { @@ -20,7 +20,7 @@ fn (mut self App) next1(input T) f64 { return 1 } -fn (mut self App) next2(input T) f64 { +fn (mut self App[M]) next2[T, M](input T) f64 { $if M is Something { return 0 } $else { @@ -30,7 +30,7 @@ fn (mut self App) next2(input T) f64 { return 1 } -fn (mut self App) next3(input T) f64 { +fn (mut self App[M]) next3[T](input T) f64 { $if M is Something { return 0 } $else { @@ -41,7 +41,7 @@ fn (mut self App) next3(input T) f64 { } fn test_generic_method_with_multi_types() { - mut app := App{ + mut app := App[Some]{ f: Some{ i: 10 } diff --git a/vlib/v/tests/generics_method_with_nested_generic_method_test.v b/vlib/v/tests/generics_method_with_nested_generic_method_test.v index 63212d689b..8bf1298f6e 100644 --- a/vlib/v/tests/generics_method_with_nested_generic_method_test.v +++ b/vlib/v/tests/generics_method_with_nested_generic_method_test.v @@ -1,10 +1,10 @@ struct Dummy {} -fn (dummy &Dummy) res() !T { +fn (dummy &Dummy) res[T]() !T { $if T is int { return 1 } $else $if T is f32 { - return dummy.res()! + 1 + return dummy.res[int]()! + 1 } $else { return error('exhausted') } @@ -13,11 +13,11 @@ fn (dummy &Dummy) res() !T { fn test_generics_method_with_nested_generic_method() ! { d := Dummy{} - println(d.res()!) - ret1 := d.res()! + println(d.res[int]()!) + ret1 := d.res[int]()! assert ret1 == 1 - println(d.res()!) - ret2 := d.res()! + println(d.res[f32]()!) + ret2 := d.res[f32]()! assert ret2 == 2.0 } diff --git a/vlib/v/tests/generics_method_with_sumtype_args_test.v b/vlib/v/tests/generics_method_with_sumtype_args_test.v index 3ff6fc0b79..4847584c65 100644 --- a/vlib/v/tests/generics_method_with_sumtype_args_test.v +++ b/vlib/v/tests/generics_method_with_sumtype_args_test.v @@ -2,7 +2,7 @@ module main fn test_generics_method_with_sumtype_args() { mut me := CatDad{} - ret := me.adopt(CatType.black, BlackCat{}) + ret := me.adopt[CatType, Cat](CatType.black, BlackCat{}) println(ret) assert ret == 22 } @@ -21,6 +21,6 @@ struct WhiteCat {} struct CatDad {} -fn (mut foo CatDad) adopt(d D, t T) int { +fn (mut foo CatDad) adopt[D, T](d D, t T) int { return 22 } diff --git a/vlib/v/tests/generics_multi_array_in_test.v b/vlib/v/tests/generics_multi_array_in_test.v index fb3be8b345..5a93b38d8e 100644 --- a/vlib/v/tests/generics_multi_array_in_test.v +++ b/vlib/v/tests/generics_multi_array_in_test.v @@ -1,4 +1,4 @@ -fn include(a T, b []T) bool { +fn include[T](a T, b []T) bool { return a in b } diff --git a/vlib/v/tests/generics_multi_type_comptime_call_test.v b/vlib/v/tests/generics_multi_type_comptime_call_test.v index 6900690e48..b931d946ea 100644 --- a/vlib/v/tests/generics_multi_type_comptime_call_test.v +++ b/vlib/v/tests/generics_multi_type_comptime_call_test.v @@ -12,7 +12,7 @@ fn (b &Bar) world() string { return @FN } -fn execute_methods() string { +fn execute_methods[T]() string { tmp := T{} $for method in T.methods { if method.attrs.len >= 2 { @@ -29,11 +29,11 @@ fn execute_methods() string { } fn test_generics_multi_type_comptime_call() { - ret1 := execute_methods() + ret1 := execute_methods[Foo]() println(ret1) assert ret1 == 'hello' - ret2 := execute_methods() + ret2 := execute_methods[Bar]() println(ret2) assert ret2 == 'world' } diff --git a/vlib/v/tests/generics_multi_types_struct_init_test.v b/vlib/v/tests/generics_multi_types_struct_init_test.v index 08d3ba605a..80b57205b2 100644 --- a/vlib/v/tests/generics_multi_types_struct_init_test.v +++ b/vlib/v/tests/generics_multi_types_struct_init_test.v @@ -1,9 +1,9 @@ -struct Response { +struct Response[T] { result T } -pub fn send(res T) string { - msg := Response{ +pub fn send[T](res T) string { + msg := Response[T]{ result: res } return '${msg}' @@ -16,26 +16,26 @@ struct Bar {} fn test_generics_multi_types_struct_init() { mut ret := send(Foo{}) println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[Foo]{') assert ret.contains('result: Foo{}') ret = send(Bar{}) println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[Bar]{') assert ret.contains('result: Bar{}') ret = send(123) println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[int]{') assert ret.contains('result: 123') ret = send('abc') println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[string]{') assert ret.contains("result: 'abc'") ret = send(2.22) println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[f64]{') assert ret.contains('result: 2.22') } diff --git a/vlib/v/tests/generics_nested_struct_init_test.v b/vlib/v/tests/generics_nested_struct_init_test.v index 544436a38a..9faab523f8 100644 --- a/vlib/v/tests/generics_nested_struct_init_test.v +++ b/vlib/v/tests/generics_nested_struct_init_test.v @@ -1,52 +1,52 @@ -struct Foo { +struct Foo[T] { foo T } -struct Bar { +struct Bar[T] { mut: - foos []Foo + foos []Foo[T] } -fn (mut b Bar) add(v T) { - b.foos << Foo{ +fn (mut b Bar[T]) add(v T) { + b.foos << Foo[T]{ foo: v } } fn test_nested_generics_struct_init() { - mut bar1 := Bar{} + mut bar1 := Bar[string]{} bar1.add('bar') println(bar1) result1 := '${bar1}' - assert result1.contains('Bar{') - assert result1.contains('foos: [Foo{') + assert result1.contains('Bar[string]{') + assert result1.contains('foos: [Foo[string]{') assert result1.contains("foo: 'bar'") - mut bar2 := Bar{} + mut bar2 := Bar[int]{} bar2.add(22) println(bar2) result2 := '${bar2}' - assert result2.contains('Bar{') - assert result2.contains('foos: [Foo{') + assert result2.contains('Bar[int]{') + assert result2.contains('foos: [Foo[int]{') assert result2.contains('foo: 22') - mut bar3 := Bar{} + mut bar3 := Bar[f64]{} bar3.add(2.2) println(bar3) result3 := '${bar3}' - assert result3.contains('Bar{') - assert result3.contains('foos: [Foo{') + assert result3.contains('Bar[f64]{') + assert result3.contains('foos: [Foo[f64]{') assert result3.contains('foo: 2.2') - mut bar4 := Bar{} + mut bar4 := Bar[bool]{} bar4.add(true) println(bar4) result4 := '${bar4}' - assert result4.contains('Bar{') - assert result4.contains('foos: [Foo{') + assert result4.contains('Bar[bool]{') + assert result4.contains('foos: [Foo[bool]{') assert result4.contains('foo: true') } diff --git a/vlib/v/tests/generics_return_generics_struct_test.v b/vlib/v/tests/generics_return_generics_struct_test.v index 0e92b45120..75aa4ea38d 100644 --- a/vlib/v/tests/generics_return_generics_struct_test.v +++ b/vlib/v/tests/generics_return_generics_struct_test.v @@ -1,37 +1,37 @@ // test generics function that return generics struct -pub struct Optional { +pub struct Optional[T] { mut: value T some bool } -pub fn new_some(value T) Optional { - return Optional{ +pub fn new_some[T](value T) Optional[T] { + return Optional[T]{ value: value some: true } } -pub fn some(opt Optional) bool { +pub fn some[T](opt Optional[T]) bool { return opt.some } -pub fn get(opt Optional) T { +pub fn get[T](opt Optional[T]) T { return opt.value } -pub fn set(mut opt Optional, value T) { +pub fn set[T](mut opt Optional[T], value T) { opt.value = value opt.some = true } fn test_generics_fn_return_generics_struct() { - mut o := new_some(23) - println(some(o)) - assert some(o) == true - set(mut o, 42) - println(get(o)) - assert get(o) == 42 + mut o := new_some[int](23) + println(some[int](o)) + assert some[int](o) == true + set[int](mut o, 42) + println(get[int](o)) + assert get[int](o) == 42 } // test generics method that return generics struct @@ -39,45 +39,45 @@ pub struct Foo { foo int } -pub fn (f Foo) new_some(value T) Optional { - return Optional{ +pub fn (f Foo) new_some[T](value T) Optional[T] { + return Optional[T]{ value: value some: true } } -pub fn (f Foo) some(opt Optional) bool { +pub fn (f Foo) some[T](opt Optional[T]) bool { return opt.some } -pub fn (f Foo) get(opt Optional) T { +pub fn (f Foo) get[T](opt Optional[T]) T { return opt.value } -pub fn (f Foo) set(mut opt Optional, value T) { +pub fn (f Foo) set[T](mut opt Optional[T], value T) { opt.value = value opt.some = true } fn test_generics_method_return_generics_struct() { foo := Foo{} - mut o := foo.new_some(23) - println(foo.some(o)) - assert foo.some(o) == true - foo.set(mut o, 42) - println(foo.get(o)) - assert foo.get(o) == 42 + mut o := foo.new_some[int](23) + println(foo.some[int](o)) + assert foo.some[int](o) == true + foo.set[int](mut o, 42) + println(foo.get[int](o)) + assert foo.get[int](o) == 42 } // test genrics struct str() -pub struct ArrayIterator { +pub struct ArrayIterator[T] { data []T mut: index int } -pub fn iter(arr []T) ArrayIterator { - return ArrayIterator{ +pub fn iter[T](arr []T) ArrayIterator[T] { + return ArrayIterator[T]{ data: arr index: 11 } @@ -85,59 +85,59 @@ pub fn iter(arr []T) ArrayIterator { fn test_generics_with_generics_struct_string() { data := ['foo', 'bar'] - it := iter(data) + it := iter[string](data) println(it) ret := '${it}' - assert ret.contains('ArrayIterator{') + assert ret.contains('ArrayIterator[string]{') assert ret.contains("data: ['foo', 'bar']") assert ret.contains('index: 11') } fn test_generics_struct_insts_to_concrete() { - ai := ArrayIterator{ + ai := ArrayIterator[int]{ data: [11, 22] index: 22 } println(ai) ret := '${ai}' - assert ret.contains('ArrayIterator{') + assert ret.contains('ArrayIterator[int]{') assert ret.contains('data: [11, 22]') assert ret.contains('index: 22') } -struct Iterator { +struct Iterator[T] { data []T } -pub fn (mut i Iterator) next() ?T { +pub fn (mut i Iterator[T]) next[T]() ?T { return i.data[0] } -pub fn iter_data(data []T) Iterator { - return Iterator{ +pub fn iter_data[T](data []T) Iterator[T] { + return Iterator[T]{ data: data } } fn test_generics_return_generic_struct_from_fn() { - mut it := iter_data([1, 2, 3]) + mut it := iter_data[int]([1, 2, 3]) println(it.next() or { -1 }) assert '${it.next()}' == 'Option(1)' } -struct ListNode { +struct ListNode[T] { pub mut: val T - next &ListNode = 0 + next &ListNode[T] = 0 } -fn (mut node ListNode) test() &ListNode { +fn (mut node ListNode[T]) test() &ListNode[T] { return node.next } fn test_generics_return_generic_struct_field() { - mut node1 := &ListNode{100, 0} - mut node2 := &ListNode{200, 0} + mut node1 := &ListNode[int]{100, 0} + mut node2 := &ListNode[int]{200, 0} node1.next = node2 ret := node1.test() println(ret) diff --git a/vlib/v/tests/generics_return_inconsistent_types_generics_struct_test.v b/vlib/v/tests/generics_return_inconsistent_types_generics_struct_test.v index 7bb64023f2..4bbd6e0504 100644 --- a/vlib/v/tests/generics_return_inconsistent_types_generics_struct_test.v +++ b/vlib/v/tests/generics_return_inconsistent_types_generics_struct_test.v @@ -1,51 +1,51 @@ // test generics function that return generics struct -pub struct Optional { +pub struct Optional[T] { mut: value T some bool typ string } -pub fn new_some(value T, b B) Optional { - return Optional{ +pub fn new_some[T, B](value T, b B) Optional[T] { + return Optional[T]{ value: value some: true typ: typeof(b).name } } -pub fn some(opt Optional) bool { +pub fn some[T](opt Optional[T]) bool { return opt.some } -pub fn get_value(opt Optional) T { +pub fn get_value[T](opt Optional[T]) T { return opt.value } -pub fn get_typ(opt Optional) string { +pub fn get_typ[T](opt Optional[T]) string { return opt.typ } -pub fn set(mut opt Optional, value T, b B) { +pub fn set[T, B](mut opt Optional[T], value T, b B) { opt.value = value opt.some = true opt.typ = typeof(b).name } fn test_inconsistent_types_generics_fn_return_generics_struct() { - mut o := new_some(23, 'aaa') - println(some(o)) - assert some(o) == true + mut o := new_some[int, string](23, 'aaa') + println(some[int](o)) + assert some[int](o) == true - println(get_value(o)) - assert get_value(o) == 23 + println(get_value[int](o)) + assert get_value[int](o) == 23 - set(mut o, 42, 'aaa') - println(get_value(o)) - assert get_value(o) == 42 + set[int, string](mut o, 42, 'aaa') + println(get_value[int](o)) + assert get_value[int](o) == 42 - println(get_typ(o)) - assert get_typ(o) == 'string' + println(get_typ[int](o)) + assert get_typ[int](o) == 'string' } // test generics method that return generics struct @@ -53,27 +53,27 @@ pub struct Foo { foo int } -pub fn (f Foo) new_some(value T, b B) Optional { - return Optional{ +pub fn (f Foo) new_some[T, B](value T, b B) Optional[T] { + return Optional[T]{ value: value some: true typ: typeof(b).name } } -pub fn (f Foo) some(opt Optional) bool { +pub fn (f Foo) some[T](opt Optional[T]) bool { return opt.some } -pub fn (f Foo) get_value(opt Optional) T { +pub fn (f Foo) get_value[T](opt Optional[T]) T { return opt.value } -pub fn (f Foo) get_typ(opt Optional) string { +pub fn (f Foo) get_typ[T](opt Optional[T]) string { return opt.typ } -pub fn (f Foo) set(mut opt Optional, value T, b B) { +pub fn (f Foo) set[T, B](mut opt Optional[T], value T, b B) { opt.value = value opt.some = true opt.typ = typeof(b).name @@ -81,17 +81,17 @@ pub fn (f Foo) set(mut opt Optional, value T, b B) { fn test_inconstent_types_generics_method_return_generics_struct() { foo := Foo{} - mut o := foo.new_some(23, 'aaa') - println(foo.some(o)) - assert foo.some(o) == true + mut o := foo.new_some[int, string](23, 'aaa') + println(foo.some[int](o)) + assert foo.some[int](o) == true - println(foo.get_value(o)) - assert foo.get_value(o) == 23 + println(foo.get_value[int](o)) + assert foo.get_value[int](o) == 23 - foo.set(mut o, 42, 'aaa') - println(foo.get_value(o)) - assert foo.get_value(o) == 42 + foo.set[int, string](mut o, 42, 'aaa') + println(foo.get_value[int](o)) + assert foo.get_value[int](o) == 42 - println(foo.get_typ(o)) - assert foo.get_typ(o) == 'string' + println(foo.get_typ[int](o)) + assert foo.get_typ[int](o) == 'string' } diff --git a/vlib/v/tests/generics_return_multi_array_test.v b/vlib/v/tests/generics_return_multi_array_test.v index eaa8fe1adc..adeef99adb 100644 --- a/vlib/v/tests/generics_return_multi_array_test.v +++ b/vlib/v/tests/generics_return_multi_array_test.v @@ -1,12 +1,12 @@ -fn example1(data []T) [][]T { +fn example1[T](data []T) [][]T { return [data] } -fn example2(data [][]T) [][][]T { +fn example2[T](data [][]T) [][][]T { return [data] } -fn example3(data [][][]T) [][][][]T { +fn example3[T](data [][][]T) [][][][]T { return [data] } diff --git a/vlib/v/tests/generics_return_multiple_generics_struct_test.v b/vlib/v/tests/generics_return_multiple_generics_struct_test.v index 4470226318..7f293b2634 100644 --- a/vlib/v/tests/generics_return_multiple_generics_struct_test.v +++ b/vlib/v/tests/generics_return_multiple_generics_struct_test.v @@ -1,60 +1,60 @@ -struct Foo { +struct Foo[A, B] { mut: a A b B } -fn new_foo(a A, b B) Foo { - return Foo{ +fn new_foo[A, B](a A, b B) Foo[A, B] { + return Foo[A, B]{ a: a b: b } } -fn get_a(opt Foo) A { +fn get_a[A, B](opt Foo[A, B]) A { return opt.a } -fn get_b(opt Foo) B { +fn get_b[A, B](opt Foo[A, B]) B { return opt.b } -fn set(mut opt Foo, a A, b B) { +fn set[A, B](mut opt Foo[A, B], a A, b B) { opt.a = a opt.b = b } fn test_generics_return_multiple_generics_struct() { - mut o1 := new_foo(23, 'aaa') - println(get_a(o1)) - assert get_a(o1) == 23 - println(get_b(o1)) - assert get_b(o1) == 'aaa' - set(mut o1, 42, 'bbb') - println(get_a(o1)) - assert get_a(o1) == 42 - println(get_b(o1)) - assert get_b(o1) == 'bbb' + mut o1 := new_foo[int, string](23, 'aaa') + println(get_a[int, string](o1)) + assert get_a[int, string](o1) == 23 + println(get_b[int, string](o1)) + assert get_b[int, string](o1) == 'aaa' + set[int, string](mut o1, 42, 'bbb') + println(get_a[int, string](o1)) + assert get_a[int, string](o1) == 42 + println(get_b[int, string](o1)) + assert get_b[int, string](o1) == 'bbb' - mut o2 := new_foo('bbb', 22) - println(get_a(o2)) - assert get_a(o2) == 'bbb' - println(get_b(o2)) - assert get_b(o2) == 22 - set(mut o2, 'bbb', 42) - println(get_a(o2)) - assert get_a(o2) == 'bbb' - println(get_b(o2)) - assert get_b(o2) == 42 + mut o2 := new_foo[string, int]('bbb', 22) + println(get_a[string, int](o2)) + assert get_a[string, int](o2) == 'bbb' + println(get_b[string, int](o2)) + assert get_b[string, int](o2) == 22 + set[string, int](mut o2, 'bbb', 42) + println(get_a[string, int](o2)) + assert get_a[string, int](o2) == 'bbb' + println(get_b[string, int](o2)) + assert get_b[string, int](o2) == 42 - mut o3 := new_foo(23, true) - println(get_a(o3)) - assert get_a(o3) == 23 - println(get_b(o3)) - assert get_b(o3) == true - set(mut o3, 42, false) - println(get_a(o3)) - assert get_a(o3) == 42 - println(get_b(o3)) - assert get_b(o3) == false + mut o3 := new_foo[int, bool](23, true) + println(get_a[int, bool](o3)) + assert get_a[int, bool](o3) == 23 + println(get_b[int, bool](o3)) + assert get_b[int, bool](o3) == true + set[int, bool](mut o3, 42, false) + println(get_a[int, bool](o3)) + assert get_a[int, bool](o3) == 42 + println(get_b[int, bool](o3)) + assert get_b[int, bool](o3) == false } diff --git a/vlib/v/tests/generics_return_recursive_generics_struct_test.v b/vlib/v/tests/generics_return_recursive_generics_struct_test.v index 34b22767ff..a464ee7e0b 100644 --- a/vlib/v/tests/generics_return_recursive_generics_struct_test.v +++ b/vlib/v/tests/generics_return_recursive_generics_struct_test.v @@ -1,11 +1,11 @@ -struct Node { +struct Node[T] { mut: val T - next &Node + next &Node[T] } -fn make_node(val []T) Node { - return Node{ +fn make_node[T](val []T) Node[T] { + return Node[T]{ val: val[0] next: 0 } diff --git a/vlib/v/tests/generics_return_reference_generics_struct_test.v b/vlib/v/tests/generics_return_reference_generics_struct_test.v index 500b64f8f2..c40dcb23ed 100644 --- a/vlib/v/tests/generics_return_reference_generics_struct_test.v +++ b/vlib/v/tests/generics_return_reference_generics_struct_test.v @@ -1,23 +1,23 @@ -struct Foo { +struct Foo[T] { data []T } -fn new_foo(len int) &Foo { - return &Foo{ +fn new_foo[T](len int) &Foo[T] { + return &Foo[T]{ data: []T{len: len} } } fn test_generics_return_reference_generics_struct() { - f1 := new_foo(4) + f1 := new_foo[int](4) println(f1) assert f1.data == [0, 0, 0, 0] - f2 := new_foo(4) + f2 := new_foo[bool](4) println(f2) assert f2.data == [false, false, false, false] - f3 := new_foo(4) + f3 := new_foo[f64](4) println(f3) assert f3.data == [0.0, 0.0, 0.0, 0.0] } diff --git a/vlib/v/tests/generics_struct_anon_fn_fields_test.v b/vlib/v/tests/generics_struct_anon_fn_fields_test.v index 7979340f95..1342236e04 100644 --- a/vlib/v/tests/generics_struct_anon_fn_fields_test.v +++ b/vlib/v/tests/generics_struct_anon_fn_fields_test.v @@ -1,32 +1,32 @@ -struct Scope { +struct Scope[T] { before fn () T specs []fn (T) T after fn (T) } fn test_generics_struct_anon_fn_fields() { - s1 := Scope{} + s1 := Scope[u32]{} println(s1) ts1 := '${s1}' assert ts1.contains('before: fn () u32') assert ts1.contains('specs: []') assert ts1.contains('after: fn (u32)') - s2 := Scope{} + s2 := Scope[f64]{} println(s2) ts2 := '${s2}' assert ts2.contains('before: fn () f64') assert ts2.contains('specs: []') assert ts2.contains('after: fn (f64)') - s3 := Scope{} + s3 := Scope[string]{} println(s3) ts3 := '${s3}' assert ts3.contains('before: fn () string') assert ts3.contains('specs: []') assert ts3.contains('after: fn (string)') - s4 := Scope{} + s4 := Scope[bool]{} println(s4) ts4 := '${s4}' assert ts4.contains('before: fn () bool') diff --git a/vlib/v/tests/generics_struct_anon_fn_type_test.v b/vlib/v/tests/generics_struct_anon_fn_type_test.v index 3bdd3d4349..ffcb08dcde 100644 --- a/vlib/v/tests/generics_struct_anon_fn_type_test.v +++ b/vlib/v/tests/generics_struct_anon_fn_type_test.v @@ -2,50 +2,50 @@ fn neg(a int) int { return -a } -struct FnHolder1 { +struct FnHolder1[T] { func T } -fn (self FnHolder1) call(a int) int { +fn (self FnHolder1[T]) call(a int) int { return self.func(a) } -struct FnHolder2 { +struct FnHolder2[T] { func fn (int) int } -fn (self FnHolder2) call(a int) int { +fn (self FnHolder2[T]) call(a int) int { return self.func(a) } -fn holder_call_1(func T, a int) int { - h := FnHolder1{func} +fn holder_call_1[T](func T, a int) int { + h := FnHolder1[T]{func} return h.call(a) } -fn holder_call_2(func T, a int) int { - h := FnHolder2{func} +fn holder_call_2[T](func T, a int) int { + h := FnHolder2[T]{func} return h.call(a) } -fn holder_call_11(func T, a int) int { +fn holder_call_11[T](func T, a int) int { f := func - h := FnHolder1{f} + h := FnHolder1[T]{f} return h.call(a) } -fn holder_call_21(func T, a int) int { +fn holder_call_21[T](func T, a int) int { f := func - h := FnHolder2{f} + h := FnHolder2[T]{f} return h.call(a) } -fn holder_call_12(func T, a int) int { - return FnHolder1{func}.call(a) +fn holder_call_12[T](func T, a int) int { + return FnHolder1[T]{func}.call(a) } -fn holder_call_22(func T, a int) int { - return FnHolder2{func}.call(a) +fn holder_call_22[T](func T, a int) int { + return FnHolder2[T]{func}.call(a) } fn test_generic_struct_with_anon_fn_parameter() { @@ -55,7 +55,7 @@ fn test_generic_struct_with_anon_fn_parameter() { assert ret == -2 ret = holder_call_12(neg, 3) assert ret == -3 - ret = FnHolder1{neg}.call(4) + ret = FnHolder1[fn (int) int]{neg}.call(4) assert ret == -4 ret = holder_call_2(neg, 3) @@ -64,6 +64,6 @@ fn test_generic_struct_with_anon_fn_parameter() { assert ret == -4 ret = holder_call_22(neg, 5) assert ret == -5 - ret = FnHolder2{neg}.call(6) + ret = FnHolder2[fn (int) int]{neg}.call(6) assert ret == -6 } diff --git a/vlib/v/tests/generics_struct_field_with_default_struct_value_test.v b/vlib/v/tests/generics_struct_field_with_default_struct_value_test.v index a4b97b4931..2283194098 100644 --- a/vlib/v/tests/generics_struct_field_with_default_struct_value_test.v +++ b/vlib/v/tests/generics_struct_field_with_default_struct_value_test.v @@ -4,17 +4,17 @@ struct None {} type OptError = None | string -struct Opt { +struct Opt[T] { value T error OptError = None{} } struct MessageModify { - text Opt + text Opt[string] } fn test_generic_struct_field_with_default_struct_value() { - edit_query := MessageModify{Opt{ + edit_query := MessageModify{Opt[string]{ value: 'Hello there!' }} println(edit_query) diff --git a/vlib/v/tests/generics_struct_free_test.v b/vlib/v/tests/generics_struct_free_test.v index f9bab5f315..8395a36144 100644 --- a/vlib/v/tests/generics_struct_free_test.v +++ b/vlib/v/tests/generics_struct_free_test.v @@ -1,28 +1,28 @@ -struct List { +struct List[T] { pub mut: - head &ListNode = 0 + head &ListNode[T] = 0 } -struct ListNode { +struct ListNode[T] { pub mut: value T - next &ListNode = 0 + next &ListNode[T] = 0 } -fn list_new() List { - return List{} +fn list_new[T]() List[T] { + return List[T]{} } -fn listnode_new() &ListNode { - return &ListNode{0, 0} +fn listnode_new[T]() &ListNode[T] { + return &ListNode[T]{0, 0} } -fn (mut l List) free() { +fn (mut l List[T]) free() { // } fn test_generic_struct_free() { - mut list := list_new() + mut list := list_new[string]() println(list) list.free() assert true diff --git a/vlib/v/tests/generics_struct_init_in_generic_fn_test.v b/vlib/v/tests/generics_struct_init_in_generic_fn_test.v index 8e719d2a56..653c75bdcd 100644 --- a/vlib/v/tests/generics_struct_init_in_generic_fn_test.v +++ b/vlib/v/tests/generics_struct_init_in_generic_fn_test.v @@ -17,7 +17,7 @@ fn test_generics_struct_init_in_generic_fn() { assert ret.id == 2 } -pub fn do(t T) T { +pub fn do[T](t T) T { max := T{ id: 2 } diff --git a/vlib/v/tests/generics_struct_init_test.v b/vlib/v/tests/generics_struct_init_test.v index 6af61e6c34..2ff3bec237 100644 --- a/vlib/v/tests/generics_struct_init_test.v +++ b/vlib/v/tests/generics_struct_init_test.v @@ -3,12 +3,12 @@ mut: arr []string } -fn test() T { +fn test[T]() T { return T{} } fn test_generics_struct_init() { - mut b := test() + mut b := test[Blah]() b.arr << 'item' println(b.arr) assert b.arr == ['item'] diff --git a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v index ac310bb456..5cb6eae010 100644 --- a/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v +++ b/vlib/v/tests/generics_struct_init_with_inconsistent_generic_types_test.v @@ -1,9 +1,9 @@ -struct Response { +struct Response[U] { result U } -pub fn send(res T) string { - msg := Response{ +pub fn send[T](res T) string { + msg := Response[T]{ result: res } return '${msg}' @@ -12,11 +12,11 @@ pub fn send(res T) string { fn test_generics_struct_init_with_inconsistent_generic_types() { mut ret := send(123) println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[int]{') assert ret.contains('result: 123') ret = send('abc') println(ret) - assert ret.contains('Response{') + assert ret.contains('Response[string]{') assert ret.contains("result: 'abc'") } diff --git a/vlib/v/tests/generics_struct_inst_method_call_test.v b/vlib/v/tests/generics_struct_inst_method_call_test.v index 76694a7b8e..a387b003c2 100644 --- a/vlib/v/tests/generics_struct_inst_method_call_test.v +++ b/vlib/v/tests/generics_struct_inst_method_call_test.v @@ -1,29 +1,29 @@ fn test_generics_struct_inst_method_call() { - v1 := V2d{100} + v1 := V2d[f32]{100} r1 := v1.in_bounds(tp_lft, bt_rigt) println(r1) assert r1 } const ( - tp_lft = V2d{20} - bt_rigt = V2d{650} + tp_lft = V2d[f32]{20} + bt_rigt = V2d[f32]{650} ) -struct V2d { +struct V2d[T] { mut: x T } -pub fn (v1 V2d) unpack() T { +pub fn (v1 V2d[T]) unpack() T { return v1.x } -pub fn (v1 V2d) less_than(v2 V2d) V2d { - return V2d{v1.x < v2.x} +pub fn (v1 V2d[T]) less_than(v2 V2d[T]) V2d[bool] { + return V2d[bool]{v1.x < v2.x} } -pub fn (v1 V2d) in_bounds(top_left V2d, bottom_right V2d) bool { +pub fn (v1 V2d[T]) in_bounds(top_left V2d[T], bottom_right V2d[T]) bool { v1.less_than(bottom_right).unpack() return true } diff --git a/vlib/v/tests/generics_struct_parent_has_str_to_string_test.v b/vlib/v/tests/generics_struct_parent_has_str_to_string_test.v index ab94e4222b..76c84216f4 100644 --- a/vlib/v/tests/generics_struct_parent_has_str_to_string_test.v +++ b/vlib/v/tests/generics_struct_parent_has_str_to_string_test.v @@ -15,7 +15,7 @@ mut: struct Vm { mut: display Display - stack datatypes.Stack + stack datatypes.Stack[u16] } struct Pattern { diff --git a/vlib/v/tests/generics_struct_to_string_test.v b/vlib/v/tests/generics_struct_to_string_test.v index b4d93d7938..486fb4f4c5 100644 --- a/vlib/v/tests/generics_struct_to_string_test.v +++ b/vlib/v/tests/generics_struct_to_string_test.v @@ -1,33 +1,33 @@ -struct Info { +struct Info[T] { data T } -fn get_info(res Info) string { +fn get_info[T](res Info[T]) string { return '${res}' } fn test_generic_struct_to_string() { - mut ret := get_info(Info{true}) + mut ret := get_info(Info[bool]{true}) println(ret) assert ret.contains('data: true') - ret = get_info(Info{123}) + ret = get_info(Info[int]{123}) println(ret) assert ret.contains('data: 123') - ret = get_info(Info{f32(2.2)}) + ret = get_info(Info[f32]{f32(2.2)}) println(ret) assert ret.contains('data: 2.2') - ret = get_info(Info{2.2}) + ret = get_info(Info[f64]{2.2}) println(ret) assert ret.contains('data: 2.2') - ret = get_info(Info{'aaa'}) + ret = get_info(Info[string]{'aaa'}) println(ret) assert ret.contains("data: 'aaa'") - ret = get_info(Info{u64(234)}) + ret = get_info(Info[u64]{u64(234)}) println(ret) assert ret.contains('data: 234') } diff --git a/vlib/v/tests/generics_struct_with_array_test.v b/vlib/v/tests/generics_struct_with_array_test.v index 976c99254d..8c0497c5ae 100644 --- a/vlib/v/tests/generics_struct_with_array_test.v +++ b/vlib/v/tests/generics_struct_with_array_test.v @@ -1,9 +1,9 @@ -struct Set { +struct Set[T] { pub mut: arr []T } -fn (mut s Set) add(elem T) bool { +fn (mut s Set[T]) add(elem T) bool { return match s.has(elem) { true { false @@ -15,30 +15,30 @@ fn (mut s Set) add(elem T) bool { } } -fn (s Set) has(elem T) bool { +fn (s Set[T]) has(elem T) bool { return elem in s.arr } fn test_generics_struct_with_array() { - mut s1 := Set{} + mut s1 := Set[int]{} println('declared a int-Set ${s1}') s1.add(1) println('the int-Set ${s1}') assert s1.arr == [1] - mut s2 := Set{} + mut s2 := Set[bool]{} println('declared a bool-Set ${s2}') s2.add(true) println('the bool-Set ${s2}') assert s2.arr == [true] - mut s3 := Set{} + mut s3 := Set[f64]{} println('declared a float-Set ${s3}') s3.add(2.22) println('the float-Set ${s3}') assert s3.arr == [2.22] - mut s4 := Set{} + mut s4 := Set[string]{} println('declared a string-Set ${s4}') s4.add('smth') println('the string-Set ${s4} ') diff --git a/vlib/v/tests/generics_struct_with_non_generic_interface_test.v b/vlib/v/tests/generics_struct_with_non_generic_interface_test.v index 475f3f0c38..02fec7212e 100644 --- a/vlib/v/tests/generics_struct_with_non_generic_interface_test.v +++ b/vlib/v/tests/generics_struct_with_non_generic_interface_test.v @@ -2,12 +2,12 @@ interface Box { transform(input int) int } -struct Test { +struct Test[T] { data T salt int } -fn (t Test) transform(input int) int { +fn (t Test[T]) transform(input int) int { return input + t.salt } @@ -16,7 +16,7 @@ fn box_transform(b Box) int { } fn test_generic_struct_with_non_generic_interface() { - ret := box_transform(Test{ + ret := box_transform(Test[string]{ data: 'hello' salt: 6 }) @@ -24,8 +24,8 @@ fn test_generic_struct_with_non_generic_interface() { assert ret == 106 } -fn run(data T) { - t := Test{ +fn run[T](data T) { + t := Test[T]{ data: data salt: 6 } diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index 43a742a851..00b07d5f98 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -1,28 +1,28 @@ import simplemodule -fn simple(p T) T { +fn simple[T](p T) T { return p } fn test_identity() { - assert simple(1) == 1 - assert simple(1 + 0) == 1 - assert simple('g') == 'g' - assert simple('g') + 'h' == 'gh' + assert simple[int](1) == 1 + assert simple[int](1 + 0) == 1 + assert simple[string]('g') == 'g' + assert simple[string]('g') + 'h' == 'gh' - assert simple<[]int>([1])[0] == 1 - assert simple({ + assert simple[[]int]([1])[0] == 1 + assert simple[map[string]string]({ 'a': 'b' })['a'] == 'b' - assert simple(simplemodule.Data{ value: 8 }).value == 8 + assert simple[simplemodule.Data](simplemodule.Data{ value: 8 }).value == 8 x := &simplemodule.Data{ value: 123 } - assert simple<&simplemodule.Data>(x).value == 123 + assert simple[&simplemodule.Data](x).value == 123 } -fn plus(xxx T, b T) T { +fn plus[T](xxx T, b T) T { // x := a // y := b // ww := ww @@ -31,19 +31,19 @@ fn plus(xxx T, b T) T { } fn test_infix_expr() { - a := plus(2, 3) + a := plus[int](2, 3) assert a == 5 - assert plus(10, 1) == 11 - assert plus('a', 'b') == 'ab' + assert plus[int](10, 1) == 11 + assert plus[string]('a', 'b') == 'ab' } -fn plus_one(a T) T { +fn plus_one[T](a T) T { mut b := a b++ return b } -fn minus_one(a T) T { +fn minus_one[T](a T) T { mut b := a b-- return b @@ -81,7 +81,7 @@ fn test_postfix_expr() { assert minus_one(f64(3.3)) - 2.3 < delta } -fn sum(l []T) T { +fn sum[T](l []T) T { mut r := T(0) for e in l { r += e @@ -94,7 +94,7 @@ fn test_array() { assert sum(b) == 6 } -fn max(brug string, a ...T) T { +fn max[T](brug string, a ...T) T { mut max := a[0] for item in a[1..] { if max < item { @@ -111,7 +111,7 @@ fn test_generic_variadic() { assert max('krkr', ...[u8(4), 3, 2, 1]) == 4 } -fn create() { +fn create[T]() { _ := T{} mut xx := T{} xx.name = 'foo' @@ -135,39 +135,39 @@ fn (u User) init() { fn (c City) init() { } -fn mut_arg(mut x T) { +fn mut_arg[T](mut x T) { // println(x.name) // = 'foo' } -fn mut_arg2(mut x T) T { +fn mut_arg2[T](mut x T) T { // println(x.name) // = 'foo' return *x } fn test_create() { - create() - create() + create[User]() + create[City]() mut u := User{} - mut_arg(mut u) - mut_arg2(mut u) + mut_arg[User](mut u) + mut_arg2[User](mut u) } -fn return_array(arr []T) []T { +fn return_array[T](arr []T) []T { return arr } fn test_return_array() { - a1 := return_array([1, 2, 3]) + a1 := return_array[int]([1, 2, 3]) assert a1 == [1, 2, 3] - a2 := return_array([1.1, 2.2, 3.3]) + a2 := return_array[f64]([1.1, 2.2, 3.3]) assert a2 == [1.1, 2.2, 3.3] - a3 := return_array(['a', 'b', 'c']) + a3 := return_array[string](['a', 'b', 'c']) assert a3 == ['a', 'b', 'c'] - a4 := return_array([true, false, true]) + a4 := return_array[bool]([true, false, true]) assert a4 == [true, false, true] } -fn opt(v T) ?T { +fn opt[T](v T) ?T { if sizeof(T) > 1 { return v } @@ -183,7 +183,7 @@ fn test_optional() { assert b == 99 } -fn ptr(v T) &T { +fn ptr[T](v T) &T { a := [v] return a.data } @@ -193,7 +193,7 @@ fn test_ptr() { assert *ptr('aa') == 'aa' } -fn map_f(l []T, f fn (T) U) []U { +fn map_f[T, U](l []T, f fn (T) U) []U { mut r := []U{} for e in l { r << f(e) @@ -218,12 +218,12 @@ fn mul_int(x int, y int) int { return x * y } -fn assert_eq(a T, b T) { +fn assert_eq[T](a T, b T) { r := a == b assert r } -fn print_nice(x T, indent int) string { +fn print_nice[T](x T, indent int) string { mut space := '' for _ in 0 .. indent { space = space + ' ' @@ -249,7 +249,7 @@ mut: y f64 } -fn (mut p Point) translate(x T, y T) { +fn (mut p Point) translate[T](x T, y T) { p.x += x p.y += y } @@ -260,7 +260,7 @@ fn test_generic_method() { assert p.x == 2.0 && p.y == 1.0 } -fn get_values(i T) []T { +fn get_values[T](i T) []T { return [i] } @@ -294,7 +294,7 @@ pub mut: name string } -struct Repo { +struct Repo[T, U] { db DB pub mut: model T @@ -306,13 +306,13 @@ pub mut: // return Repo{db: db} // } fn test_generic_struct() { - mut a := Repo{ + mut a := Repo[User, Permission]{ model: User{ name: 'joe' } } assert a.model.name == 'joe' - mut b := Repo{ + mut b := Repo[Group, Permission]{ permission: Permission{ name: 'superuser' } @@ -324,30 +324,30 @@ fn test_generic_struct() { assert typeof(b.model).name == 'Group' } -struct Foo { +struct Foo[T] { pub: data T } -fn (f Foo) value() string { +fn (f Foo[int]) value() string { return f.data.str() } fn test_generic_struct_method() { - foo_int := Foo{2} + foo_int := Foo[int]{2} assert foo_int.value() == '2' } fn test_struct_from_other_module() { - g := simplemodule.ThisIsGeneric{} + g := simplemodule.ThisIsGeneric[Permission]{} assert g.msg.name == '' } fn test_generic_struct_print_array_as_field() { - foo := Foo<[]string>{ + foo := Foo[[]string]{ data: []string{} } - assert foo.str() == 'Foo<[]string>{\n data: []\n}' + assert foo.str() == 'Foo[[]string]{\n data: []\n}' } struct Abc { @@ -356,7 +356,7 @@ struct Abc { z int } -fn p(args ...T) { +fn p[T](args ...T) { size := sizeof(T) print('p called with size: ${size:3} | ') for _, x in args { @@ -387,11 +387,11 @@ mut: context Context } -fn test(mut app T) { - nested_test(mut app) +fn test[T](mut app T) { + nested_test[T](mut app) } -fn nested_test(mut app T) { +fn nested_test[T](mut app T) { app.context = Context{} } @@ -400,17 +400,17 @@ fn test_pass_generic_to_nested_function() { test(mut app) } -fn generic_return_map() map[string]M { +fn generic_return_map[M]() map[string]M { return { '': M{} } } fn test_generic_return_map() { - assert typeof(generic_return_map()).name == 'map[string]string' + assert typeof(generic_return_map[string]()).name == 'map[string]string' } -fn generic_return_nested_map() map[string]map[string]M { +fn generic_return_nested_map[M]() map[string]map[string]M { return { '': { '': M{} @@ -419,10 +419,10 @@ fn generic_return_nested_map() map[string]map[string]M { } fn test_generic_return_nested_map() { - assert typeof(generic_return_nested_map()).name == 'map[string]map[string]string' + assert typeof(generic_return_nested_map[string]()).name == 'map[string]map[string]string' } -fn multi_return() (A, B) { +fn multi_return[A, B]() (A, B) { return A{}, B{} } @@ -436,11 +436,11 @@ struct Foo4 {} fn test_multi_return() { // compiles - multi_return() - multi_return() + multi_return[Foo1, Foo2]() + multi_return[Foo3, Foo4]() } -fn multi_generic_args(t T, v V) bool { +fn multi_generic_args[T, V](t T, v V) bool { return true } @@ -448,65 +448,65 @@ fn test_multi_generic_args() { assert multi_generic_args('Super', 2021) } -fn new() T { +fn new[T]() T { return T{} } fn test_generic_init() { // array init - mut a := new<[]string>() + mut a := new[[]string]() assert a.len == 0 a << 'a' assert a.len == 1 assert a[0] == 'a' // map init - mut b := new() + mut b := new[map[string]string]() assert b.len == 0 b['b'] = 'b' assert b.len == 1 assert b['b'] == 'b' // struct init - mut c := new() + mut c := new[User]() c.name = 'c' assert c.name == 'c' } -fn return_one(rec int, useless T) T { +fn return_one[T](rec int, useless T) T { // foo < bar() should work - if rec == 0 || 0 < return_one(rec - 1, useless) { + if rec == 0 || 0 < return_one[T](rec - 1, useless) { return T(1) } return T(0) } -struct MultiLevel { +struct MultiLevel[T] { foo T } -fn get_multilevel_foo(bar MultiLevel) int { +fn get_multilevel_foo[T](bar MultiLevel[T]) int { return bar.foo.foo } -fn get_multilevel_foo_2(bar T, baz U) int { +fn get_multilevel_foo_2[T, U](bar T, baz U) int { return bar.foo.foo + baz.foo.foo } fn test_multi_level_generics() { - one := MultiLevel{ + one := MultiLevel[int]{ foo: 10 } - two := MultiLevel>{ + two := MultiLevel[MultiLevel[int]]{ foo: one } assert two.foo.foo == 10 - three := MultiLevel>>{ + three := MultiLevel[MultiLevel[MultiLevel[int]]]{ foo: two } assert three.foo.foo.foo == 10 - assert get_multilevel_foo>(two) == 10 - assert get_multilevel_foo_2>, MultiLevel>>(two, + assert get_multilevel_foo[MultiLevel[int]](two) == 10 + assert get_multilevel_foo_2[MultiLevel[MultiLevel[int]], MultiLevel[MultiLevel[int]]](two, two) == 20 } @@ -516,12 +516,12 @@ fn (e1 Empty_) < (e2 Empty_) bool { return true } -struct TandU { +struct TandU[T, U] { t T u U } -fn boring_function(t T) bool { +fn boring_function[T](t T) bool { return true } @@ -535,16 +535,16 @@ fn test_generic_detection() { assert b1 && b2 // generic - assert multi_generic_args(0, 's') - assert multi_generic_args(Foo1{}, Foo2{}) - assert multi_generic_args, Foo>(Foo{}, Foo{}) + assert multi_generic_args[int, string](0, 's') + assert multi_generic_args[Foo1, Foo2](Foo1{}, Foo2{}) + assert multi_generic_args[Foo[int], Foo[int]](Foo[int]{}, Foo[int]{}) // TODO: assert multi_generic_args, Foo>(Foo1{}, Foo2{}) - assert multi_generic_args(simplemodule.Data{}, 0) - assert multi_generic_args(0, simplemodule.Data{}) - assert multi_generic_args<[]int, int>([]int{}, 0) - assert multi_generic_args(map[int]int{}, 0) - assert 0 < return_one(10, 0) + assert multi_generic_args[simplemodule.Data, int](simplemodule.Data{}, 0) + assert multi_generic_args[int, simplemodule.Data](0, simplemodule.Data{}) + assert multi_generic_args[[]int, int]([]int{}, 0) + assert multi_generic_args[map[int]int, int](map[int]int{}, 0) + assert 0 < return_one[int](10, 0) // "the hardest cases" foo, bar, baz := 1, 2, 16 @@ -554,29 +554,29 @@ fn test_generic_detection() { res3, res4 := Empty_{} < Empty_{}, baz >> (foo + 1 - 1) assert res3 assert res4 == 8 - assert boring_function>(TandU{ + assert boring_function[TandU[Empty_, int]](TandU[Empty_, int]{ t: Empty_{} u: 10 }) - assert boring_function>>(MultiLevel>{ - foo: MultiLevel{ + assert boring_function[MultiLevel[MultiLevel[int]]](MultiLevel[MultiLevel[int]]{ + foo: MultiLevel[int]{ foo: 10 } }) - assert boring_function, []int>>(TandU, []int>{ - t: MultiLevel{ + assert boring_function[TandU[MultiLevel[int], []int]](TandU[MultiLevel[int], []int]{ + t: MultiLevel[int]{ foo: 10 } u: [10] }) // this final case challenges your scanner :-) - assert boring_function>, map[string][]int>>(TandU>, map[string][]int>{ - t: TandU>{ + assert boring_function[TandU[TandU[int, MultiLevel[Empty_]], map[string][]int]](TandU[TandU[int, MultiLevel[Empty_]], map[string][]int]{ + t: TandU[int, MultiLevel[Empty_]]{ t: 20 - u: MultiLevel{ + u: MultiLevel[Empty_]{ foo: Empty_{} } } diff --git a/vlib/v/tests/generics_with_anon_generics_fn_test.v b/vlib/v/tests/generics_with_anon_generics_fn_test.v index b5bde8f089..bdd00adebf 100644 --- a/vlib/v/tests/generics_with_anon_generics_fn_test.v +++ b/vlib/v/tests/generics_with_anon_generics_fn_test.v @@ -1,16 +1,16 @@ -struct MyStruct { +struct MyStruct[T] { arr []T } -fn (mut s MyStruct) get_data(pos int) T { +fn (mut s MyStruct[T]) get_data(pos int) T { return s.arr[pos] } -fn (mut s MyStruct) iterate(handler fn (T) int) int { +fn (mut s MyStruct[T]) iterate(handler fn (T) int) int { mut sum := 0 mut i := 0 for { - k := s.get_data(i) + k := s.get_data[T](i) sum += handler(k) i++ if i > 4 { @@ -28,30 +28,30 @@ pub fn consume_str(data string) string { return data } -fn call(f fn (T) T, v T) T { +fn call[T](f fn (T) T, v T) T { return f(v) } -struct Pair { +struct Pair[T, U] { a T b U } fn test_generics_with_anon_generics_fn() { - mut s := MyStruct{ + mut s := MyStruct[int]{ arr: [1, 2, 3, 4, 5] } - y := s.iterate(consume) + y := s.iterate[int](consume) println(y) assert y == 15 - assert call(consume, 1) == 1 - assert call(consume_str, '1') == '1' + assert call[int](consume, 1) == 1 + assert call[string](consume_str, '1') == '1' assert call(consume, 1) == 1 assert call(consume_str, '1') == '1' - pair := Pair{1, 's'} - assert call(fn (v Pair) Pair { + pair := Pair[int, string]{1, 's'} + assert call(fn (v Pair[int, string]) Pair[int, string] { return v }, pair) == pair } diff --git a/vlib/v/tests/generics_with_assign_nested_generics_call_test.v b/vlib/v/tests/generics_with_assign_nested_generics_call_test.v index 7bd0753217..87382972ce 100644 --- a/vlib/v/tests/generics_with_assign_nested_generics_call_test.v +++ b/vlib/v/tests/generics_with_assign_nested_generics_call_test.v @@ -1,32 +1,32 @@ -struct SSS { +struct SSS[T] { mut: x T } -fn (s SSS) inner() T { +fn (s SSS[T]) inner() T { return s.x } -fn (s SSS) outer() string { - ret := s.inner() +fn (s SSS[T]) outer() string { + ret := s.inner[T]() println(ret) return '${ret}' } fn test_generics_with_assign_nested_generic_method_call() { - s1 := SSS{100} + s1 := SSS[int]{100} assert s1.outer() == '100' - s2 := SSS{'hello'} + s2 := SSS[string]{'hello'} assert s2.outer() == 'hello' } -fn fn_inner(t T) T { +fn fn_inner[T](t T) T { return t } -fn fn_outer(t T) string { - ret := fn_inner(t) +fn fn_outer[T](t T) string { + ret := fn_inner[T](t) println(ret) return '${ret}' } diff --git a/vlib/v/tests/generics_with_cascaded_multiple_nested_generics_fn_test.v b/vlib/v/tests/generics_with_cascaded_multiple_nested_generics_fn_test.v index 89d93a6c39..13e5c97ecc 100644 --- a/vlib/v/tests/generics_with_cascaded_multiple_nested_generics_fn_test.v +++ b/vlib/v/tests/generics_with_cascaded_multiple_nested_generics_fn_test.v @@ -1,29 +1,29 @@ -fn gfn1(var T) T { +fn gfn1[T](var T) T { return var } -fn gfn2(var T) T { - return gfn1(var) +fn gfn2[T](var T) T { + return gfn1[T](var) } -fn gfn3(var T) T { - return gfn2(var) +fn gfn3[T](var T) T { + return gfn2[T](var) } -fn gfn4(var T) T { - return gfn3(var) +fn gfn4[T](var T) T { + return gfn3[T](var) } // don't give concrete types -fn gfn2_infer(var T) T { +fn gfn2_infer[T](var T) T { return gfn1(var) } -fn gfn3_infer(var T) T { +fn gfn3_infer[T](var T) T { return gfn2_infer(var) } -fn gfn4_infer(var T) T { +fn gfn4_infer[T](var T) T { return gfn3_infer(var) } diff --git a/vlib/v/tests/generics_with_complex_nested_generics_type_test.v b/vlib/v/tests/generics_with_complex_nested_generics_type_test.v index b6e06012d6..0d8915cec4 100644 --- a/vlib/v/tests/generics_with_complex_nested_generics_type_test.v +++ b/vlib/v/tests/generics_with_complex_nested_generics_type_test.v @@ -1,13 +1,13 @@ fn test_generics_with_complex_nested_generics_type() { mut buf := []u8{} - initial(buf) + initial[string, u64](buf) } -fn initial(buf []u8) map[K]V { +fn initial[K, V](buf []u8) map[K]V { mut ret := map[K]V{} for _ in 0 .. 3 { - k := get(buf) - v := get(buf) + k := get[K](buf) + v := get[V](buf) ret[k] = v } println(ret) @@ -15,7 +15,7 @@ fn initial(buf []u8) map[K]V { return ret } -fn get(buf []u8) T { +fn get[T](buf []u8) T { $if T is string { return buf.bytestr() + 'get' } $else $if T is u64 { diff --git a/vlib/v/tests/generics_with_embed_generics_test.v b/vlib/v/tests/generics_with_embed_generics_test.v index 3ca713f61e..efd2fc4760 100644 --- a/vlib/v/tests/generics_with_embed_generics_test.v +++ b/vlib/v/tests/generics_with_embed_generics_test.v @@ -1,16 +1,16 @@ -struct Group { +struct Group[T] { len int val []T mut: index int } -fn group_new(val ...T) Group { +fn group_new[T](val ...T) Group[T] { mut arr := []T{cap: val.len} for i in val { arr << i } - mut g := Group{ + mut g := Group[T]{ len: val.len val: arr } @@ -18,7 +18,7 @@ fn group_new(val ...T) Group { return g } -fn (mut it Group) next() ?T { +fn (mut it Group[T]) next() ?T { if it.index >= it.len { return none } @@ -28,25 +28,25 @@ fn (mut it Group) next() ?T { } fn test_generics_with_embed_generics() { - gx1 := group_new(1, 2, 3) + gx1 := group_new[int](1, 2, 3) for x in gx1.val { println(x) } assert gx1.val == [1, 2, 3] - gx2 := group_new(1.1, 2.2, 3.3) + gx2 := group_new[f64](1.1, 2.2, 3.3) for x in gx2.val { println(x) } assert gx2.val == [1.1, 2.2, 3.3] - gx3 := group_new(true, true, false) + gx3 := group_new[bool](true, true, false) for x in gx3.val { println(x) } assert gx3.val == [true, true, false] - gx4 := group_new('aa', 'bb', 'cc') + gx4 := group_new[string]('aa', 'bb', 'cc') for x in gx4.val { println(x) } diff --git a/vlib/v/tests/generics_with_fixed_array_type_test.v b/vlib/v/tests/generics_with_fixed_array_type_test.v index c7f0a6eed4..65a148308e 100644 --- a/vlib/v/tests/generics_with_fixed_array_type_test.v +++ b/vlib/v/tests/generics_with_fixed_array_type_test.v @@ -1,4 +1,4 @@ -fn show_element(arr T) string { +fn show_element[T](arr T) string { return '${arr[1]}' } diff --git a/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v b/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v index 6591b550cf..a123ef8b18 100644 --- a/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v +++ b/vlib/v/tests/generics_with_generics_fn_return_generics_fn_type_test.v @@ -13,26 +13,26 @@ fn normal_v2(func fn (int) int) fn (int) int { return f } -fn generic_v1(func T) T { +fn generic_v1[T](func T) T { assert T.name == typeof(neg).name assert typeof(func).name == typeof(neg).name return func } -fn generic_v2(func T) T { +fn generic_v2[T](func T) T { assert T.name == typeof(neg).name f := func assert typeof(f).name == typeof(neg).name return f } -fn mixed_v1(func T) fn (int) int { +fn mixed_v1[T](func T) fn (int) int { assert T.name == typeof(neg).name assert typeof(func).name == typeof(neg).name return func } -fn mixed_v2(func T) fn (int) int { +fn mixed_v2[T](func T) fn (int) int { assert T.name == typeof(neg).name f := func assert typeof(f).name == typeof(neg).name @@ -70,7 +70,7 @@ fn neg_b(b int) int { // assume that "generic" is a heavy function and should be shared // by *all* callers in this file [noinline] -fn generic(func T) T { +fn generic[T](func T) T { return func } diff --git a/vlib/v/tests/generics_with_generics_fn_type_parameter_test.v b/vlib/v/tests/generics_with_generics_fn_type_parameter_test.v index a59db4b2b1..1e9da135d0 100644 --- a/vlib/v/tests/generics_with_generics_fn_type_parameter_test.v +++ b/vlib/v/tests/generics_with_generics_fn_type_parameter_test.v @@ -8,13 +8,13 @@ fn indirect_call(func fn (int) int, a int) int { return func(a) } -fn generic_call(func T, a int) int { +fn generic_call[T](func T, a int) int { println(T.name) assert T.name == typeof(neg).name return func(a) } -fn generic_indirect_call(func T, a int) int { +fn generic_indirect_call[T](func T, a int) int { println(T.name) assert T.name == typeof(neg).name return indirect_call(func, a) @@ -26,13 +26,13 @@ fn indirect_call_v2(func fn (int) int, a int) int { return f(a) } -fn generic_call_v2(func T, a int) int { +fn generic_call_v2[T](func T, a int) int { f := func assert typeof(f).name == typeof(neg).name return f(a) } -fn generic_indirect_call_v2(func T, a int) int { +fn generic_indirect_call_v2[T](func T, a int) int { f := func assert typeof(f).name == typeof(neg).name return indirect_call_v2(f, a) diff --git a/vlib/v/tests/generics_with_generics_struct_init_test.v b/vlib/v/tests/generics_with_generics_struct_init_test.v index 9225ffdbc9..564d851f58 100644 --- a/vlib/v/tests/generics_with_generics_struct_init_test.v +++ b/vlib/v/tests/generics_with_generics_struct_init_test.v @@ -1,23 +1,23 @@ -struct List { +struct List[T] { mut: count u32 - first &ListNode - last &ListNode + first &ListNode[T] + last &ListNode[T] } -struct ListNode { +struct ListNode[T] { mut: val T - next &ListNode = 0 + next &ListNode[T] = 0 } -fn create(arr []T) &List { +fn create[T](arr []T) &List[T] { assert arr.len > 0 - mut n := &ListNode{ + mut n := &ListNode[T]{ val: arr[0] next: 0 } - mut l := &List{ + mut l := &List[T]{ first: n last: n count: 1 diff --git a/vlib/v/tests/generics_with_generics_struct_receiver_test.v b/vlib/v/tests/generics_with_generics_struct_receiver_test.v index 72c74dad43..e3165ad1e2 100644 --- a/vlib/v/tests/generics_with_generics_struct_receiver_test.v +++ b/vlib/v/tests/generics_with_generics_struct_receiver_test.v @@ -1,25 +1,25 @@ -struct Num { +struct Num[T] { num T } -fn (num Num) is_autom() bool { +fn (num Num[T]) is_autom() bool { return true } fn test_generics_with_generic_struct_receiver() { - num1 := Num{3} + num1 := Num[int]{3} println(num1.is_autom()) assert num1.is_autom() - num2 := Num{3.3} + num2 := Num[f64]{3.3} println(num2.is_autom()) assert num2.is_autom() - num3 := Num{'aaa'} + num3 := Num[string]{'aaa'} println(num3.is_autom()) assert num3.is_autom() - num4 := Num{true} + num4 := Num[bool]{true} println(num4.is_autom()) assert num4.is_autom() } diff --git a/vlib/v/tests/generics_with_multi_generics_struct_types_test.v b/vlib/v/tests/generics_with_multi_generics_struct_types_test.v index 36835cb473..0686a73aa3 100644 --- a/vlib/v/tests/generics_with_multi_generics_struct_types_test.v +++ b/vlib/v/tests/generics_with_multi_generics_struct_types_test.v @@ -1,19 +1,19 @@ -struct Animal { +struct Animal[T] { metadata T } -fn (a Animal) get() T { +fn (a Animal[T]) get[T]() T { return a.metadata } -fn extract(x Animal) T { +fn extract[T](x Animal[T]) T { return x.get() } fn test_generics_with_multi_generic_struct_types() { - a := Animal{123} - b := Animal{'456'} + a := Animal[int]{123} + b := Animal[string]{'456'} - assert extract(a) == 123 - assert extract(b) == '456' + assert extract[int](a) == 123 + assert extract[string](b) == '456' } diff --git a/vlib/v/tests/generics_with_multi_nested_generic_method_call_ref_arg_test.v b/vlib/v/tests/generics_with_multi_nested_generic_method_call_ref_arg_test.v index 242dfc8ef9..fd226dcb8d 100644 --- a/vlib/v/tests/generics_with_multi_nested_generic_method_call_ref_arg_test.v +++ b/vlib/v/tests/generics_with_multi_nested_generic_method_call_ref_arg_test.v @@ -1,9 +1,9 @@ -struct Wrapper { +struct Wrapper[S] { mut: - calc Calc + calc Calc[S] } -fn (mut w Wrapper) next(input T) f64 { +fn (mut w Wrapper[S]) next[T](input T) f64 { $if S is TypeA || S is TypeB { $if T is f64 { return w.calc.next(input) @@ -20,7 +20,7 @@ fn (mut w Wrapper) next(input T) f64 { } } -struct Calc { +struct Calc[S] { mut: typ S inner InnerCalc @@ -28,7 +28,7 @@ mut: struct InnerCalc {} -fn (mut c InnerCalc) next(input T) f64 { +fn (mut c InnerCalc) next[T](input T) f64 { $if T is f64 { return 64.2 } $else { @@ -54,7 +54,7 @@ fn (s &SecretSkill) secret() f64 { return 101.0 } -fn (mut c Calc) next(input T) f64 { +fn (mut c Calc[S]) next[T](input T) f64 { $if S is TypeA || S is TypeB { $if T is f64 { return c.typ.next(input) @@ -68,24 +68,24 @@ fn (mut c Calc) next(input T) f64 { } } -fn (mut t TypeA) next(input T) f64 { +fn (mut t TypeA) next[T](input T) f64 { return 10 } -fn (mut t TypeB) next(input T) f64 { +fn (mut t TypeB) next[T](input T) f64 { return 11 } -fn new() Wrapper { +fn new[S]() Wrapper[S] { $if S is TypeA { - return Wrapper{ - calc: Calc{ + return Wrapper[TypeA]{ + calc: Calc[TypeA]{ typ: TypeA{} } } } $else $if S is TypeB { - return Wrapper{ - calc: Calc{ + return Wrapper[TypeB]{ + calc: Calc[TypeB]{ typ: TypeB{} } } @@ -96,12 +96,12 @@ fn new() Wrapper { fn test_generics_with_multi_nested_generic_method_call_ref_arg() { { - mut c := new() + mut c := new[TypeA]() s := SecretSkill{} assert c.next(&s) == 10.0 } { - mut c := new() + mut c := new[TypeB]() s := SecretSkill{} assert c.next(&s) == 11.0 } diff --git a/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v b/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v index bb3f4948d6..de8ccb09cd 100644 --- a/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v +++ b/vlib/v/tests/generics_with_multi_nested_generic_method_call_test.v @@ -1,9 +1,9 @@ -struct Wrapper { +struct Wrapper[S] { mut: - calc Calc + calc Calc[S] } -fn (mut w Wrapper) next(input T) f64 { +fn (mut w Wrapper[S]) next[T](input T) f64 { $if S is TypeA || S is TypeB { $if T is f64 { return w.calc.next(input) @@ -18,7 +18,7 @@ fn (mut w Wrapper) next(input T) f64 { } } -struct Calc { +struct Calc[S] { mut: typ S } @@ -27,7 +27,7 @@ struct TypeA {} struct TypeB {} -fn (mut c Calc) next(input T) f64 { +fn (mut c Calc[S]) next[T](input T) f64 { $if S is TypeA || S is TypeB { $if T is f64 { return c.typ.next(input) @@ -39,26 +39,26 @@ fn (mut c Calc) next(input T) f64 { } } -fn (mut t TypeA) next(input T) f64 { +fn (mut t TypeA) next[T](input T) f64 { return 10 } -fn (mut t TypeB) next(input T) f64 { +fn (mut t TypeB) next[T](input T) f64 { return 11 } fn test_generics_with_multi_nested_generic_method_call() { { - mut c := Wrapper{ - calc: Calc{ + mut c := Wrapper[TypeA]{ + calc: Calc[TypeA]{ typ: TypeA{} } } assert c.next(100.0) == 10.0 } { - mut c := Wrapper{ - calc: Calc{ + mut c := Wrapper[TypeB]{ + calc: Calc[TypeB]{ typ: TypeB{} } } diff --git a/vlib/v/tests/generics_with_multiple_generics_struct_receiver_test.v b/vlib/v/tests/generics_with_multiple_generics_struct_receiver_test.v index ecfc57d64a..7edbe0e968 100644 --- a/vlib/v/tests/generics_with_multiple_generics_struct_receiver_test.v +++ b/vlib/v/tests/generics_with_multiple_generics_struct_receiver_test.v @@ -1,18 +1,18 @@ -struct Foo { +struct Foo[A, B] { a A b B } -fn (num Foo) get_foo1() (A, B) { +fn (num Foo[A, B]) get_foo1() (A, B) { return num.a, num.b } -fn (num Foo) get_foo2() (A, B) { +fn (num Foo[A, B]) get_foo2[B, A]() (A, B) { return num.a, num.b } fn test_generics_with_multi_generics_struct_receiver() { - num := Foo{ + num := Foo[int, string]{ a: 3 b: 'aaa' } diff --git a/vlib/v/tests/generics_with_nested_external_generics_fn_test.v b/vlib/v/tests/generics_with_nested_external_generics_fn_test.v index b246150ea9..0db726c4d6 100644 --- a/vlib/v/tests/generics_with_nested_external_generics_fn_test.v +++ b/vlib/v/tests/generics_with_nested_external_generics_fn_test.v @@ -1,10 +1,10 @@ import rand -pub fn sample(arr []T, k int) ?[]T { +pub fn sample[T](arr []T, k int) ?[]T { mut result := arr.clone() rand.seed([u32(1), 2]) // set seed to produce same results in order - rand.shuffle(mut result)? + rand.shuffle[T](mut result)? return result[0..k] } @@ -13,7 +13,7 @@ fn test_generics_with_nested_external_generics_fn() { mut arr := [11, 32, 24, 45, 57, 32, 37, 52, 37, 24] println(arr) - ret := sample(arr, 5)? + ret := sample[int](arr, 5)? println(ret) assert ret == [32, 45, 57, 11, 37] diff --git a/vlib/v/tests/generics_with_nested_generic_method_call_test.v b/vlib/v/tests/generics_with_nested_generic_method_call_test.v index 512aa62360..bdbda93508 100644 --- a/vlib/v/tests/generics_with_nested_generic_method_call_test.v +++ b/vlib/v/tests/generics_with_nested_generic_method_call_test.v @@ -1,4 +1,4 @@ -struct Calc { +struct Calc[S] { mut: typ S } @@ -7,7 +7,7 @@ struct TypeA {} struct TypeB {} -fn (mut c Calc) next(input T) f64 { +fn (mut c Calc[S]) next[T](input T) f64 { $if S is TypeA || S is TypeB { return c.typ.next(input) } $else { @@ -15,23 +15,23 @@ fn (mut c Calc) next(input T) f64 { } } -fn (mut t TypeA) next(input T) f64 { +fn (mut t TypeA) next[T](input T) f64 { return 10.0 } -fn (mut t TypeB) next(input T) f64 { +fn (mut t TypeB) next[T](input T) f64 { return 11.0 } fn test_generics_with_nested_generic_method_call() { { - mut c := Calc{ + mut c := Calc[TypeA]{ typ: TypeA{} } assert c.next(100) == 10.0 } { - mut c := Calc{ + mut c := Calc[TypeB]{ typ: TypeB{} } assert c.next(100) == 11.0 diff --git a/vlib/v/tests/generics_with_nested_generic_struct_init_test.v b/vlib/v/tests/generics_with_nested_generic_struct_init_test.v index b41ff1e590..c4150ddf81 100644 --- a/vlib/v/tests/generics_with_nested_generic_struct_init_test.v +++ b/vlib/v/tests/generics_with_nested_generic_struct_init_test.v @@ -1,24 +1,24 @@ fn test_nested_generic_struct_init() { - mut list1 := &List{} + mut list1 := &List[int]{} println(list1) assert '${list1}'.contains('head: &nil') - mut list2 := list_new() + mut list2 := list_new[int]() println(list2) assert '${list2}'.contains('head: &nil') } -struct List { +struct List[T] { pub mut: - head &ListNode = 0 + head &ListNode[T] = 0 } -struct ListNode { +struct ListNode[T] { pub mut: value T - next &ListNode = 0 + next &ListNode[T] = 0 } -pub fn list_new() &List { - return &List{} +pub fn list_new[T]() &List[T] { + return &List[T]{} } diff --git a/vlib/v/tests/generics_with_nested_generic_type_parameter_test.v b/vlib/v/tests/generics_with_nested_generic_type_parameter_test.v index 86ea8a6ca3..08f6afcc71 100644 --- a/vlib/v/tests/generics_with_nested_generic_type_parameter_test.v +++ b/vlib/v/tests/generics_with_nested_generic_type_parameter_test.v @@ -1,20 +1,20 @@ module main -pub struct Randomizer { +pub struct Randomizer[T] { } -pub struct Element { +pub struct Element[T] { } fn test_generics_with_nested_generic_type_parameter() { - a := new_randomizer() + a := new_randomizer[int]() println(a) - assert '${a}' == '&Randomizer{}' + assert '${a}' == '&Randomizer[int]{}' } -pub fn new_randomizer() &Randomizer { - return &Randomizer{} +pub fn new_randomizer[T]() &Randomizer[T] { + return &Randomizer[T]{} } -pub fn (mut r Randomizer) add_multiple(elements []Element) { +pub fn (mut r Randomizer[T]) add_multiple(elements []Element[T]) { } diff --git a/vlib/v/tests/generics_with_nested_generics_fn_infer_call_test.v b/vlib/v/tests/generics_with_nested_generics_fn_infer_call_test.v index c0641cbb49..b2ef054fc4 100644 --- a/vlib/v/tests/generics_with_nested_generics_fn_infer_call_test.v +++ b/vlib/v/tests/generics_with_nested_generics_fn_infer_call_test.v @@ -17,10 +17,10 @@ fn test_generics_with_nested_generic_fn_infer_call() { assert ret2 == Insect{} } -pub fn node_search(mut t T) T { +pub fn node_search[T](mut t T) T { return hydrate(mut t) } -fn hydrate(mut t T) T { +fn hydrate[T](mut t T) T { return t } diff --git a/vlib/v/tests/generics_with_nested_generics_fn_inst_call_test.v b/vlib/v/tests/generics_with_nested_generics_fn_inst_call_test.v index bcb0dd9bcc..fc3dbe021e 100644 --- a/vlib/v/tests/generics_with_nested_generics_fn_inst_call_test.v +++ b/vlib/v/tests/generics_with_nested_generics_fn_inst_call_test.v @@ -1,6 +1,6 @@ fn test_generics_with_nested_generic_fn_inst_call() { value := [u8(105), 116, 32, 119, 111, 114, 107, 115, 33, 33] - decoded := decode_arr(value) + decoded := decode_arr[string](value) dump(decoded) assert decoded.len == 4 assert decoded[0] == 'it works!!' @@ -9,17 +9,17 @@ fn test_generics_with_nested_generic_fn_inst_call() { assert decoded[3] == 'it works!!' } -fn decode_arr(buf []u8) []T { - arr_size := decode(buf[0..4]) +fn decode_arr[T](buf []u8) []T { + arr_size := decode[u32](buf[0..4]) mut ret := []T{cap: int(arr_size)} for _ in 0 .. arr_size { - ret << decode(buf[..]) + ret << decode[T](buf[..]) } return ret } -fn decode(buf []u8) T { +fn decode[T](buf []u8) T { $if T is u32 { return u32(buf.len) } $else $if T is string { diff --git a/vlib/v/tests/generics_with_nested_generics_fn_test.v b/vlib/v/tests/generics_with_nested_generics_fn_test.v index d651ae8ffe..7be257eb7e 100644 --- a/vlib/v/tests/generics_with_nested_generics_fn_test.v +++ b/vlib/v/tests/generics_with_nested_generics_fn_test.v @@ -9,13 +9,13 @@ mut: context Context } -fn (ng NestedGeneric) nested_test(mut app T) { +fn (ng NestedGeneric) nested_test[T](mut app T) { app.context = Context{} } -fn method_test(mut app T) int { +fn method_test[T](mut app T) int { ng := NestedGeneric{} - ng.nested_test(mut app) + ng.nested_test[T](mut app) return 22 } diff --git a/vlib/v/tests/generics_with_pointer_index_test.v b/vlib/v/tests/generics_with_pointer_index_test.v index 32325fb509..ad86b7753b 100644 --- a/vlib/v/tests/generics_with_pointer_index_test.v +++ b/vlib/v/tests/generics_with_pointer_index_test.v @@ -1,36 +1,36 @@ module main -pub struct Vec { +pub struct Vec[T] { mut: data &T cap int len int } -pub struct Iter { +pub struct Iter[T] { mut: - v &Vec + v &Vec[T] pos int } -pub fn with_cap(cap int) Vec { +pub fn with_cap[T](cap int) Vec[T] { new_data := unsafe { C.malloc(cap * int(sizeof(T))) } unsafe { C.memset(new_data, 0, cap * int(sizeof(T))) } - return Vec{ + return Vec[T]{ data: new_data cap: cap len: 0 } } -pub fn (ar &Vec) iter() Iter { - return Iter{ +pub fn (ar &Vec[T]) iter() Iter[T] { + return Iter[T]{ v: unsafe { ar } } } -pub fn (mut iter Iter) next() ?&T { +pub fn (mut iter Iter[T]) next() ?&T { if iter.pos >= iter.v.len { return none } @@ -39,7 +39,7 @@ pub fn (mut iter Iter) next() ?&T { return res } -pub fn (mut ar Vec) push(elm T) { +pub fn (mut ar Vec[T]) push(elm T) { unsafe { ar.data[ar.len - 1] = elm } @@ -50,12 +50,12 @@ struct Product { } fn test_generic_with_pointer_index() { - vec1 := with_cap(5) + vec1 := with_cap[Product](5) println(vec1) assert vec1.len == 0 assert vec1.cap == 5 - vec2 := with_cap(5) + vec2 := with_cap[int](5) println(vec2) assert vec2.len == 0 assert vec2.cap == 5 diff --git a/vlib/v/tests/generics_with_recursive_generics_fn_test.v b/vlib/v/tests/generics_with_recursive_generics_fn_test.v index f4b55475f8..fb81f73d05 100644 --- a/vlib/v/tests/generics_with_recursive_generics_fn_test.v +++ b/vlib/v/tests/generics_with_recursive_generics_fn_test.v @@ -10,14 +10,14 @@ fn test_generics_with_recursive_generics_fn() { for _ in 0 .. gen_len { arr << rand.intn(gen_max) or { 0 } } - println('before quick sort whether array is sorted: ${is_sorted(arr)}') - assert !is_sorted(arr) - quick_sort(mut arr, 0, arr.len - 1) - println('after quick sort whether array is sorted: ${is_sorted(arr)}') - assert is_sorted(arr) + println('before quick sort whether array is sorted: ${is_sorted[int](arr)}') + assert !is_sorted[int](arr) + quick_sort[int](mut arr, 0, arr.len - 1) + println('after quick sort whether array is sorted: ${is_sorted[int](arr)}') + assert is_sorted[int](arr) } -fn quick_sort(mut arr []T, l int, r int) { +fn quick_sort[T](mut arr []T, l int, r int) { if l >= r { return } @@ -29,11 +29,11 @@ fn quick_sort(mut arr []T, l int, r int) { } } arr[l], arr[sep] = arr[sep], arr[l] - quick_sort(mut arr, l, sep - 1) - quick_sort(mut arr, sep + 1, r) + quick_sort[T](mut arr, l, sep - 1) + quick_sort[T](mut arr, sep + 1, r) } -fn is_sorted(arr []T) bool { +fn is_sorted[T](arr []T) bool { for i in 0 .. arr.len - 1 { if arr[i] > arr[i + 1] { return false diff --git a/vlib/v/tests/generics_with_recursive_generics_struct_test.v b/vlib/v/tests/generics_with_recursive_generics_struct_test.v index 9216faf5df..b6e42c2edc 100644 --- a/vlib/v/tests/generics_with_recursive_generics_struct_test.v +++ b/vlib/v/tests/generics_with_recursive_generics_struct_test.v @@ -1,20 +1,20 @@ -pub struct Node { +pub struct Node[T] { value T - points_to []&Node + points_to []&Node[T] } fn test_generics_with_recursive_generics_struct() { - mid := &Node{ + mid := &Node[string]{ value: 'Middle' } - finish := &Node{ + finish := &Node[string]{ value: 'Finish' } - graph := &Node{ + graph := &Node[string]{ value: 'Start' points_to: [ - &Node{ + &Node[string]{ value: 'TopLeft' points_to: [ finish, diff --git a/vlib/v/tests/generics_with_reference_generic_args_test.v b/vlib/v/tests/generics_with_reference_generic_args_test.v index 504f9cabea..e62148cd18 100644 --- a/vlib/v/tests/generics_with_reference_generic_args_test.v +++ b/vlib/v/tests/generics_with_reference_generic_args_test.v @@ -1,6 +1,6 @@ module main -fn foo(val T) ?T { +fn foo[T](val T) ?T { return val } @@ -9,7 +9,7 @@ struct Bar { } fn test_generics_with_reference_generic_args() { - ret := foo<&Bar>(&Bar{ num: 123 }) or { panic(err) } + ret := foo[&Bar](&Bar{ num: 123 }) or { panic(err) } println(ret) assert ret.num == 123 } diff --git a/vlib/v/tests/generics_with_variadic_generic_args_test.v b/vlib/v/tests/generics_with_variadic_generic_args_test.v index 21eacf1967..7ad4ff9bde 100644 --- a/vlib/v/tests/generics_with_variadic_generic_args_test.v +++ b/vlib/v/tests/generics_with_variadic_generic_args_test.v @@ -1,15 +1,15 @@ -struct Node { +struct Node[T] { mut: data T - next &Node = 0 + next &Node[T] = 0 } -struct SinglyLinkedList { +struct SinglyLinkedList[T] { mut: - first_node &Node = 0 + first_node &Node[T] = 0 } -fn init_singlylinkedlist(nodes ...Node) SinglyLinkedList { +fn init_singlylinkedlist[T](nodes ...Node[T]) SinglyLinkedList[T] { mut current_node := &nodes[0] for i in 0 .. nodes.len - 1 { @@ -17,13 +17,13 @@ fn init_singlylinkedlist(nodes ...Node) SinglyLinkedList { current_node.next = &nodes[i + 1] } - return SinglyLinkedList{&nodes[0]} + return SinglyLinkedList[T]{&nodes[0]} } fn test_generic_with_variadic_generic_args() { - sll := init_singlylinkedlist(Node{ data: 1 }, Node{ + sll := init_singlylinkedlist[int](Node[int]{ data: 1 }, Node[int]{ data: 2 - }, Node{ + }, Node[int]{ data: 798 }) println(sll.first_node.next) diff --git a/vlib/v/tests/go_call_generic_fn_test.v b/vlib/v/tests/go_call_generic_fn_test.v index 3c6b0920b4..4338b6f74f 100644 --- a/vlib/v/tests/go_call_generic_fn_test.v +++ b/vlib/v/tests/go_call_generic_fn_test.v @@ -1,4 +1,4 @@ -fn test(c chan int, s T) { +fn test[T](c chan int, s T) { println('hi from generic fn test, T: ' + typeof(s).name) println('s: ${s}') assert true @@ -7,7 +7,7 @@ fn test(c chan int, s T) { fn test_go_generic_fn() { mut c := chan int{} - spawn test(c, 'abcd') + spawn test[string](c, 'abcd') x := <-c assert x == 123 println('bye') diff --git a/vlib/v/tests/if_expr_with_generic_sumtype_test.v b/vlib/v/tests/if_expr_with_generic_sumtype_test.v index cd4677b598..e1ab755223 100644 --- a/vlib/v/tests/if_expr_with_generic_sumtype_test.v +++ b/vlib/v/tests/if_expr_with_generic_sumtype_test.v @@ -1,17 +1,17 @@ -type Opt = None | Some +type Opt[T] = None[T] | Some[T] -struct None {} +struct None[T] {} -struct Some { +struct Some[T] { mut: value T } -fn operation(r int) Opt { - return if r > 0 { Some{r} } else { None{} } +fn operation(r int) Opt[int] { + return if r > 0 { Some[int]{r} } else { None[int]{} } } fn test_if_expr_with_generic_sumtype() { op := operation(1) - assert Opt(Some{1}) == op + assert Opt[int](Some[int]{1}) == op } diff --git a/vlib/v/tests/if_expression_test.v b/vlib/v/tests/if_expression_test.v index 2aac53291b..e20a541a5b 100644 --- a/vlib/v/tests/if_expression_test.v +++ b/vlib/v/tests/if_expression_test.v @@ -192,7 +192,7 @@ fn test_if_epxr_with_array_conditions() { } } -fn min(a T, b T) T { +fn min[T](a T, b T) T { return if a < b { a } else { b } } diff --git a/vlib/v/tests/inout/vscript_using_generics_in_os.vsh b/vlib/v/tests/inout/vscript_using_generics_in_os.vsh index eea3c42776..4304d97329 100644 --- a/vlib/v/tests/inout/vscript_using_generics_in_os.vsh +++ b/vlib/v/tests/inout/vscript_using_generics_in_os.vsh @@ -4,4 +4,4 @@ write_file_array(test_file_name, [u8(0xff), 0xff, 0xff, 0xff])? defer { rm(test_file_name) or {} } -println(read_file_array(test_file_name)) +println(read_file_array[u8](test_file_name)) diff --git a/vlib/v/tests/interface_edge_cases/i9_test.v b/vlib/v/tests/interface_edge_cases/i9_test.v index 0d565f4aef..61ef7db6ac 100644 --- a/vlib/v/tests/interface_edge_cases/i9_test.v +++ b/vlib/v/tests/interface_edge_cases/i9_test.v @@ -21,7 +21,7 @@ interface Drawer { draw() string } -fn to_string_generic(t T) { +fn to_string_generic[T](t T) { to_string(t) } diff --git a/vlib/v/tests/isreftype_test.v b/vlib/v/tests/isreftype_test.v index d097138b07..a56bf128e7 100644 --- a/vlib/v/tests/isreftype_test.v +++ b/vlib/v/tests/isreftype_test.v @@ -33,7 +33,7 @@ fn test_isreftype() { assert isreftype([3]int) == false } -fn check_ref() string { +fn check_ref[T]() string { if isreftype(T) { return 'ref' } else { @@ -42,8 +42,8 @@ fn check_ref() string { } fn test_generic_ref() { - assert check_ref() == 'no ref' - assert check_ref() == 'ref' + assert check_ref[f64]() == 'no ref' + assert check_ref[S3]() == 'ref' } fn test_expression_ref() { diff --git a/vlib/v/tests/map_builtin_call_test.v b/vlib/v/tests/map_builtin_call_test.v index 407e25e4b2..0df16527b1 100644 --- a/vlib/v/tests/map_builtin_call_test.v +++ b/vlib/v/tests/map_builtin_call_test.v @@ -1,27 +1,27 @@ -fn call_key_is_generic(v T) { +fn call_key_is_generic[T](v T) { a := map[T]u8{} _ := a.keys().filter(it == v) } -fn call_value_is_generic(v T) { +fn call_value_is_generic[T](v T) { a := map[u8]T{} _ := a.values().filter(it == v) } -fn call_all_is_generic_keys_method(v T) { +fn call_all_is_generic_keys_method[T, U](v T) { a := map[T]U{} _ := a.keys().filter(it == v) } -fn call_all_is_generic_values_method(v U) { +fn call_all_is_generic_values_method[T, U](v U) { a := map[T]U{} _ := a.values().filter(it == v) } fn test_call_has_generic() { - call_key_is_generic(1) - call_value_is_generic('') - call_all_is_generic_keys_method(1) - call_all_is_generic_values_method('') + call_key_is_generic[int](1) + call_value_is_generic[string]('') + call_all_is_generic_keys_method[int, string](1) + call_all_is_generic_values_method[int, string]('') assert true } diff --git a/vlib/v/tests/modules/simplemodule/simplemodule.v b/vlib/v/tests/modules/simplemodule/simplemodule.v index 8cc58ae8dc..3b3ced78d4 100644 --- a/vlib/v/tests/modules/simplemodule/simplemodule.v +++ b/vlib/v/tests/modules/simplemodule/simplemodule.v @@ -8,7 +8,7 @@ pub fn imul(x int, y int) int { return x * y } -pub struct ThisIsGeneric { +pub struct ThisIsGeneric[T] { msg T } diff --git a/vlib/v/tests/repl/repl_test.v b/vlib/v/tests/repl/repl_test.v index 94892d66bf..b072d31fcb 100644 --- a/vlib/v/tests/repl/repl_test.v +++ b/vlib/v/tests/repl/repl_test.v @@ -56,7 +56,7 @@ fn test_all_v_repl_files() { // See: https://docs.microsoft.com/en-us/cpp/build/reference/fs-force-synchronous-pdb-writes?view=vs-2019 pool_repl.set_max_jobs(1) } - pool_repl.work_on_items(session.options.files) + pool_repl.work_on_items[string](session.options.files) session.bmark.stop() println(session.bmark.total_message('total time spent running REPL files')) } @@ -76,7 +76,7 @@ fn worker_repl(mut p pool.PoolProcessor, idx int, thread_id int) voidptr { os.rmdir_all(tfolder) or { panic(err) } } os.mkdir(tfolder) or { panic(err) } - file := p.get_item(idx) + file := p.get_item[string](idx) session.bmark.step() tls_bench.step() fres := runner.run_repl_file(tfolder, session.options.vexec, file) or { diff --git a/vlib/v/tests/sizeof_2_test.v b/vlib/v/tests/sizeof_2_test.v index 1e656b15f4..fb7fbf498b 100644 --- a/vlib/v/tests/sizeof_2_test.v +++ b/vlib/v/tests/sizeof_2_test.v @@ -1,8 +1,8 @@ -fn getsize

() u32 { +fn getsize[P]() u32 { return sizeof(P) } fn test_sizeof_2() { - assert getsize() == 8 - assert 4 == getsize() + assert getsize[f64]() == 8 + assert 4 == getsize[int]() } diff --git a/vlib/v/tests/str_gen_test.v b/vlib/v/tests/str_gen_test.v index d0c63e79a8..dff13a12f6 100644 --- a/vlib/v/tests/str_gen_test.v +++ b/vlib/v/tests/str_gen_test.v @@ -253,11 +253,11 @@ fn test_map_with_struct() { struct ForGeneric {} -fn generic_fn_interpolation(p T) string { +fn generic_fn_interpolation[T](p T) string { return '${p}' } -fn generic_fn_str(p T) string { +fn generic_fn_str[T](p T) string { return p.str() } @@ -307,25 +307,25 @@ fn test_alias_struct() { assert '${t}' == 'TestAlias(TestStruct{\n x: 0\n})' } -struct GenericStruct { +struct GenericStruct[T] { x T } fn test_generic_struct() { - x := GenericStruct{} - assert '${x}' == 'GenericStruct{\n x: TestStruct{\n x: 0\n }\n}' - assert x.str() == 'GenericStruct{\n x: TestStruct{\n x: 0\n }\n}' + x := GenericStruct[TestStruct]{} + assert '${x}' == 'GenericStruct[TestStruct]{\n x: TestStruct{\n x: 0\n }\n}' + assert x.str() == 'GenericStruct[TestStruct]{\n x: TestStruct{\n x: 0\n }\n}' } -struct MultiGenericStruct { +struct MultiGenericStruct[T, X] { t T x X } fn test_multi_generic_struct() { - x := MultiGenericStruct{} - assert '${x}' == 'MultiGenericStruct{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}' - assert x.str() == 'MultiGenericStruct{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}' + x := MultiGenericStruct[TestStruct, TestStruct]{} + assert '${x}' == 'MultiGenericStruct[TestStruct, TestStruct]{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}' + assert x.str() == 'MultiGenericStruct[TestStruct, TestStruct]{\n t: TestStruct{\n x: 0\n }\n x: TestStruct{\n x: 0\n }\n}' } fn create_option_err() ?string { diff --git a/vlib/v/tests/struct_embed_test.v b/vlib/v/tests/struct_embed_test.v index 1886072433..1d41ba4f62 100644 --- a/vlib/v/tests/struct_embed_test.v +++ b/vlib/v/tests/struct_embed_test.v @@ -60,13 +60,13 @@ struct TestEmbedFromModule { flag.Flag } -struct BarGeneric { +struct BarGeneric[T] { pub: foo T } struct BarGenericContainer { - BarGeneric + BarGeneric[int] } fn test_generic_embed() { @@ -138,7 +138,7 @@ struct App { Context } -fn embed_field_access_generic(mut app T) { +fn embed_field_access_generic[T](mut app T) { app.Context = Context{ static_files: app.static_files } @@ -149,7 +149,7 @@ fn test_embed_field_access_generic() { embed_field_access_generic(mut app) } -fn embed_method_generic(app T) bool { +fn embed_method_generic[T](app T) bool { return app.test() } diff --git a/vlib/v/tests/type_name_in_if_test.v b/vlib/v/tests/type_name_in_if_test.v index 254ea26654..13eeb2bcf6 100644 --- a/vlib/v/tests/type_name_in_if_test.v +++ b/vlib/v/tests/type_name_in_if_test.v @@ -1,6 +1,6 @@ -struct Flag {} +struct Flag[T] {} -fn (f Flag) verify() { +fn (f Flag[T]) verify() { if T.name == 'int' { println('It is an int!') assert true @@ -8,6 +8,6 @@ fn (f Flag) verify() { } fn test_generic_type_name_in_if() { - flag := Flag{} + flag := Flag[int]{} flag.verify() } diff --git a/vlib/v/tests/type_name_test.v b/vlib/v/tests/type_name_test.v index 7d978c6fdc..bc22149812 100644 --- a/vlib/v/tests/type_name_test.v +++ b/vlib/v/tests/type_name_test.v @@ -1,4 +1,4 @@ -fn simple(p T) string { +fn simple[T](p T) string { tname := T.name assert tname == typeof(p).name return tname diff --git a/vlib/v/tests/typeof_test.v b/vlib/v/tests/typeof_test.v index 286b64c4bd..5e768cd351 100644 --- a/vlib/v/tests/typeof_test.v +++ b/vlib/v/tests/typeof_test.v @@ -147,11 +147,11 @@ fn test_typeof_on_fn() { assert typeof(myfn4).name == typeof(myfn4) } -fn type_name(v T) string { +fn type_name[T](v T) string { return typeof(v).name } -fn array_item_type(v []T) string { +fn array_item_type[T](v []T) string { return typeof(v[0]).name } diff --git a/vlib/v/token/keywords_matcher_trie.v b/vlib/v/token/keywords_matcher_trie.v index b347039618..eee07a37f6 100644 --- a/vlib/v/token/keywords_matcher_trie.v +++ b/vlib/v/token/keywords_matcher_trie.v @@ -62,7 +62,7 @@ pub fn (mut km KeywordsMatcherTrie) add_word(word string, value int) { // new_keywords_matcher_trie creates a new KeywordsMatcherTrie instance from a given map // with string keys, and integer or enum values. -pub fn new_keywords_matcher_trie(kw_map map[string]T) KeywordsMatcherTrie { +pub fn new_keywords_matcher_trie[T](kw_map map[string]T) KeywordsMatcherTrie { mut km := KeywordsMatcherTrie{ nodes: []&TrieNode{cap: 20} } @@ -85,7 +85,7 @@ pub fn new_keywords_matcher_from_array_trie(names []string) KeywordsMatcherTrie for i, name in names { m[name] = i } - return new_keywords_matcher_trie(m) + return new_keywords_matcher_trie[int](m) } // diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index e814195500..cd5e45a454 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -190,7 +190,7 @@ pub const ( keywords = build_keys() ) -pub const scanner_matcher = new_keywords_matcher_trie(keywords) +pub const scanner_matcher = new_keywords_matcher_trie[Kind](keywords) // build_keys genereates a map with keywords' string values: // Keywords['return'] == .key_return diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 266be5dd23..a8dd3b3e69 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -231,14 +231,14 @@ pub fn (mut ctx Context) text(s string) Result { } // Response HTTP_OK with json_s as payload with content-type `application/json` -pub fn (mut ctx Context) json(j T) Result { +pub fn (mut ctx Context) json[T](j T) Result { json_s := json.encode(j) ctx.send_response_to_client('application/json', json_s) return Result{} } // Response HTTP_OK with a pretty-printed JSON result -pub fn (mut ctx Context) json_pretty(j T) Result { +pub fn (mut ctx Context) json_pretty[T](j T) Result { json_s := json.encode_pretty(j) ctx.send_response_to_client('application/json', json_s) return Result{} @@ -377,8 +377,8 @@ interface DbInterface { } // run - start a new VWeb server, listening to all available addresses, at the specified `port` -pub fn run(global_app &T, port int) { - run_at(global_app, host: '', port: port, family: .ip6) or { panic(err.msg()) } +pub fn run[T](global_app &T, port int) { + run_at[T](global_app, host: '', port: port, family: .ip6) or { panic(err.msg()) } } [params] @@ -391,7 +391,7 @@ pub struct RunParams { // run_at - start a new VWeb server, listening only on a specific address `host`, at the specified `port` // Example: vweb.run_at(new_app(), vweb.RunParams{ host: 'localhost' port: 8099 family: .ip }) or { panic(err) } [manualfree] -pub fn run_at(global_app &T, params RunParams) ! { +pub fn run_at[T](global_app &T, params RunParams) ! { if params.port <= 0 || params.port > 65535 { return error('invalid port number `${params.port}`, it should be between 1 and 65535') } @@ -433,12 +433,12 @@ pub fn run_at(global_app &T, params RunParams) ! { eprintln('accept() failed with error: ${err.msg()}') continue } - spawn handle_conn(mut conn, mut request_app, routes) + spawn handle_conn[T](mut conn, mut request_app, routes) } } [manualfree] -fn handle_conn(mut conn net.TcpConn, mut app T, routes map[string]Route) { +fn handle_conn[T](mut conn net.TcpConn, mut app T, routes map[string]Route) { conn.set_read_timeout(30 * time.second) conn.set_write_timeout(30 * time.second) defer { @@ -503,7 +503,7 @@ fn handle_conn(mut conn net.TcpConn, mut app T, routes map[string]Route) { app.before_request() // Static handling - if serve_if_static(mut app, url) { + if serve_if_static[T](mut app, url) { // successfully served a static file return } @@ -604,7 +604,7 @@ fn route_matches(url_words []string, route_words []string) ?[]string { // check if request is for a static file and serves it // returns true if we served a static file, false otherwise [manualfree] -fn serve_if_static(mut app T, url urllib.URL) bool { +fn serve_if_static[T](mut app T, url urllib.URL) bool { // TODO: handle url parameters properly - for now, ignore them static_file := app.static_files[url.path] mime_type := app.static_mime_types[url.path] diff --git a/vlib/vweb/vweb_app_test.v b/vlib/vweb/vweb_app_test.v index 6abb642719..1db4755e7c 100644 --- a/vlib/vweb/vweb_app_test.v +++ b/vlib/vweb/vweb_app_test.v @@ -65,13 +65,13 @@ fn (mut app App) time_json_pretty() { }) } -struct ApiSuccessResponse { +struct ApiSuccessResponse[T] { success bool result T } -fn (mut app App) json_success(result T) vweb.Result { - response := ApiSuccessResponse{ +fn (mut app App) json_success[T](result T) vweb.Result { + response := ApiSuccessResponse[T]{ success: true result: result } @@ -80,8 +80,8 @@ fn (mut app App) json_success(result T) vweb.Result { } // should compile, this is a helper method, not exposed as a route -fn (mut app App) some_helper(result T) ApiSuccessResponse { - response := ApiSuccessResponse{ +fn (mut app App) some_helper[T](result T) ApiSuccessResponse[T] { + response := ApiSuccessResponse[T]{ success: true result: result } diff --git a/vlib/x/json2/README.md b/vlib/x/json2/README.md index 256ca93dcf..54d6ce8693 100644 --- a/vlib/x/json2/README.md +++ b/vlib/x/json2/README.md @@ -48,14 +48,14 @@ fn main() { //} // Encode a struct/type to JSON - encoded_json := json2.encode(person2) + encoded_json := json2.encode[Person](person2) } ``` -## Using `decode` and `encode` +## Using `decode[T]` and `encode[T]` > Codegen for this feature is still WIP. > You need to manually define the methods before using the module to structs. -In order to use the `decode` and `encode` function, you need to explicitly define +In order to use the `decode[T]` and `encode[T]` function, you need to explicitly define two methods: `from_json` and `to_json`. `from_json` accepts a `json2.Any` argument and inside of it you need to map the fields you're going to put into the type. As for `to_json` method, you just need to map the values into `json2.Any` @@ -91,9 +91,9 @@ fn (p Person) to_json() string { fn main() { resp := os.read_file('./person.json')! - person := json2.decode(resp)! + person := json2.decode[Person](resp)! println(person) // Person{name: 'Bob', age: 28, pets: ['Floof']} - person_json := json2.encode(person) + person_json := json2.encode[Person](person) println(person_json) // {"name": "Bob", "age": 28, "pets": ["Floof"]} } ``` @@ -128,7 +128,7 @@ fn (mut p Person) from_json(f json2.Any) { ### Null Values `x.json2` has a separate `null` type for differentiating an undefined value and a null value. -To verify that the field you're accessing is a `null`, use ` is json2.Null`. +To verify that the field you're accessing is a `null`, use `[typ] is json2.Null`. ```v ignore fn (mut p Person) from_json(f json2.Any) { diff --git a/vlib/x/json2/encoder.v b/vlib/x/json2/encoder.v index 5b913557da..57afb5cd29 100644 --- a/vlib/x/json2/encoder.v +++ b/vlib/x/json2/encoder.v @@ -39,8 +39,8 @@ const escaped_chars = [(r'\b').bytes(), (r'\f').bytes(), (r'\n').bytes(), (r'\r').bytes(), (r'\t').bytes()] // encode_value encodes a value to the specific writer. -pub fn (e &Encoder) encode_value(val T, mut wr io.Writer) ! { - e.encode_value_with_level(val, 1, mut wr)! +pub fn (e &Encoder) encode_value[T](val T, mut wr io.Writer) ! { + e.encode_value_with_level[T](val, 1, mut wr)! } fn (e &Encoder) encode_newline(level int, mut wr io.Writer) ! { @@ -132,7 +132,7 @@ fn (e &Encoder) encode_any(val Any, level int, mut wr io.Writer) ! { } } -fn (e &Encoder) encode_value_with_level(val T, level int, mut wr io.Writer) ! { +fn (e &Encoder) encode_value_with_level[T](val T, level int, mut wr io.Writer) ! { $if T is string { e.encode_string(val, mut wr)! } $else $if T is Any { @@ -160,7 +160,7 @@ fn (e &Encoder) encode_value_with_level(val T, level int, mut wr io.Writer) ! } } -fn (e &Encoder) encode_struct(val U, level int, mut wr io.Writer) ! { +fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! { wr.write([u8(`{`)])! mut i := 0 mut fields_len := 0 @@ -221,7 +221,7 @@ fn (e &Encoder) encode_struct(val U, level int, mut wr io.Writer) ! { wr.write([u8(`}`)])! } -fn (e &Encoder) encode_array(val U, level int, mut wr io.Writer) ! { +fn (e &Encoder) encode_array[U](val U, level int, mut wr io.Writer) ! { $if U is $Array { wr.write([u8(`[`)])! for i in 0 .. val.len { diff --git a/vlib/x/json2/integer_primitives_test.v b/vlib/x/json2/integer_primitives_test.v index 7ddcdc642e..f70e6c4748 100644 --- a/vlib/x/json2/integer_primitives_test.v +++ b/vlib/x/json2/integer_primitives_test.v @@ -43,10 +43,10 @@ pub fn (mut x IntegerValues) from_json(f json2.Any) { fn test_all_primitive_integer_types_are_encodable_and_decodable() { f := IntegerValues{1, 2, 3, 4, -1, -2, -3, -4} - s := json2.encode(f) + s := json2.encode[IntegerValues](f) dump(s) assert s == '{"ux8":1,"ux16":2,"ux32":3,"ux64":4,"sx8":-1,"sx16":-2,"sx32":-3,"sx64":-4}' - x := json2.decode(s)! + x := json2.decode[IntegerValues](s)! dump(x) assert x == f println('done') diff --git a/vlib/x/json2/json2.v b/vlib/x/json2/json2.v index cb2120a3e7..747f3ac1b6 100644 --- a/vlib/x/json2/json2.v +++ b/vlib/x/json2/json2.v @@ -18,7 +18,7 @@ pub fn fast_raw_decode(src string) !Any { } // decode is a generic function that decodes a JSON string into the target type. -pub fn decode(src string) !T { +pub fn decode[T](src string) !T { res := raw_decode(src)! mut typ := T{} typ.from_json(res) @@ -26,14 +26,14 @@ pub fn decode(src string) !T { } // encode is a generic function that encodes a type into a JSON string. -pub fn encode(val T) string { +pub fn encode[T](val T) string { mut sb := strings.new_builder(64) defer { unsafe { sb.free() } } default_encoder.encode_value(val, mut sb) or { dump(err) - default_encoder.encode_value(null, mut sb) or {} + default_encoder.encode_value[Null](null, mut sb) or {} } return sb.str() } diff --git a/vlib/x/json2/json_module_compatibility_test/json_test.v b/vlib/x/json2/json_module_compatibility_test/json_test.v index d2d74742bc..6dd135a395 100644 --- a/vlib/x/json2/json_module_compatibility_test/json_test.v +++ b/vlib/x/json2/json_module_compatibility_test/json_test.v @@ -29,7 +29,7 @@ fn test_simple() { name: 'João' } x := Employee{'Peter', 28, 95000.5, .worker, sub_employee} - s := json.encode(x) + s := json.encode[Employee](x) assert s == '{"name":"Peter","age":28,"salary":95000.5,"title":2,"sub_employee":{"name":"João","age":0,"salary":0.0,"title":0}}' // y := json.decode(s) or { // println(err) @@ -93,7 +93,7 @@ fn test_encode_user() { pets: 'foo' } expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}' - out := json.encode(usr) + out := json.encode[User](usr) // println(out) assert out == expected // Test json.encode on mutable pointers @@ -136,7 +136,7 @@ struct Message { fn test_encode_alias_struct() { expected := '{"id":"118499178790780929","ij":999998888}' msg := Message{'118499178790780929', 999998888} - out := json.encode(msg) + out := json.encode[Message](msg) assert out == expected } diff --git a/vlib/x/json2/temporary_workaround_types_id.v b/vlib/x/json2/temporary_workaround_types_id.v index adcb47c75a..b7779574b4 100644 --- a/vlib/x/json2/temporary_workaround_types_id.v +++ b/vlib/x/json2/temporary_workaround_types_id.v @@ -1,31 +1,31 @@ module json2 -fn gen_workaround(result T) T { +fn gen_workaround[T](result T) T { return result } -fn gen_workaround_result(result T) ?T { +fn gen_workaround_result[T](result T) ?T { return result } -fn gen_workaround_optional(result T) !T { +fn gen_workaround_optional[T](result T) !T { return result } const ( - string_type_idx = typeof(gen_workaround(unsafe { nil })).idx - result_string_type_idx = typeof(gen_workaround_result(unsafe { nil })).idx - optional_string_type_idx = typeof(gen_workaround_optional(unsafe { nil })).idx + string_type_idx = typeof(gen_workaround[string](unsafe { nil })).idx + result_string_type_idx = typeof(gen_workaround_result[string](unsafe { nil })).idx + optional_string_type_idx = typeof(gen_workaround_optional[string](unsafe { nil })).idx - int_type_idx = typeof(gen_workaround(unsafe { nil })).idx - result_int_type_idx = typeof(gen_workaround_result(unsafe { nil })).idx - optional_int_type_idx = typeof(gen_workaround_optional(unsafe { nil })).idx + int_type_idx = typeof(gen_workaround[int](unsafe { nil })).idx + result_int_type_idx = typeof(gen_workaround_result[int](unsafe { nil })).idx + optional_int_type_idx = typeof(gen_workaround_optional[int](unsafe { nil })).idx - int_array_type_idx = typeof(gen_workaround<[]int>(unsafe { nil })).idx - result_int_array_type_idx = typeof(gen_workaround_result<[]int>(unsafe { nil })).idx - optional_int_array_type_idx = typeof(gen_workaround_optional<[]int>(unsafe { nil })).idx + int_array_type_idx = typeof(gen_workaround[[]int](unsafe { nil })).idx + result_int_array_type_idx = typeof(gen_workaround_result[[]int](unsafe { nil })).idx + optional_int_array_type_idx = typeof(gen_workaround_optional[[]int](unsafe { nil })).idx - byte_array_type_idx = typeof(gen_workaround<[]byte>(unsafe { nil })).idx - result_byte_array_type_idx = typeof(gen_workaround_result<[]byte>(unsafe { nil })).idx - optional_byte_array_type_idx = typeof(gen_workaround_optional<[]byte>(unsafe { nil })).idx + byte_array_type_idx = typeof(gen_workaround[[]byte](unsafe { nil })).idx + result_byte_array_type_idx = typeof(gen_workaround_result[[]byte](unsafe { nil })).idx + optional_byte_array_type_idx = typeof(gen_workaround_optional[[]byte](unsafe { nil })).idx )