-
Notifications
You must be signed in to change notification settings - Fork 13
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
Generate types with better support for nested shapes #146
Conversation
In this first draft, we can use a constructor with a not-that-mangled name. inner_t = outer_t._nested_t
inner = inner_t(my_field=3)
outer: outer_t = outer_t(nested=inner) Using that as a type annotation still doesn't work, since we're accessing it from a nested class and that is a known limitation of Pyre. Another problem is that the additional field which contains the first-class type is added for every field in generated shapes. Using |
I'm curious, is it because it's being generated with a metaclass? Would it work if we did the codgen for the Flattening the generated classes all into the module seems to be a good solution (/ the only solution). If we do that can they still be referenced by the nested names, or do they all have to get readable names (set in |
AFAIK, Pyre simply doesn't check for types aliases that are not in the global namespace.
Actually, it seems we don't need to flatten the classes themselves if we provide aliases in the global namespace. |
That sounds fine, how are you thinking of providing the readable names? Just the field name? |
Dealing with generic types (collections) is still a bit awkward, but I don't see other alternatives. Also updated codegen tests.
As of the latest commit, and since they have to be in the toplevel, the naming scheme for type aliases is:
So it is still possible to have conflicting aliases if you're using weird field names with double underscores. It gets a bit weird with collection types: since there is no field name we can associate to them, we use 0-based indexes. deep_t = shape.dict(str, shape.list(shape.shape(very_deep=bool)))
inner_t = shape.shape(
first = deep_t,
second = deep_t,
)
outer_t = shape.shape(
nested = inner_t,
) We can have annotations for the types of every single field, of every single nested shape: import outer # assuming we generated the `outer_t` shape in `outer.py`
outer_t = outer.outer_t
inner_t = outer.typeof_nested
assert outer.typeof_nested__first == outer.typeof_nested__second # they should be the same
deep_t = outer.typeof_nested__first
deepest_t = outer.typeof_nested__first__1__0 # 1 to get the dict's value type, 0 for the type of the list
deeper: deepest_t = deepest_t(very_deep=True)
deep: deep_t = {'key': (deeper, deeper, deeper)}
inner: inner_t = inner_t(first=deep, second=deep)
outer: outer_t = outer_t(nested=inner) This runs and typechecks. |
Seems like you're on the right track, but this is breaking the build now. |
Oh, I didn't realize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this seems pretty reasonable - I'm not in love with the generated code, but digging into it should only be necessary in very narrow circumstances and other than that the public api is the same
I just left one comment of something that I think can be improved, but I'll import and land the PR when that is addressed :)
@vmagro has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator. |
c1e4f75 changes the way codegen works to accomplish this same result without the associated difficulty in starlark code |
Solves #143 by:
Flattening nested types generated in the same file/module:
This way, equal types used in different places only need to be generated once (and the typechecker knows they're the same).
Adding type aliases to every single field and type parameter:
Since type aliases need to be in the toplevel for the typechecker to see them, we need a hierarchical naming scheme.
The current scheme is not perfect: there could be conflicts if consumers use field names with double underscores.
Also, accessing the types that parameterize a collection is a bit awkward, since we lack names and resort to numeric indexes.