Repository: go
Issue: go/types: statically inferring the run-time properties of type parameters
Labels: LibraryProposal

[NOTE: I am tentatively associating this issue with go/types, but refraining initially from marking it as a proposal because there are multiple solutions with different scopes and I am unsure about the best course of action.]

Currently and by design, the only methods that can be called on values whose type is a parameter are those explicitly defined by their constraint, either directly or by embedding. That however does not match the runtime semantics of those values, e.g. the outcome of dynamic type assertions or reflection methods; for example ([playground](https://go.dev/play/p/u1vnGKQggKP)):

```go
package main

type T1 struct{}

func (T1) Method() {}

type T2 struct{}

func (*T2) Method() {}

type Constraint interface {
	T1 | *T2
}

type Mset interface {
	Method()
}

func Fn[T Constraint](x T) {
	//x.Method() // ERROR
	//x.(Mset).Method() // ERROR!
	any(x).(Mset).Method() // Works
}

func main() {
	Fn(T1{})
	Fn(&T2{})
}
```

The facilities provided in `go/types` are geared towards compile-time type checking: for example `types.Implements(<T>, <Mset>)` returns `false`. No alternatives are provided to infer runtime behavior, which makes some kinds of static analysis exceedingly hard.

In my case, for example, I want to infer how `encoding/json.Marshal` is going to behave on values of parametric type, specifically whether all members of the type set either implement `encoding.TextMarshaler` or have a string as underlying type, and are therefore usable as map keys, for arbitrary type constraints.

It is true that I can access the full definition of a type constraint and compute its type set. I considered copying the private code that `go/types` uses to do so, but was turned off by its complexity and the associated maintenance burden. It would be so much better if `go/types` could make this knowledge available through a public API.

I can think of a number of solutions, which are not necessarily mutually exclusive; from the easiest to the most radical:

1. add one or more predicates for runtime behavior, e.g. `RuntimeAssertableTo` or similar;
2. add a public API for enumerating the type set of a constraint, in addition to the method set;
3. publish the currently private `go/types._TypeSet` API (not sure why it has been made private, and what the drawbacks would be);
4. change the spec to have the method set of constraint interfaces include the intersection of the method sets of their type terms.

For my purposes I'd be happy with option (2) or (3) — (1) would be useful but not sufficient, and perhaps not a very good API.

Personally I'd very much like to see something like (4) adopted, as it would eliminate a large part of the compile-time/run-time mismatch and add some use cases for generics. Not sure whether it would fall under the umbrella of #70128; I went back in time a bit but couldn't find any issue related to method access on type parameters. It seems to me more lightweight and approachable than other proposals, but again perhaps I'm missing some known hurdles.

I'd be happy to write a proposal, but as noted above I'm not sure about the approach to pick.