Source file test/typeparam/boundmethod.go

     1  // run
     2  
     3  // Copyright 2021 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // This test illustrates how a type bound method (String below) can be implemented
     8  // either by a concrete type (myint below) or an instantiated generic type
     9  // (StringInt[myint] below).
    10  
    11  package main
    12  
    13  import (
    14  	"fmt"
    15  	"reflect"
    16  	"strconv"
    17  )
    18  
    19  type myint int
    20  
    21  //go:noinline
    22  func (m myint) String() string {
    23  	return strconv.Itoa(int(m))
    24  }
    25  
    26  type Stringer interface {
    27  	String() string
    28  }
    29  
    30  func stringify[T Stringer](s []T) (ret []string) {
    31  	for _, v := range s {
    32  		// Test normal bounds method call on type param
    33  		x1 := v.String()
    34  
    35  		// Test converting type param to its bound interface first
    36  		v1 := Stringer(v)
    37  		x2 := v1.String()
    38  
    39  		// Test method expression with type param type
    40  		f1 := T.String
    41  		x3 := f1(v)
    42  
    43  		// Test creating and calling closure equivalent to the method expression
    44  		f2 := func(v1 T) string {
    45  			return Stringer(v1).String()
    46  		}
    47  		x4 := f2(v)
    48  
    49  		if x1 != x2 || x2 != x3 || x3 != x4 {
    50  			panic(fmt.Sprintf("Mismatched values %v, %v, %v, %v\n", x1, x2, x3, x4))
    51  		}
    52  
    53  		ret = append(ret, v.String())
    54  	}
    55  	return ret
    56  }
    57  
    58  type Ints interface {
    59  	~int32 | ~int
    60  }
    61  
    62  // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
    63  // type StringInt[T Ints] T
    64  //
    65  // //go:noinline
    66  // func (m StringInt[T]) String() string {
    67  // 	return strconv.Itoa(int(m))
    68  // }
    69  
    70  type StringStruct[T Ints] struct {
    71  	f T
    72  }
    73  
    74  func (m StringStruct[T]) String() string {
    75  	return strconv.Itoa(int(m.f))
    76  }
    77  
    78  func main() {
    79  	x := []myint{myint(1), myint(2), myint(3)}
    80  
    81  	// stringify on a normal type, whose bound method is associated with the base type.
    82  	got := stringify(x)
    83  	want := []string{"1", "2", "3"}
    84  	if !reflect.DeepEqual(got, want) {
    85  		panic(fmt.Sprintf("got %s, want %s", got, want))
    86  	}
    87  
    88  	// For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
    89  	// x2 := []StringInt[myint]{StringInt[myint](5), StringInt[myint](7), StringInt[myint](6)}
    90  	//
    91  	// // stringify on an instantiated type, whose bound method is associated with
    92  	// // the generic type StringInt[T], which maps directly to T.
    93  	// got2 := stringify(x2)
    94  	// want2 := []string{"5", "7", "6"}
    95  	// if !reflect.DeepEqual(got2, want2) {
    96  	// 	panic(fmt.Sprintf("got %s, want %s", got2, want2))
    97  	// }
    98  
    99  	// stringify on an instantiated type, whose bound method is associated with
   100  	// the generic type StringStruct[T], which maps to a struct containing T.
   101  	x3 := []StringStruct[myint]{StringStruct[myint]{f: 11}, StringStruct[myint]{f: 10}, StringStruct[myint]{f: 9}}
   102  
   103  	got3 := stringify(x3)
   104  	want3 := []string{"11", "10", "9"}
   105  	if !reflect.DeepEqual(got3, want3) {
   106  		panic(fmt.Sprintf("got %s, want %s", got3, want3))
   107  	}
   108  }
   109  

View as plain text