summaryrefslogtreecommitdiffstats
path: root/test/typeparam/settable.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /test/typeparam/settable.go
parentInitial commit. (diff)
downloadgolang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz
golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/typeparam/settable.go')
-rw-r--r--test/typeparam/settable.go123
1 files changed, 123 insertions, 0 deletions
diff --git a/test/typeparam/settable.go b/test/typeparam/settable.go
new file mode 100644
index 0000000..56cf367
--- /dev/null
+++ b/test/typeparam/settable.go
@@ -0,0 +1,123 @@
+// run
+
+// Copyright 2021 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.
+
+package main
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Various implementations of fromStrings().
+
+type Setter[B any] interface {
+ Set(string)
+ *B
+}
+
+// Takes two type parameters where PT = *T
+func fromStrings1[T any, PT Setter[T]](s []string) []T {
+ result := make([]T, len(s))
+ for i, v := range s {
+ // The type of &result[i] is *T which is in the type list
+ // of Setter, so we can convert it to PT.
+ p := PT(&result[i])
+ // PT has a Set method.
+ p.Set(v)
+ }
+ return result
+}
+
+func fromStrings1a[T any, PT Setter[T]](s []string) []PT {
+ result := make([]PT, len(s))
+ for i, v := range s {
+ // The type new(T) is *T which is in the type list
+ // of Setter, so we can convert it to PT.
+ result[i] = PT(new(T))
+ p := result[i]
+ // PT has a Set method.
+ p.Set(v)
+ }
+ return result
+}
+
+// Takes one type parameter and a set function
+func fromStrings2[T any](s []string, set func(*T, string)) []T {
+ results := make([]T, len(s))
+ for i, v := range s {
+ set(&results[i], v)
+ }
+ return results
+}
+
+type Setter2 interface {
+ Set(string)
+}
+
+// Takes only one type parameter, but causes a panic (see below)
+func fromStrings3[T Setter2](s []string) []T {
+ results := make([]T, len(s))
+ for i, v := range s {
+ // Panics if T is a pointer type because receiver is T(nil).
+ results[i].Set(v)
+ }
+ return results
+}
+
+// Two concrete types with the appropriate Set method.
+
+type SettableInt int
+
+func (p *SettableInt) Set(s string) {
+ i, err := strconv.Atoi(s)
+ if err != nil {
+ panic(err)
+ }
+ *p = SettableInt(i)
+}
+
+type SettableString struct {
+ s string
+}
+
+func (x *SettableString) Set(s string) {
+ x.s = s
+}
+
+func main() {
+ s := fromStrings1[SettableInt, *SettableInt]([]string{"1"})
+ if len(s) != 1 || s[0] != 1 {
+ panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
+ }
+
+ s2 := fromStrings1a[SettableInt, *SettableInt]([]string{"1"})
+ if len(s2) != 1 || *s2[0] != 1 {
+ x := 1
+ panic(fmt.Sprintf("got %v, want %v", s2, []*int{&x}))
+ }
+
+ // Test out constraint type inference, which should determine that the second
+ // type param is *SettableString.
+ ps := fromStrings1[SettableString]([]string{"x", "y"})
+ if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) {
+ panic(s)
+ }
+
+ s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) })
+ if len(s) != 1 || s[0] != 1 {
+ panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
+ }
+
+ defer func() {
+ if recover() == nil {
+ panic("did not panic as expected")
+ }
+ }()
+ // This should type check but should panic at run time,
+ // because it will make a slice of *SettableInt and then call
+ // Set on a nil value.
+ fromStrings3[*SettableInt]([]string{"1"})
+}