aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/testdata/examples/functions.go2
blob: 154d09f52878e226958a11ba8c5b4e79a42c64c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file shows some examples of type-parameterized functions.

package p

// Reverse is a generic function that takes a []T argument and
// reverses that slice in place.
func Reverse[T any](list []T) {
	i := 0
	j := len(list)-1
	for i < j {
		list[i], list[j] = list[j], list[i]
		i++
		j--
	}
}

func _() {
	// Reverse can be called with an explicit type argument.
	Reverse[int](nil)
	Reverse[string]([]string{"foo", "bar"})
	Reverse[struct{x, y int}]([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}})

	// Since the type parameter is used for an incoming argument,
	// it can be inferred from the provided argument's type.
	Reverse([]string{"foo", "bar"})
	Reverse([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}})

	// But the incoming argument must have a type, even if it's a
	// default type. An untyped nil won't work.
	// Reverse(nil) // this won't type-check

	// A typed nil will work, though.
	Reverse([]int(nil))
}

// Certain functions, such as the built-in `new` could be written using
// type parameters.
func new[T any]() *T {
	var x T
	return &x
}

// When calling our own `new`, we need to pass the type parameter
// explicitly since there is no (value) argument from which the
// result type could be inferred. We don't try to infer the
// result type from the assignment to keep things simple and
// easy to understand.
var _ = new[int]()
var _ *float64 = new[float64]() // the result type is indeed *float64

// A function may have multiple type parameters, of course.
func foo[A, B, C any](a A, b []B, c *C) B {
	// do something here
	return b[0]
}

// As before, we can pass type parameters explicitly.
var s = foo[int, string, float64](1, []string{"first"}, new[float64]())

// Or we can use type inference.
var _ float64 = foo(42, []float64{1.0}, &s)

// Type inference works in a straight-forward manner even
// for variadic functions.
func variadic[A, B any](A, B, ...B) int

// var _ = variadic(1) // ERROR not enough arguments
var _ = variadic(1, 2.3)
var _ = variadic(1, 2.3, 3.4, 4.5)
var _ = variadic[int, float64](1, 2.3, 3.4, 4)

// Type inference also works in recursive function calls where
// the inferred type is the type parameter of the caller.
func f1[T any](x T) {
	f1(x)
}

func f2a[T any](x, y T) {
	f2a(x, y)
}

func f2b[T any](x, y T) {
	f2b(y, x)
}

func g2a[P, Q any](x P, y Q) {
	g2a(x, y)
}

func g2b[P, Q any](x P, y Q) {
	g2b(y, x)
}

// Here's an example of a recursive function call with variadic
// arguments and type inference inferring the type parameter of
// the caller (i.e., itself).
func max[T interface{ ~int }](x ...T) T {
	var x0 T
	if len(x) > 0 {
		x0 = x[0]
	}
	if len(x) > 1 {
		x1 := max(x[1:]...)
		if x1 > x0 {
			return x1
		}
	}
	return x0
}

// When inferring channel types, the channel direction is ignored
// for the purpose of type inference. Once the type has been in-
// fered, the usual parameter passing rules are applied.
// Thus even if a type can be inferred successfully, the function
// call may not be valid.

func fboth[T any](chan T)
func frecv[T any](<-chan T)
func fsend[T any](chan<- T)

func _() {
	var both chan int
	var recv <-chan int
	var send chan<-int

	fboth(both)
	fboth(recv /* ERROR cannot use */ )
	fboth(send /* ERROR cannot use */ )

	frecv(both)
	frecv(recv)
	frecv(send /* ERROR cannot use */ )

	fsend(both)
	fsend(recv /* ERROR cannot use */)
	fsend(send)
}

func ffboth[T any](func(chan T))
func ffrecv[T any](func(<-chan T))
func ffsend[T any](func(chan<- T))

func _() {
	var both func(chan int)
	var recv func(<-chan int)
	var send func(chan<- int)

	ffboth(both)
	ffboth(recv /* ERROR cannot use */ )
	ffboth(send /* ERROR cannot use */ )

	ffrecv(both /* ERROR cannot use */ )
	ffrecv(recv)
	ffrecv(send /* ERROR cannot use */ )

	ffsend(both /* ERROR cannot use */ )
	ffsend(recv /* ERROR cannot use */ )
	ffsend(send)
}

// When inferring elements of unnamed composite parameter types,
// if the arguments are defined types, use their underlying types.
// Even though the matching types are not exactly structurally the
// same (one is a type literal, the other a named type), because
// assignment is permitted, parameter passing is permitted as well,
// so type inference should be able to handle these cases well.

func g1[T any]([]T)
func g2[T any]([]T, T)
func g3[T any](*T, ...T)

func _() {
	type intSlize []int
	g1([]int{})
	g1(intSlize{})
	g2(nil, 0)

	type myString string
	var s1 string
	g3(nil, "1", myString("2"), "3")
	g3(&s1, "1", myString /* ERROR does not match */ ("2"), "3")
	_ = s1

	type myStruct struct{x int}
	var s2 myStruct
	g3(nil, struct{x int}{}, myStruct{})
	g3(&s2, struct{x int}{}, myStruct{})
	g3(nil, myStruct{}, struct{x int}{})
	g3(&s2, myStruct{}, struct{x int}{})
}

// Here's a realistic example.

func append[T any](s []T, t ...T) []T

func _() {
	var f func()
	type Funcs []func()
	var funcs Funcs
	_ = append(funcs, f)
}

// Generic type declarations cannot have empty type parameter lists
// (that would indicate a slice type). Thus, generic functions cannot
// have empty type parameter lists, either. This is a syntax error.

func h[] /* ERROR empty type parameter list */ ()

func _() {
	h[] /* ERROR operand */ ()
}