Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: allow parameterized type aliases to omit redundant type parameters #68617

Open
adonovan opened this issue Jul 27, 2024 · 5 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Thinking
Milestone

Comments

@adonovan
Copy link
Member

adonovan commented Jul 27, 2024

#46477 is an accepted proposal to allow type parameters on aliases, although the implied change to the spec wording has not yet been fleshed out, so it's not clear whether the current issue is a compiler bug or a request to change the spec.

When instantiating a parameterized function, it is legal to omit one or more type parameters (a suffix of the parameter tuple) if they can be inferred from the argument types. For example, all three of these uses of Contains are instantiated the same way, even though only the first is fully explicit:

https://go.dev/play/p/o3WFjULJVqE

	_ = slices.Contains[mySliceType, string](slice, "")
	_ = slices.Contains[mySliceType](slice, "")
	_ = slices.Contains(slice, "")

This inference needn't be based on the types of the arguments, but can also proceed from the explicit type arguments, as in this variant where the argument types alone are insufficient:

func _(slice mySliceType) {
	_ = slices.Contains[mySliceType](nil, "") // inferred as [mySliceType, mystring]
}

type mystring string
type mySliceType []mystring

Parameterized type aliases should behave in an analogous way. That is, if the first type arguments to a parameterized type alias are sufficient to determine the instantiation, the others should not be required. However, that is not the current behavior of the compiler:

https://go.dev/play/p/BkWFFkHDKPW?v=gotip

type SliceElementType[Slice ~[]Elem, Elem any] = Elem

var _ SliceElementType[myStringSlice] // error: not enough type arguments

I see two reasons for making the analogy. The first is symmetry. The second is that parameterized type aliases with this inference may be used to express "pure functions over types", including destructuring operators. For example, the SliceElementType[T] operator is the inverse of the []T operator: the latter adds a slice type constructor, and the former strips it off. This is a useful form of expressiveness that allows you to denote the element type of an arbitrary slice type, which might not otherwise be expressible. One can imagine similar operators for denoting the elements of pointer, map, and chan types, the parameters and result types of functions, and (someday) the types of struct fields.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 27, 2024
@gabyhelp
Copy link

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jul 27, 2024
@dmitshur
Copy link
Contributor

CC @golang/compiler.

@dmitshur dmitshur added this to the Backlog milestone Jul 27, 2024
@griesemer
Copy link
Contributor

@adonovan You're asking for (constraint) type inference for generic alias types, but note that we don't even have type inference for generic non-alias types - we only have type inference for function calls.

The reason is that instantiating a generic type (alias or not) requires providing type arguments for the type parameters, and it's possible (in theory) to provide the generic (instantiated) type itself as type argument; that is, to instantiate a generic type with itself, directly or indirectly, which may lead to cycles. We don't understand what kind of cycles should be permitted if any. With the possibility of cycles, type inference becomes an even more complex beast. I think we first need to fully understand this in detail because we can move at all, but I am not aware of anybody spending serious cycles on this at the moment.

We have (internally) discussed allowing type inference for generic alias types if a simple cycle check succeeds (no reference, directly or indirectly to the generic type being instantiated). That is likely going to catch virtually all important cases and maybe good enough.

Note that this problem doesn't arise at all with generic functions because they cannot serve as type arguments.

cc: @timothy-king for visibility.

@ddemoss222
Copy link

@griesemer Have internal discussions on the proposed solution (simple cycle check) advanced? Any updates on whether that may be included in a coming release?

@griesemer
Copy link
Contributor

@ddemoss222 This request requires that we support (constraint) type inference for normal types, which we currently don't (and we also are not actively working on it). So this won't be in the 1.24 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Thinking
Projects
Development

No branches or pull requests

7 participants