Skip to content

Handling nested type arguments #1374

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

grantnelson-wf
Copy link
Collaborator

@grantnelson-wf grantnelson-wf commented May 28, 2025

This fixes some issues. See "Fixing Nested Type Arguments" in summary of #1370.
This also cleans up some of the resolver code to make it easier to prepare for resolution of types.

This change fixes when a type argument itself is nested. For example:

func Foo[T any]() {
	type Bar struct { X T }
	type Baz[U any] struct { }
	_ = Baz[Bar]{}
	...
}

The Baz is instantiated correctly using the nesting type argument for Foo and the argument given to it Bar. However, Bar has not been instantiated correctly with the nesting type argument for Foo, meaning Bar is still generic with the underlying type of struct { X T }. If Foo[int]() is called, the Bar used for the type argument for Baz needs to be understood to be Bar[int;] with struct { X int }.

Initially I intended to change the substitution to always modify the underlying struct in a named type. However, that causes problems in the instance map since the instance map uses the object pointer as a key and the fully substituted object has a different pointer. Instead, following how types.Instantiate works, I made the instances allow for lazy substitution, i.e. unsubstituted type parameters are allowed in the context of a named type with those type parameters and properly substituted type arguments.

In the above example this would mean Bar would be seen as struct { X T } but that is now acceptable to the code since it is in context where T is defined. This is acceptable since the transformation code later on continues to substitute as needed, so the T will be substituted to int before it is used.

The only draw back to not fully substituting the underlying types is that when printing Baz[Bar] in Foo[int]; Go will output Baz[Bar[int;]] (ignoring the dot numbering and the extra ;), whilst now, GopherJS will output Baz[Bar] without properly indicating the nesting context. We can swing back around to this later, I didn't want get stuck on this too long when it is rare that nested type arguments or deep nesting is used in normal code.

This is related to #1013 and #1270

@grantnelson-wf grantnelson-wf self-assigned this May 28, 2025
@grantnelson-wf grantnelson-wf marked this pull request as ready for review May 28, 2025 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant