github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/typeparams/example/README.md (about)

     1  <!-- Autogenerated by weave; DO NOT EDIT -->
     2  <!-- To regenerate the readme, run: -->
     3  <!-- go run golang.org/x/example/gotypes@latest generic-go-types.md -->
     4  
     5  # Updating tools to support type parameters.
     6  
     7  This guide is maintained by Rob Findley (`rfindley@google.com`).
     8  
     9  **status**: this document is currently a work-in-progress. See
    10  [golang/go#50447](https://go.dev/issues/50447) for more details.
    11  
    12  1. [Introduction](#introduction)
    13  1. [Summary of new language features and their APIs](#summary-of-new-language-features-and-their-apis)
    14  1. [Examples](#examples)
    15  	1. [Generic types](#generic-types)
    16  	1. [Constraint Interfaces](#constraint-interfaces)
    17  	1. [Instantiation](#instantiation)
    18  1. [Updating tools while building at older Go versions](#updating-tools-while-building-at-older-go-versions)
    19  1. [Further help](#further-help)
    20  
    21  # Introduction
    22  
    23  With Go 1.18, Go now supports generic programming via type parameters. This
    24  document is intended to serve as a guide for tool authors that want to update
    25  their tools to support the new language constructs introduced for generic Go.
    26  
    27  This guide assumes some knowledge of the language changes to support generics.
    28  See the following references for more information:
    29  
    30  - The [original proposal](https://go.dev/issue/43651) for type parameters.
    31  - The [addendum for type sets](https://go.dev/issue/45346).
    32  - The [latest language specfication](https://tip.golang.org/ref/spec) (still in-progress as of 2021-01-11).
    33  - The proposals for new APIs in
    34    [go/token and go/ast](https://go.dev/issue/47781), and in
    35    [go/types](https://go.dev/issue/47916).
    36  
    37  It also assumes existing knowledge of `go/ast` and `go/types`. If you're just
    38  getting started,
    39  [x/example/gotypes](https://github.com/golang/example/tree/master/gotypes) is
    40  a great introduction (and was the inspiration for this guide).
    41  
    42  # Summary of new language features and their APIs
    43  
    44  While generic Go programming is a large change to the language, at a high level
    45  it introduces only a few new concepts. Specifically, we can break down our
    46  discussion into the following three broad categories. In each category, the
    47  relevant new APIs are listed (some constructors and getters/setters may be
    48  elided where they are trivial).
    49  
    50  **Generic types**. Types and functions may be _generic_, meaning their
    51  declaration has a non-empty _type parameter list_: as in `type  List[T any]
    52  ...` or `func f[T1, T2 any]() { ... }`. Type parameter lists define placeholder
    53  types (_type parameters_), scoped to the declaration, which may be substituted
    54  by any type satisfying their corresponding _constraint interface_ to
    55  _instantiate_ a new type or function.
    56  
    57  Generic types may have methods, which declare `receiver type parameters` via
    58  their receiver type expression: `func (r T[P1, ..., PN]) method(...) (...)
    59  {...}`.
    60  
    61  _New APIs_:
    62   - The field `ast.TypeSpec.TypeParams` holds the type parameter list syntax for
    63     type declarations.
    64   - The field `ast.FuncType.TypeParams` holds the type parameter list syntax for
    65     function declarations.
    66   - The type `types.TypeParam` is a `types.Type` representing a type parameter.
    67     On this type, the `Constraint` and `SetConstraint` methods allow
    68     getting/setting the constraint, the `Index` method returns the index of the
    69     type parameter in the type parameter list that declares it, and the `Obj`
    70     method returns the object declared in the declaration scope for the type
    71     parameter (a `types.TypeName`).
    72   - The type `types.TypeParamList` holds a list of type parameters.
    73   - The method `types.Named.TypeParams` returns the type parameters for a type
    74     declaration.
    75   - The method `types.Named.SetTypeParams` sets type parameters on a defined
    76     type.
    77   - The function `types.NewSignatureType` creates a new (possibly generic)
    78     signature type.
    79   - The method `types.Signature.RecvTypeParams` returns the receiver type
    80     parameters for a method.
    81   - The method `types.Signature.TypeParams` returns the type parameters for
    82     a function.
    83  
    84  **Constraint Interfaces**: type parameter constraints are interfaces, expressed
    85  via an interface type expression. Interfaces that are only used in constraint
    86  position are permitted new embedded elements composed of tilde expressions
    87  (`~T`) and unions (`A | B | ~C`). The new builtin interface type `comparable`
    88  is implemented by types for which `==` and `!=` are valid. As a special case,
    89  the `interface` keyword may be omitted from constraint expressions if it may be
    90  implied (in which case we say the interface is _implicit_).
    91  
    92  _New APIs_:
    93   - The constant `token.TILDE` is used to represent tilde expressions as an
    94     `ast.UnaryExpr`.
    95   - Union expressions are represented as an `ast.BinaryExpr` using `|`. This
    96     means that `ast.BinaryExpr` may now be both a type and value expression.
    97   - The method `types.Interface.IsImplicit` reports whether the `interface`
    98     keyword was elided from this interface.
    99   - The method `types.Interface.MarkImplicit` marks an interface as being
   100     implicit.
   101   - The method `types.Interface.IsComparable` reports whether every type in an
   102     interface's type set is comparable.
   103   - The method `types.Interface.IsMethodSet` reports whether an interface is
   104     defined entirely by its methods (has no _specific types_).
   105   - The type `types.Union` is a type that represents an embedded union
   106     expression in an interface. May only appear as an embedded element in
   107     interfaces.
   108   - The type `types.Term` represents a (possibly tilde) term of a union.
   109  
   110  **Instantiation**: generic types and functions may be _instantiated_ to create
   111  non-generic types and functions by providing _type arguments_ (`var x T[int]`).
   112  Function type arguments may be _inferred_ via function arguments, or via
   113  type parameter constraints.
   114  
   115  _New APIs_:
   116   - The type `ast.IndexListExpr` holds index expressions with multiple indices,
   117     as occurs in instantiation expressions with multiple type arguments, or in
   118     receivers with multiple type parameters.
   119   - The function `types.Instantiate` instantiates a generic type with type arguments.
   120   - The type `types.Context` is an opaque instantiation context that may be
   121     shared to reduce duplicate instances.
   122   - The field `types.Config.Context` holds a shared `Context` to use for
   123     instantiation while type-checking.
   124   - The type `types.TypeList` holds a list of types.
   125   - The type `types.ArgumentError` holds an error associated with a specific
   126     argument index. Used to represent instantiation errors.
   127   - The field `types.Info.Instances` maps instantiated identifiers to information
   128     about the resulting type instance.
   129   - The type `types.Instance` holds information about a type or function
   130     instance.
   131   - The method `types.Named.TypeArgs` reports the type arguments used to
   132     instantiate a named type.
   133  
   134  # Examples
   135  
   136  The following examples demonstrate the new APIs above, and discuss their
   137  properties. All examples are runnable, contained in subdirectories of the
   138  directory holding this README.
   139  
   140  ## Generic types
   141  
   142  ### Type parameter lists
   143  
   144  Suppose we want to understand the generic library below, which defines a generic
   145  `Pair`, a constraint interface `Constraint`, and a generic function `MakePair`.
   146  
   147  ```
   148  package main
   149  
   150  type Constraint interface {
   151  	Value() interface{}
   152  }
   153  
   154  type Pair[L, R any] struct {
   155  	left  L
   156  	right R
   157  }
   158  
   159  func MakePair[L, R Constraint](l L, r R) Pair[L, R] {
   160  	return Pair[L, R]{l, r}
   161  }
   162  ```
   163  
   164  We can use the new `TypeParams` fields in `ast.TypeSpec` and `ast.FuncType` to
   165  access the syntax of the type parameter list. From there, we can access type
   166  parameter types in at least three ways:
   167   - by looking up type parameter definitions in `types.Info`
   168   - by calling `TypeParams()` on `types.Named` or `types.Signature`
   169   - by looking up type parameter objects in the declaration scope. Note that
   170     there now may be a scope associated with an `ast.TypeSpec` node.
   171  
   172  ```
   173  func PrintTypeParams(fset *token.FileSet, file *ast.File) error {
   174  	conf := types.Config{Importer: importer.Default()}
   175  	info := &types.Info{
   176  		Scopes: make(map[ast.Node]*types.Scope),
   177  		Defs:   make(map[*ast.Ident]types.Object),
   178  	}
   179  	_, err := conf.Check("hello", fset, []*ast.File{file}, info)
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	// For convenience, we can use ast.Inspect to find the nodes we want to
   185  	// investigate.
   186  	ast.Inspect(file, func(n ast.Node) bool {
   187  		var name *ast.Ident                  // the name of the generic object, or nil
   188  		var tparamSyntax *ast.FieldList      // the list of type parameter fields
   189  		var tparamTypes *types.TypeParamList // the list of type parameter types
   190  		var scopeNode ast.Node               // the node associated with the declaration scope
   191  
   192  		switch n := n.(type) {
   193  		case *ast.TypeSpec:
   194  			name = n.Name
   195  			tparamSyntax = n.TypeParams
   196  			tparamTypes = info.Defs[name].Type().(*types.Named).TypeParams()
   197  			name = n.Name
   198  			scopeNode = n
   199  		case *ast.FuncDecl:
   200  			name = n.Name
   201  			tparamSyntax = n.Type.TypeParams
   202  			tparamTypes = info.Defs[name].Type().(*types.Signature).TypeParams()
   203  			scopeNode = n.Type
   204  		}
   205  
   206  		if name == nil {
   207  			return true // not a generic object
   208  		}
   209  
   210  		// Option 1: find type parameters by looking at their declaring field list.
   211  		if tparamSyntax != nil {
   212  			fmt.Printf("%s has a type parameter field list with %d fields\n", name.Name, tparamSyntax.NumFields())
   213  			for _, field := range tparamSyntax.List {
   214  				for _, name := range field.Names {
   215  					tparam := info.Defs[name]
   216  					fmt.Printf("  field %s defines an object %q\n", name.Name, tparam)
   217  				}
   218  			}
   219  		} else {
   220  			fmt.Printf("%s does not have a type parameter list\n", name.Name)
   221  		}
   222  
   223  		// Option 2: find type parameters via the TypeParams() method on the
   224  		// generic type.
   225  		fmt.Printf("%s has %d type parameters:\n", name.Name, tparamTypes.Len())
   226  		for i := 0; i < tparamTypes.Len(); i++ {
   227  			tparam := tparamTypes.At(i)
   228  			fmt.Printf("  %s has constraint %s\n", tparam, tparam.Constraint())
   229  		}
   230  
   231  		// Option 3: find type parameters by looking in the declaration scope.
   232  		scope, ok := info.Scopes[scopeNode]
   233  		if ok {
   234  			fmt.Printf("%s has a scope with %d objects:\n", name.Name, scope.Len())
   235  			for _, name := range scope.Names() {
   236  				fmt.Printf("  %s is a %T\n", name, scope.Lookup(name))
   237  			}
   238  		} else {
   239  			fmt.Printf("%s does not have a scope\n", name.Name)
   240  		}
   241  
   242  		return true
   243  	})
   244  	return nil
   245  }
   246  ```
   247  
   248  This program produces the following output. Note that not every type spec has
   249  a scope.
   250  
   251  ```
   252  > go run github.com/powerman/golang-tools/internal/typeparams/example/findtypeparams
   253  Constraint does not have a type parameter list
   254  Constraint has 0 type parameters:
   255  Constraint does not have a scope
   256  Pair has a type parameter field list with 2 fields
   257    field L defines an object "type parameter L any"
   258    field R defines an object "type parameter R any"
   259  Pair has 2 type parameters:
   260    L has constraint any
   261    R has constraint any
   262  Pair has a scope with 2 objects:
   263    L is a *types.TypeName
   264    R is a *types.TypeName
   265  MakePair has a type parameter field list with 2 fields
   266    field L defines an object "type parameter L hello.Constraint"
   267    field R defines an object "type parameter R hello.Constraint"
   268  MakePair has 2 type parameters:
   269    L has constraint hello.Constraint
   270    R has constraint hello.Constraint
   271  MakePair has a scope with 4 objects:
   272    L is a *types.TypeName
   273    R is a *types.TypeName
   274    l is a *types.Var
   275    r is a *types.Var
   276  ```
   277  
   278  ### Methods on generic types
   279  
   280  **TODO**
   281  
   282  ## Constraint Interfaces
   283  
   284  ### New interface elements
   285  
   286  **TODO**
   287  
   288  ### Implicit interfaces
   289  
   290  **TODO**
   291  
   292  ### Type sets
   293  
   294  **TODO**
   295  
   296  ## Instantiation
   297  
   298  ### Finding instantiated types
   299  
   300  **TODO**
   301  
   302  ### Creating new instantiated types
   303  
   304  **TODO**
   305  
   306  ### Using a shared context
   307  
   308  **TODO**
   309  
   310  # Updating tools while building at older Go versions
   311  
   312  In the examples above, we can see how a lot of the new APIs integrate with
   313  existing usage of `go/ast` or `go/types`. However, most tools still need to
   314  build at older Go versions, and handling the new language constructs in-line
   315  will break builds at older Go versions.
   316  
   317  For this purpose, the `x/exp/typeparams` package provides functions and types
   318  that proxy the new APIs (with stub implementations at older Go versions).
   319  **NOTE**: does not yet exist -- see
   320  [golang/go#50447](https://go.dev/issues/50447) for more information.
   321  
   322  # Further help
   323  
   324  If you're working on updating a tool to support generics, and need help, please
   325  feel free to reach out for help in any of the following ways:
   326   - Via the [golang-tools](https://groups.google.com/g/golang-tools) mailing list.
   327   - Directly to me via email (`rfindley@google.com`).
   328   - For bugs, you can [file an issue](https://github.com/golang/go/issues/new/choose).