diff options
Diffstat (limited to 'internal/typeparams/example/README.md')
-rw-r--r-- | internal/typeparams/example/README.md | 328 |
1 files changed, 0 insertions, 328 deletions
diff --git a/internal/typeparams/example/README.md b/internal/typeparams/example/README.md deleted file mode 100644 index 9877735bf..000000000 --- a/internal/typeparams/example/README.md +++ /dev/null @@ -1,328 +0,0 @@ -<!-- Autogenerated by weave; DO NOT EDIT --> -<!-- To regenerate the readme, run: --> -<!-- go run golang.org/x/example/gotypes@latest generic-go-types.md --> - -# Updating tools to support type parameters. - -This guide is maintained by Rob Findley (`rfindley@google.com`). - -**status**: this document is currently a work-in-progress. See -[golang/go#50447](https://go.dev/issues/50447) for more details. - -1. [Introduction](#introduction) -1. [Summary of new language features and their APIs](#summary-of-new-language-features-and-their-apis) -1. [Examples](#examples) - 1. [Generic types](#generic-types) - 1. [Constraint Interfaces](#constraint-interfaces) - 1. [Instantiation](#instantiation) -1. [Updating tools while building at older Go versions](#updating-tools-while-building-at-older-go-versions) -1. [Further help](#further-help) - -# Introduction - -With Go 1.18, Go now supports generic programming via type parameters. This -document is intended to serve as a guide for tool authors that want to update -their tools to support the new language constructs introduced for generic Go. - -This guide assumes some knowledge of the language changes to support generics. -See the following references for more information: - -- The [original proposal](https://go.dev/issue/43651) for type parameters. -- The [addendum for type sets](https://go.dev/issue/45346). -- The [latest language specfication](https://tip.golang.org/ref/spec) (still in-progress as of 2021-01-11). -- The proposals for new APIs in - [go/token and go/ast](https://go.dev/issue/47781), and in - [go/types](https://go.dev/issue/47916). - -It also assumes existing knowledge of `go/ast` and `go/types`. If you're just -getting started, -[x/example/gotypes](https://github.com/golang/example/tree/master/gotypes) is -a great introduction (and was the inspiration for this guide). - -# Summary of new language features and their APIs - -While generic Go programming is a large change to the language, at a high level -it introduces only a few new concepts. Specifically, we can break down our -discussion into the following three broad categories. In each category, the -relevant new APIs are listed (some constructors and getters/setters may be -elided where they are trivial). - -**Generic types**. Types and functions may be _generic_, meaning their -declaration has a non-empty _type parameter list_: as in `type List[T any] -...` or `func f[T1, T2 any]() { ... }`. Type parameter lists define placeholder -types (_type parameters_), scoped to the declaration, which may be substituted -by any type satisfying their corresponding _constraint interface_ to -_instantiate_ a new type or function. - -Generic types may have methods, which declare `receiver type parameters` via -their receiver type expression: `func (r T[P1, ..., PN]) method(...) (...) -{...}`. - -_New APIs_: - - The field `ast.TypeSpec.TypeParams` holds the type parameter list syntax for - type declarations. - - The field `ast.FuncType.TypeParams` holds the type parameter list syntax for - function declarations. - - The type `types.TypeParam` is a `types.Type` representing a type parameter. - On this type, the `Constraint` and `SetConstraint` methods allow - getting/setting the constraint, the `Index` method returns the index of the - type parameter in the type parameter list that declares it, and the `Obj` - method returns the object declared in the declaration scope for the type - parameter (a `types.TypeName`). - - The type `types.TypeParamList` holds a list of type parameters. - - The method `types.Named.TypeParams` returns the type parameters for a type - declaration. - - The method `types.Named.SetTypeParams` sets type parameters on a defined - type. - - The function `types.NewSignatureType` creates a new (possibly generic) - signature type. - - The method `types.Signature.RecvTypeParams` returns the receiver type - parameters for a method. - - The method `types.Signature.TypeParams` returns the type parameters for - a function. - -**Constraint Interfaces**: type parameter constraints are interfaces, expressed -via an interface type expression. Interfaces that are only used in constraint -position are permitted new embedded elements composed of tilde expressions -(`~T`) and unions (`A | B | ~C`). The new builtin interface type `comparable` -is implemented by types for which `==` and `!=` are valid. As a special case, -the `interface` keyword may be omitted from constraint expressions if it may be -implied (in which case we say the interface is _implicit_). - -_New APIs_: - - The constant `token.TILDE` is used to represent tilde expressions as an - `ast.UnaryExpr`. - - Union expressions are represented as an `ast.BinaryExpr` using `|`. This - means that `ast.BinaryExpr` may now be both a type and value expression. - - The method `types.Interface.IsImplicit` reports whether the `interface` - keyword was elided from this interface. - - The method `types.Interface.MarkImplicit` marks an interface as being - implicit. - - The method `types.Interface.IsComparable` reports whether every type in an - interface's type set is comparable. - - The method `types.Interface.IsMethodSet` reports whether an interface is - defined entirely by its methods (has no _specific types_). - - The type `types.Union` is a type that represents an embedded union - expression in an interface. May only appear as an embedded element in - interfaces. - - The type `types.Term` represents a (possibly tilde) term of a union. - -**Instantiation**: generic types and functions may be _instantiated_ to create -non-generic types and functions by providing _type arguments_ (`var x T[int]`). -Function type arguments may be _inferred_ via function arguments, or via -type parameter constraints. - -_New APIs_: - - The type `ast.IndexListExpr` holds index expressions with multiple indices, - as occurs in instantiation expressions with multiple type arguments, or in - receivers with multiple type parameters. - - The function `types.Instantiate` instantiates a generic type with type arguments. - - The type `types.Context` is an opaque instantiation context that may be - shared to reduce duplicate instances. - - The field `types.Config.Context` holds a shared `Context` to use for - instantiation while type-checking. - - The type `types.TypeList` holds a list of types. - - The type `types.ArgumentError` holds an error associated with a specific - argument index. Used to represent instantiation errors. - - The field `types.Info.Instances` maps instantiated identifiers to information - about the resulting type instance. - - The type `types.Instance` holds information about a type or function - instance. - - The method `types.Named.TypeArgs` reports the type arguments used to - instantiate a named type. - -# Examples - -The following examples demonstrate the new APIs above, and discuss their -properties. All examples are runnable, contained in subdirectories of the -directory holding this README. - -## Generic types - -### Type parameter lists - -Suppose we want to understand the generic library below, which defines a generic -`Pair`, a constraint interface `Constraint`, and a generic function `MakePair`. - -``` -package main - -type Constraint interface { - Value() interface{} -} - -type Pair[L, R any] struct { - left L - right R -} - -func MakePair[L, R Constraint](l L, r R) Pair[L, R] { - return Pair[L, R]{l, r} -} -``` - -We can use the new `TypeParams` fields in `ast.TypeSpec` and `ast.FuncType` to -access the syntax of the type parameter list. From there, we can access type -parameter types in at least three ways: - - by looking up type parameter definitions in `types.Info` - - by calling `TypeParams()` on `types.Named` or `types.Signature` - - by looking up type parameter objects in the declaration scope. Note that - there now may be a scope associated with an `ast.TypeSpec` node. - -``` -func PrintTypeParams(fset *token.FileSet, file *ast.File) error { - conf := types.Config{Importer: importer.Default()} - info := &types.Info{ - Scopes: make(map[ast.Node]*types.Scope), - Defs: make(map[*ast.Ident]types.Object), - } - _, err := conf.Check("hello", fset, []*ast.File{file}, info) - if err != nil { - return err - } - - // For convenience, we can use ast.Inspect to find the nodes we want to - // investigate. - ast.Inspect(file, func(n ast.Node) bool { - var name *ast.Ident // the name of the generic object, or nil - var tparamSyntax *ast.FieldList // the list of type parameter fields - var tparamTypes *types.TypeParamList // the list of type parameter types - var scopeNode ast.Node // the node associated with the declaration scope - - switch n := n.(type) { - case *ast.TypeSpec: - name = n.Name - tparamSyntax = n.TypeParams - tparamTypes = info.Defs[name].Type().(*types.Named).TypeParams() - name = n.Name - scopeNode = n - case *ast.FuncDecl: - name = n.Name - tparamSyntax = n.Type.TypeParams - tparamTypes = info.Defs[name].Type().(*types.Signature).TypeParams() - scopeNode = n.Type - } - - if name == nil { - return true // not a generic object - } - - // Option 1: find type parameters by looking at their declaring field list. - if tparamSyntax != nil { - fmt.Printf("%s has a type parameter field list with %d fields\n", name.Name, tparamSyntax.NumFields()) - for _, field := range tparamSyntax.List { - for _, name := range field.Names { - tparam := info.Defs[name] - fmt.Printf(" field %s defines an object %q\n", name.Name, tparam) - } - } - } else { - fmt.Printf("%s does not have a type parameter list\n", name.Name) - } - - // Option 2: find type parameters via the TypeParams() method on the - // generic type. - fmt.Printf("%s has %d type parameters:\n", name.Name, tparamTypes.Len()) - for i := 0; i < tparamTypes.Len(); i++ { - tparam := tparamTypes.At(i) - fmt.Printf(" %s has constraint %s\n", tparam, tparam.Constraint()) - } - - // Option 3: find type parameters by looking in the declaration scope. - scope, ok := info.Scopes[scopeNode] - if ok { - fmt.Printf("%s has a scope with %d objects:\n", name.Name, scope.Len()) - for _, name := range scope.Names() { - fmt.Printf(" %s is a %T\n", name, scope.Lookup(name)) - } - } else { - fmt.Printf("%s does not have a scope\n", name.Name) - } - - return true - }) - return nil -} -``` - -This program produces the following output. Note that not every type spec has -a scope. - -``` -> go run golang.org/x/tools/internal/typeparams/example/findtypeparams -Constraint does not have a type parameter list -Constraint has 0 type parameters: -Constraint does not have a scope -Pair has a type parameter field list with 2 fields - field L defines an object "type parameter L any" - field R defines an object "type parameter R any" -Pair has 2 type parameters: - L has constraint any - R has constraint any -Pair has a scope with 2 objects: - L is a *types.TypeName - R is a *types.TypeName -MakePair has a type parameter field list with 2 fields - field L defines an object "type parameter L hello.Constraint" - field R defines an object "type parameter R hello.Constraint" -MakePair has 2 type parameters: - L has constraint hello.Constraint - R has constraint hello.Constraint -MakePair has a scope with 4 objects: - L is a *types.TypeName - R is a *types.TypeName - l is a *types.Var - r is a *types.Var -``` - -### Methods on generic types - -**TODO** - -## Constraint Interfaces - -### New interface elements - -**TODO** - -### Implicit interfaces - -**TODO** - -### Type sets - -**TODO** - -## Instantiation - -### Finding instantiated types - -**TODO** - -### Creating new instantiated types - -**TODO** - -### Using a shared context - -**TODO** - -# Updating tools while building at older Go versions - -In the examples above, we can see how a lot of the new APIs integrate with -existing usage of `go/ast` or `go/types`. However, most tools still need to -build at older Go versions, and handling the new language constructs in-line -will break builds at older Go versions. - -For this purpose, the `x/exp/typeparams` package provides functions and types -that proxy the new APIs (with stub implementations at older Go versions). -**NOTE**: does not yet exist -- see -[golang/go#50447](https://go.dev/issues/50447) for more information. - -# Further help - -If you're working on updating a tool to support generics, and need help, please -feel free to reach out for help in any of the following ways: - - Via the [golang-tools](https://groups.google.com/g/golang-tools) mailing list. - - Directly to me via email (`rfindley@google.com`). - - For bugs, you can [file an issue](https://github.com/golang/go/issues/new/choose). |