Repository: go
Issue: proposal: spec: apply constraint type inference to generic types
Labels: Proposal,Proposal-Hold,TypeInference

### Author background

- Experienced Go Engineer, over 8 years experience
- Rust, C, Zig

### Related proposals

- I am not sure if this idea has been proposed before
- This idea does not effect error handling
- This proposal is about generics

### Proposal

- The proposed change is to allow for better type inference when working with generic referencing interfaces
- This proposal helps anyone who uses generics in a factory or generator pattern. Additionally, anyone writing data structures
- The purpose of this proposal is to allow for interface types referencing generics `type MyInterface[T] interface { *T }` to be inferred better
- The ability to infer types for interfaces targeting a pointer value of a generic type
- Allow for pointer types of structs to be inferred more easily by Golang generics
- The change is backward compatible
- This change does not affect existing features
- This change is not a performance improvement

### Costs

- This would not affect the learning scale of Go as it's a deeper subject. For more experienced Engineers, it should make generics more simple to work with
- More work on the compiler to perform stronger inferring  
- gopls would be affected
- Negligible, but a slight performance cost
- No runtime cost
- A use-case for this feature is available [here](https://go.dev/play/p/kYb4St3FkDw)
- No prototype is available for the implementation of this feature

### Example - Current Requirement
```go
package main

import (
	"strconv"
)

func main() {
	c := New[testType]()
	c.Txn(func(txn Txn[testType, *testType]) {
		txn.New(testType{val: "1"})
		txn.Update("0", func(tt testType) (out testType) {
			return
		})
	})
}

func New[T any, U Value[T]]() *Controller[T, U] {
	var c Controller[T, U]
	c.m = make(map[string]T)
	return &c
}

type Controller[T any, U Value[T]] struct {
	idx int
	m   map[string]T
}

func (c *Controller[T, U]) Txn(fn func(Txn[T, U])) {
	var txn Txn[T, U]
	txn.c = c
	fn(txn)
}

type Txn[T any, U Value[T]] struct {
	c *Controller[T, U]
}

func (txn *Txn[T, U]) New(t T) {
	u := U(&t)
	u.SetID(strconv.Itoa(txn.c.idx))
	txn.c.idx++
}

func (txn *Txn[T, U]) Update(key string, fn func(T) T) {
	v, ok := txn.c.m[key]
	if !ok {
		return
	}

	txn.c.m[key] = fn(v)
}

type testType struct {
	id  string
	val string
}

func (t *testType) SetID(id string) {
	t.id = id
}

type Value[T any] interface {
	*T
	SetID(string)
}
```

### Example - Proposal
```go
package main

import (
	"strconv"
)

func main() {
	c := New[testType]()
	c.Txn(func(txn Txn[testType]) {
		txn.New(testType{val: "1"})
		txn.Update("0", func(tt testType) (out testType) {
			return
		})
	})
}

func New[T any, U Value[T]]() *Controller[T, U] {
	var c Controller[T, U]
	c.m = make(map[string]T)
	return &c
}

type Controller[T any, U Value[T]] struct {
	idx int
	m   map[string]T
}

func (c *Controller[T, U]) Txn(fn func(Txn[T, U])) {
	var txn Txn[T, U]
	txn.c = c
	fn(txn)
}

type Txn[T any, U Value[T]] struct {
	c *Controller[T, U]
}

func (txn *Txn[T, U]) New(t T) {
	u := U(&t)
	u.SetID(strconv.Itoa(txn.c.idx))
	txn.c.idx++
}

func (txn *Txn[T, U]) Update(key string, fn func(T) T) {
	v, ok := txn.c.m[key]
	if !ok {
		return
	}

	txn.c.m[key] = fn(v)
}

type testType struct {
	id  string
	val string
}

func (t *testType) SetID(id string) {
	t.id = id
}

type Value[T any] interface {
	*T
	SetID(string)
}
```