Adding nested type support #1370
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Adding type parameters from a function into the nested types inside of that function. For example:
The type
Baris concrete (i.e. not generic) however it acts like it is generic because it is nested in a generic function. If the function is called likeFoo[string]()thenBarinnately is different from if the function is called likeFoo[int](). The nesting type parameters is shown likeBar[T;]and instantiated likeBar[string;]andBar[int;].In Go the
;in the type parameters isn't present if the nested type is concrete.Bazis generic meaning the;indicates the separation between the nested type parameters and the objects own type parameters. For example ifBaz[string]{}is expressed inside ofFoo[int], then aBaz[int; string]is instantiated. IfBaz[T]{}is expressed inside ofFoo[X], then aBaz[X; X]is instantiated.When creating instances for a nested type, all combinations of nest function instances and nesting type instances need to be determined. For example if
Foohas the instancesFoo[string]andFoo[int], andBazhas the instancesBaz[bool]andBaz[string], then the resolved instances forBazareBaz[string; bool],Baz[string; string],Baz[int; bool], andBaz[int; string]. While reading the instances fromtypes.Info, an instance may have a type parameter in it, e.g.Baz[T]. We replace the type parameter with the nest function's instance type arguments, meaningBaz[T]resolves toBaz[int; int]andBaz[string; string], but notBaz[int; string]norBaz[string; int].Note: I used
TNestor similar to store the type arguments from the nest function or method as a separate set fromTArgs. This is different from what Go does which is using an index for the "implicit" type arguments to differentiate between the two parts, seen here. I felt it was easier to maintain and to fit into the existing code better than using an index.This is related to #1013 and #1270
Future Work / Known Issues
Fixing Nested Type Arguments
This change does not include a fix for when a type argument itself is nested. For example:
The
Bazis instantiated correctly using the nesting type argument forFooand the argument given to itBar. However,Barhas not been instantiated correctly with the nesting type argument forFoo, meaningBaris still generic with the underlying type ofstruct { X T }. IfFoo[int]()is called, theBarused for the type argument forBazneeds to beBar[int;]withstruct { X int }.I didn't fix this issue yet because it feels very unlikely, although possible, to happen, and I found it while finishing up this PR. So, instead of delaying this initial work on nested types, I left some tests that demonstrate the issue and skipped them with a
TODO(grantnelson-wf)comment.Fixing DCE
This change does not include an update to the DCE to remove unused instances caused by nested types. For example:
In the above code the instances
Foo[string]andFoo[int]are created, thenFoo[int]is found to be dead and eliminated. However, the instanceBar[string;]andBar[int;]are created by their respective nest function instances. Right now our DCE doesn't take into account the nesting type parameters so will see all instances ofBaras alive because"Bar"is used in the aliveFoo[string]. This leaves the dead codeBar[int], also seen as"Bar", alive when it should be eliminated.A following ticket will fix the DCE to take into acount the nesting type parameters so that dead nested types will be properly removed.
Numbering Nested Types Issue
This change does not include any of the numbering of types like Go does. For example:
When the types returned from
FooandBarare printed, they aremain.Biz[main.Baz·1]andmain.Biz[main.Baz·2]respectively. The·1and·2are indications of which declaration ofBazis being used. They are not shown in all cases and never show for package level declarations. The numbering is applied in the order the files are parsed and nested types are declared in those files.The number increases monotonically with each new type declaration regardless of their name and type, meaning if the
BazinBaris changed totype Cat interface{}andBizis instantiated withCatinBar, the types aremain.Biz[main.Baz·1]andmain.Biz[main.Cat·2]. The type fromFoodidn't change andCatis still denoted with a·2since it is the second nested type.Since these numbers aren't being collected nor printed, we can not remove
typeparam/nested.gofrom the known failures of the Gorepo Tests yet. The test will not pass because the outputs will not match without the nested type numbering. So, not only are does that test hit some "Nested Type Arguments" (themain.U's aren't being instantiated correctly), but the difference in the outputs looks like: