Repository: go
Issue: spec: add examples (or more explicit prose) regarding the identity/difference of types escaping generic and non-generic functions
Labels: Documentation,NeedsInvestigation


### What did you do?

[Playground Link](https://go.dev/play/p/phJTMuCj-Z0)

```go
package main

import "fmt"

func main() {
	fmt.Println(F[int]() == F[int](), F[int]() != G(), G() == G(), F[int]() != F[string]())
}

func F[T comparable]() any {
	type x struct{ _ [0]T }
	return x{}
}

func G() any {
	type x struct{ _ [0]int }
	return x{}
}
```

### What did you see happen?

`true true true true`

### What did you expect to see?

`true true true true`. The output is clearly intuitively correct and the most sensible behavior of this program. However, I'm having trouble justifying it from the spec.

For equality of interfaces, [the spec says](https://tip.golang.org/ref/spec#Comparison_operators):

> Interface types that are not type parameters are comparable. Two interface values are equal if they have [identical](https://tip.golang.org/ref/spec#Type_identity) dynamic types and equal dynamic values or if both have value `nil`.

The program is constructed such that the dynamic types all have exactly one dynamic value, hence we need to check if the dynamic types are identical:

> A [named type](https://tip.golang.org/ref/spec#Types) is always different from any other type. Otherwise, two types are identical if their [underlying](https://tip.golang.org/ref/spec#Types) type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types. In detail: […]

In this case, all types involved are named types. So, the question is whether those named types are "other types" or not. Determining whether that is the case is the contention. [The only relevant answer I can find says](https://tip.golang.org/ref/spec#Type_definitions):

> A type definition creates a new, distinct type with the same [underlying type](https://tip.golang.org/ref/spec#Underlying_types) and operations as the given type and binds an identifier, the type name, to it. […] The new type is called a defined type. It is [different](https://tip.golang.org/ref/spec#Type_identity) from any other type, including the type it is created from.

As well as later:

> If the type definition specifies [type parameters](https://tip.golang.org/ref/spec#Type_parameter_declarations), the type name denotes a generic type. Generic types must be [instantiated](https://tip.golang.org/ref/spec#Instantiations) when they are used.

Lastly, [going back to Type identity](https://tip.golang.org/ref/spec#Type_identity), we also note:

> Two [instantiated](https://tip.golang.org/ref/spec#Instantiations) types are identical if their defined types and all type arguments are identical.

That's all the relevant spec pieces I can really find.

Now my argument:

`F[int]() == F[int]()` and `G() == G()`, demonstrating that the created type is not tied to a call, but to the type definition AST node.

`G() != F[int]()` demonstrates that different type definition AST nodes lead to non-identical types. Strengthening the assertion that the actual AST node determines type identity.

Buf `F[int]() != F[string]()` shows that *the same* type definition can lead to *different* types. Even though 1. the type definition is not generic (it has no type parameters) and 2. it is a named type, so its identity *should* solely be determined by its type definition.

To be clear, again: This is obviously the only sensible and expected way for this code to behave, but it seems there is a hole in the spec for this behavior.