go: cmd/compile: invalidly inferred type for interface that doesn't use type parameter

In the following code:

type T[P any] interface {
	m()
}

func g[P any](T[P]) {}

func _() {
	var x T[int]
	g(x)         // here we infer P == int, but in fact any type of P would be ok
	g[string](x) // here we set P == string
}

we infer the type int for P of g. But in fact any type would make this code work. Type inference should not succeed in this case.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 26 (18 by maintainers)

Commits related to this issue

Most upvoted comments

I think the framing provided by @griesemer and @atdiar is useful: if the solution is not unique, inference should fail. Otherwise, we run the risk of inferring a different type in the future (and that’s exactly why we need the special case currently).

I’ll note that there are other cases where there is one unique solution, and inference fails because of the current implementation:

type S[P any] interface{}

func F[P any](S[P], P) {}

func _() {
	var s S[int]
	F(s, "")
}

@hajimehoshi in general to express units.

type Distance[Unit any] float64
type Miles struct{}
type Meters struct{} 

type DistanceMiles = Distance[Miles] 
type DistanceMeters = Distance[Meters] 

I’d think.

But your question is more interesting and I responded a bit too fast, since you are especially targeting the case of interface types.

I’m curious as well to see what people think.

@atdiar Your 2nd example will work with the fix.

Exactly, that’s why inference fails.

It’s a case similar to f(x) = c where c is constant.

Given c, we are still trying to find the one value of x that we passed to f.

That’s what was meant by unique, I don’t disagree at all.

g(T[int](x)) is the same as g(x) if x is of type T[int]. So g(T[string](nil)) currently works but would fail if we consider this issue a bug. Consider g[int](T[string](nil)) which works either way.

In other words, currently we have an exception for defined generic interface types: if a defined generic interface type T which is instantiated with a concrete type X (assuming there’s one type parameter) is then matched against the same interface type “instantiated” with a type parameter, we infer the type X for the type parameter, even if the type parameter is never used by the methods: T[X] unified against T[P] leads to the inference of X for P.

If we consider this issue a bug, then a) we don’t need an exception anymore, but b) in this example we wouldn’t be able to infer X anymore.

I think this is a pretty esoteric case and doesn’t really justify the exception.

See also #8082 which applies when the interface types are components of other types.