Tree[T Ordered[T]] struct { root *node[T] } func (t *Tree[T]) Insert(v T) { if v.Less(t.root.value) { /* go left */ } else { /* go right */ } } Each element must be able to compare itself with another value of the same type. 3
Nov 8, 2021 The deadlock occurred during type inference for type arguments to generic types. CL 361922 fixed the deadlock by restricting self-reference. 10
inference for type arguments to generic types was cut from the design before release. The restriction remained until Go 1.26. go-review.googlesource.com/c/go/+/711420 — commit message, Robert Griesemer, 2025 12
Foo[T Bar] interface{} Rejected type Bar interface { type Bar interface { foo() Foo[Bar] } foo() Foo[Bar] } type Foo[T Bar] interface{} Same dependency graph. Different result through Go 1.25. 14
// Set the type parameters before collecting the type constraints because // the parameterized type may be used by the constraints (go.dev/issue/47887). // Example: type T[P T[P]] interface{} The checker could already represent this dependency. 16
state: // objDecl() in go/types/decl.go // - not in Checker.objPathIdx and type == nil // in Checker.objPathIdx // - not in Checker.objPathIdx and type != nil → → → white (not yet checked) grey (pending) black (done) 17
tracks each object as white, grey, or black. Encountering a grey object means a cycle. Checking Ordered[T Ordered[T]] : white grey Ordered[T] → same grey object turns grey cycle detected is called Before Go 1.26, validCycle rejected this cycle because it occurred in a type-parameter list. 18
go/types/decl.go tparCycle := false // ...loop over the objects in the cycle... case *TypeName: if check.inTParamList && isGeneric(obj.typ) { tparCycle = true break loop } 19
after CL 711420: white grey Ordered[T] → same grey object black turns grey accepted → checking finishes (done) tparCycle accepts the cycle, so Ordered reaches the black (completed) state. 21
[]E type Element[E Element[E]] interface { Less(E) bool Children() ElementList[E] // E must be Element } github.com/golang/go/issues/68162 — ecryth, Jun 25, 2024 Tree can put the requirement on its own type parameter. Element cannot, because Children() returns ElementList[E] . 23
map: var ordinary map[any]string // accepted Generic map, Go 1.18–1.19: type Map[K comparable, V any] map[K]V var generic Map[any, string] // rejected The key type is identical, but only the generic declaration was rejected. 27
only comparable strictly comparable types slice int string any also contains slices, map bool struct{ n int } maps, and functions func netip.Addr … []int is in any 's type set but not comparable 's, so any does not implement comparable . 29
satisfies comparable implements comparable = satisfies comparable implements comparable + any (example) The type set of comparable stayed the same A new exception applies to C = interface{ comparable; E } It requires E to be basic and T (the candidate type argument) to be comparable and implement E any satisfies comparable , but does not implement it. 30
a type parameter constrained only by any receive the same treatment? Interface type any type Map[K comparable, V any] map[K]V var _ Map[any, string] // allowed K comparable is interface{ comparable; any } . Type parameter P any func g[P any]() { var _ Map[P, string] // compile error } P may still be instantiated as []int . any satisfies comparable . → The exception does not make an unconstrained type parameter comparable. 31
Map[K comparable, V any] map[K]V ordinary := map[any]string{} generic := Map[any, string]{} ordinary[[]int{}] = "slice" // panics at run time generic[[]int{}] = "slice" // panics at run time Go 1.20 accepts the same runtime risk that already exists for an ordinary map. 32
which may panic qualified → any has always Strictly comparable: guarantees that == will not panic qualify → any still does not → any still does not Satisfies comparable : may be used as a type argument → any qualifies Implements comparable : fits inside its type set since Go 1.20 → Only the rule for satisfying the constraint changed. 33
introduced core types (a spec concept, not Go syntax). Here's how it defined close() , in Go 1.18 through 1.24: For an argument ch with core type that is a channel... The specification reused this concept for range , close , send, and copy . 35
type Rangeable interface { string | []byte } func f[T Rangeable](v T) { for _, b := range v { _ = b } } Go 1.18 – 1.24 // error: cannot range over v (variable of type T // constrained by Rangeable): no core type Go 1.25 / Go 1.26 (current) // error: cannot range over v (variable of type T // constrained by Rangeable): string and []byte // have different underlying types 36
parameters type Container[T any] struct { items []T } func (c *Container[T]) Map[U any](f func(T) U) *Container[U] { // ... } // syntax error: method must have no type parameters Through Go 1.26, methods could not declare their own type parameters. 39
Generic concrete method: the receiver type is known statically Generic interface method: the dynamic concrete receiver type is known only at run time, and the required method instantiation may not be known at compile time The 2021 design considered the two capabilities together. The Go gopher was designed by Renée French. 40
time: walk the whole program's call graph impractical Instantiate at run time: use JIT compilation or reflection → → impractical Exclude interface implementation: generic methods never implement interface methods → insufficient benefit over functions Link time Run time No interfaces The Go gopher was designed by Renée French. 41
unsolved, but the 2026 proposal treats concrete methods as independently useful. github.com/golang/go/issues/77273 — Robert Griesemer, 2026 APIs grouped under the receiver type Discoverability in documentation and tooling Fluent method-call syntax 42
Container[T any] struct { items []T } func (c *Container[T]) Map[U any](f func(T) U) *Container[U] { // ... } var c Container[int] _ = c.Map(strconv.Itoa) // T = int from the receiver; U = string from the argument 43
type I interface { M[T any](T) T } // invalid Interface implementation type I interface { M(int) } type S struct{} func (S) M[T any](T) {} var _ I = S{} // invalid Interface methods cannot declare type parameters. Generic methods cannot implement interface methods. 45