Skip to content

proposal: spec: function type inference should work in all assignment contexts #77245

@griesemer

Description

@griesemer

The Go 1.21 release introduced significantly improved type inference. Specifically:

A (possibly partially instantiated generic) function may now be called with arguments that are themselves (possibly partially instantiated) generic functions. The compiler will attempt to infer the missing type arguments of the callee (as before) and, for each argument that is a generic function that is not fully instantiated, its missing type arguments (new). [ ... ] More generally, a generic function may now be used without explicit instantiation when it is assigned to a variable or returned as a result value if the type arguments can be inferred from the assignment.

As stated, this type inference works in assignments, but it doesn't work for all assignments. For instance, given (playground):

type S struct{ f func(int) }

func g[T any](T) {}

func _(s S) {
	s.f = g          // ok
	s = S{f: g}      // error: cannot use generic function g without instantiation
	s = S{f: g[int]} // ok
}

The assignment of the generic function g to the function-typed field f of struct S works as described but the same (implicit) assignment to field f in the struct literal does not - explicit instantiation of g is required.

The same is true for assignments to array, slice, or map elements vs the same (implicit) assignment in the respective composite literals, and sends to channels (playground):

type F func(int)
type A [10]F
type S []F
type M map[string]F
type C chan F

func g[T any](T) {}

func _() {
	var a A
	a[0] = g      // ok
	a = A{g}      // error: cannot use generic function g without instantiation
	a = A{g[int]} // ok

	var s S
	s[0] = g      // ok
	s = S{g}      // error: cannot use generic function g without instantiation
	s = S{g[int]} // ok

	var m M
	m["foo"] = g         // ok
	m = M{"foo": g}      // error: cannot use generic function g without instantiation
	m = M{"foo": g[int]} // ok

	var c C
	c <- g      // error: cannot use generic function g without instantiation
	c <- g[int] // ok
}

In all these cases we have an assignment where the type on the LHS is completely known and thus the function type parameter can be inferred unambiguously, and should be inferred for consistency.

While making this change likely requires some clarifications in the spec, I believe this is arguably a bug rather than a language change because the assignments (a[0] = g) work, but the implicit assignments in composite literals don't (a = A{g}). The exception is channel sends, but even in that case the element to be sent must be assignable to the channel element type and thus establishes a clear "target" type.

Correction:
The spec is explicit about where this inference is supposed to work (see Instantiations). I believe it makes sense to generalize to all assignment contexts but that requires a spec change and proposal.

Metadata

Metadata

Labels

LanguageChangeSuggested changes to the Go languageLanguageProposalIssues describing a requested change to the Go language specification.ProposalTypeInferenceIssue is related to generic type inference

Projects

Status

Todo

Status

Active

Relationships

None yet

Development

No branches or pull requests

Issue actions