...

Source file src/internal/types/testdata/examples/types.go

Documentation: internal/types/testdata/examples

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file shows some examples of generic types.
     6  
     7  package p
     8  
     9  // List is just what it says - a slice of E elements.
    10  type List[E any] []E
    11  
    12  // A generic (parameterized) type must always be instantiated
    13  // before it can be used to designate the type of a variable
    14  // (including a struct field, or function parameter); though
    15  // for the latter cases, the provided type may be another type
    16  // parameter. So:
    17  var _ List[byte] = []byte{}
    18  
    19  // A generic binary tree might be declared as follows.
    20  type Tree[E any] struct {
    21  	left, right *Tree[E]
    22  	payload E
    23  }
    24  
    25  // A simple instantiation of Tree:
    26  var root1 Tree[int]
    27  
    28  // The actual type parameter provided may be a generic type itself:
    29  var root2 Tree[List[int]]
    30  
    31  // A couple of more complex examples.
    32  // We don't need extra parentheses around the element type of the slices on
    33  // the right (unlike when we use ()'s rather than []'s for type parameters).
    34  var _ List[List[int]] = []List[int]{}
    35  var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{}
    36  
    37  // Type parameters act like type aliases when used in generic types
    38  // in the sense that we can "emulate" a specific type instantiation
    39  // with type aliases.
    40  type T1[P any] struct {
    41  	f P
    42  }
    43  
    44  type T2[P any] struct {
    45  	f struct {
    46  		g P
    47  	}
    48  }
    49  
    50  var x1 T1[struct{ g int }]
    51  var x2 T2[int]
    52  
    53  func _() {
    54  	// This assignment is invalid because the types of x1, x2 are T1(...)
    55  	// and T2(...) respectively, which are two different defined types.
    56  	x1 = x2 // ERROR "assignment"
    57  
    58  	// This assignment is valid because the types of x1.f and x2.f are
    59  	// both struct { g int }; the type parameters act like type aliases
    60  	// and their actual names don't come into play here.
    61  	x1.f = x2.f
    62  }
    63  
    64  // We can verify this behavior using type aliases instead:
    65  type T1a struct {
    66  	f A1
    67  }
    68  type A1 = struct { g int }
    69  
    70  type T2a struct {
    71  	f struct {
    72  		g A2
    73  	}
    74  }
    75  type A2 = int
    76  
    77  var x1a T1a
    78  var x2a T2a
    79  
    80  func _() {
    81  	x1a = x2a // ERROR "assignment"
    82  	x1a.f = x2a.f
    83  }
    84  
    85  // Another interesting corner case are generic types that don't use
    86  // their type arguments. For instance:
    87  type T[P any] struct{}
    88  
    89  var xint T[int]
    90  var xbool T[bool]
    91  
    92  // Are these two variables of the same type? After all, their underlying
    93  // types are identical. We consider them to be different because each type
    94  // instantiation creates a new named type, in this case T<int> and T<bool>
    95  // even if their underlying types are identical. This is sensible because
    96  // we might still have methods that have different signatures or behave
    97  // differently depending on the type arguments, and thus we can't possibly
    98  // consider such types identical. Consequently:
    99  func _() {
   100  	xint = xbool // ERROR "assignment"
   101  }
   102  
   103  // Generic types cannot be used without instantiation.
   104  var _ T // ERROR "cannot use generic type T"
   105  var _ = T /* ERROR "cannot use generic type T" */ (0)
   106  
   107  // In type context, generic (parameterized) types cannot be parenthesized before
   108  // being instantiated. See also NOTES entry from 12/4/2019.
   109  var _ (T /* ERROR "cannot use generic type T" */ )[ /* ERRORx `unexpected \[|expected ';'` */ int]
   110  
   111  // All types may be parameterized, including interfaces.
   112  type I1[T any] interface{
   113  	m1(T)
   114  }
   115  
   116  // There is no such thing as a variadic generic type.
   117  type _[T ... /* ERROR "invalid use of '...'" */ any] struct{}
   118  
   119  // Generic interfaces may be embedded as one would expect.
   120  type I2 interface {
   121  	I1(int)     // method!
   122  	I1[string]  // embedded I1
   123  }
   124  
   125  func _() {
   126  	var x I2
   127  	x.I1(0)
   128  	x.m1("foo")
   129  }
   130  
   131  type I0 interface {
   132  	m0()
   133  }
   134  
   135  type I3 interface {
   136  	I0
   137  	I1[bool]
   138  	m(string)
   139  }
   140  
   141  func _() {
   142  	var x I3
   143  	x.m0()
   144  	x.m1(true)
   145  	x.m("foo")
   146  }
   147  
   148  type _ struct {
   149  	( /* ERROR "cannot parenthesize" */ int8)
   150  	( /* ERROR "cannot parenthesize" */ *int16)
   151  	*( /* ERROR "cannot parenthesize" */ int32)
   152  	List[int]
   153  
   154  	int8 /* ERROR "int8 redeclared" */
   155  	*int16 /* ERROR "int16 redeclared" */
   156  	List /* ERROR "List redeclared" */ [int]
   157  }
   158  
   159  // Issue #45639: We don't allow this anymore. Keep this code
   160  //               in case we decide to revisit this decision.
   161  //
   162  // It's possible to declare local types whose underlying types
   163  // are type parameters. As with ordinary type definitions, the
   164  // types underlying properties are "inherited" but the methods
   165  // are not.
   166  // func _[T interface{ m(); ~int }]() {
   167  // 	type L T
   168  // 	var x L
   169  //
   170  // 	// m is not defined on L (it is not "inherited" from
   171  // 	// its underlying type).
   172  // 	x.m /* ERROR "x.m undefined" */ ()
   173  //
   174  // 	// But the properties of T, such that as that it supports
   175  // 	// the operations of the types given by its type bound,
   176  // 	// are also the properties of L.
   177  // 	x++
   178  // 	_ = x - x
   179  //
   180  // 	// On the other hand, if we define a local alias for T,
   181  // 	// that alias stands for T as expected.
   182  // 	type A = T
   183  // 	var y A
   184  // 	y.m()
   185  // 	_ = y < 0
   186  // }
   187  
   188  // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
   189  // // It is not permitted to declare a local type whose underlying
   190  // // type is a type parameter not declared by that type declaration.
   191  // func _[T any]() {
   192  // 	type _ T         // ERROR "cannot use function type parameter T as RHS in type declaration"
   193  // 	type _ [_ any] T // ERROR "cannot use function type parameter T as RHS in type declaration"
   194  // }
   195  
   196  // As a special case, an explicit type argument may be omitted
   197  // from a type parameter bound if the type bound expects exactly
   198  // one type argument. In that case, the type argument is the
   199  // respective type parameter to which the type bound applies.
   200  // Note: We may not permit this syntactic sugar at first.
   201  // Note: This is now disabled. All examples below are adjusted.
   202  type Adder[T any] interface {
   203  	Add(T) T
   204  }
   205  
   206  // We don't need to explicitly instantiate the Adder bound
   207  // if we have exactly one type parameter.
   208  func Sum[T Adder[T]](list []T) T {
   209  	var sum T
   210  	for _, x := range list {
   211  		sum = sum.Add(x)
   212  	}
   213  	return sum
   214  }
   215  
   216  // Valid and invalid variations.
   217  type B0 any
   218  type B1[_ any] any
   219  type B2[_, _ any] any
   220  
   221  func _[T1 B0]() {}
   222  func _[T1 B1[T1]]() {}
   223  func _[T1 B2 /* ERRORx `cannot use generic type .* without instantiation` */ ]() {}
   224  
   225  func _[T1, T2 B0]() {}
   226  func _[T1 B1[T1], T2 B1[T2]]() {}
   227  func _[T1, T2 B2 /* ERRORx `cannot use generic type .* without instantiation` */ ]() {}
   228  
   229  func _[T1 B0, T2 B1[T2]]() {} // here B1 applies to T2
   230  
   231  // When the type argument is left away, the type bound is
   232  // instantiated for each type parameter with that type
   233  // parameter.
   234  // Note: We may not permit this syntactic sugar at first.
   235  func _[A Adder[A], B Adder[B], C Adder[A]]() {
   236  	var a A // A's type bound is Adder[A]
   237  	a = a.Add(a)
   238  	var b B // B's type bound is Adder[B]
   239  	b = b.Add(b)
   240  	var c C // C's type bound is Adder[A]
   241  	a = c.Add(a)
   242  }
   243  
   244  // The type of variables (incl. parameters and return values) cannot
   245  // be an interface with type constraints or be/embed comparable.
   246  type I interface {
   247  	~int
   248  }
   249  
   250  var (
   251  	_ interface /* ERROR "contains type constraints" */ {~int}
   252  	_ I /* ERROR "contains type constraints" */
   253  )
   254  
   255  func _(I /* ERROR "contains type constraints" */ )
   256  func _(x, y, z I /* ERROR "contains type constraints" */ )
   257  func _() I /* ERROR "contains type constraints" */
   258  
   259  func _() {
   260  	var _ I /* ERROR "contains type constraints" */
   261  }
   262  
   263  type C interface {
   264  	comparable
   265  }
   266  
   267  var _ comparable /* ERROR "comparable" */
   268  var _ C /* ERROR "comparable" */
   269  
   270  func _(_ comparable /* ERROR "comparable" */ , _ C /* ERROR "comparable" */ )
   271  
   272  func _() {
   273  	var _ comparable /* ERROR "comparable" */
   274  	var _ C /* ERROR "comparable" */
   275  }
   276  
   277  // Type parameters are never const types, i.e., it's
   278  // not possible to declare a constant of type parameter type.
   279  // (If a type set contains just a single const type, we could
   280  // allow it, but such type sets don't make much sense in the
   281  // first place.)
   282  func _[T interface{~int|~float64}]() {
   283  	// not valid
   284  	const _ = T /* ERROR "not constant" */ (0)
   285  	const _ T /* ERROR "invalid constant type T" */ = 1
   286  
   287  	// valid
   288  	var _ = T(0)
   289  	var _ T = 1
   290  	_ = T(0)
   291  }
   292  
   293  // It is possible to create composite literals of type parameter
   294  // type as long as it's possible to create a composite literal
   295  // of the core type of the type parameter's constraint.
   296  func _[P interface{ ~[]int }]() P {
   297  	return P{}
   298  	return P{1, 2, 3}
   299  }
   300  
   301  func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P {
   302  	x := P{}
   303  	return P{{}}
   304  	return P{E{}}
   305  	return P{E{"foo": x}}
   306  	return P{{"foo": x}, {}}
   307  }
   308  
   309  // This is a degenerate case with a singleton type set, but we can create
   310  // composite literals even if the core type is a defined type.
   311  type MyInts []int
   312  
   313  func _[P MyInts]() P {
   314  	return P{}
   315  }
   316  

View as plain text