-
Notifications
You must be signed in to change notification settings - Fork 496
Explicit type instantiations (f<<T>>)
#1980
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
Conversation
|
😮 |
Analysis/src/ConstraintGenerator.cpp
Outdated
| typeParameters.push_back(resolveType( | ||
| scope, | ||
| typeOrPack.type, | ||
| true // todo soon: what does this (inTypeArguments) do? |
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.
This is checked in one place and I don't really understand what I should do:
// If we're not in a type argument context, we need to create a constraint that expands this.
// The dispatching of the above constraint will queue up additional constraints for nested
// type function applications.
if (!inTypeArguments)
addConstraint(scope, ty->location, TypeAliasExpansionConstraint{/* target */ result});
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.
It's an outside-in expansion. If you have F<G<H<T>>>, you only need one constraint to expand the outermost type function application. Expansion of the outermost enqueues additional TypeAliasExpansionConstraint to the inner type arguments.
Say type F<T> = { tag: "F", payload: T }, type G<T> = { tag: "G", payload: T }, and type H<T> = { tag: "H", payload: T }.
First, F<G<H<T>>> produces a blocked type. Second, expansion of F gives us { tag: "F", payload: *blocked-type-0* } and enqueues a constraint to expand *blocked-type-0* with the result of G<H<T>>. Repeat this algorithm, and you get { tag: "F", payload: { tag: "G", payload: *blocked-type-1* } }. Repeat once again, and you get { tag: "F", payload: { tag: "G", payload: { tag: "H", payload: T } } }.
Doing it outside-in is important to tie the knot for cyclic type function applications. If you enqueue them all with nothing controlling the expansion, you get Turing completeness.
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.
In this case, you should be using false in both calls to resolveType and resolveTypePack in the getExplicitTypeIds function. They'll recurse and set that argument to true. Otherwise local x: F<T> = identity<<F<T>>>() will fail to type check! (because you have two different PendingExpansionTypes, and if they aren't pointer equal, they do not unify)
Analysis/src/ConstraintGenerator.cpp
Outdated
| typeParameters.push_back(resolveType( | ||
| scope, | ||
| typeOrPack.type, | ||
| true // todo soon: what does this (inTypeArguments) do? |
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.
| true // todo soon: what does this (inTypeArguments) do? | |
| /* inTypeArguments */ false |
Analysis/src/ConstraintGenerator.cpp
Outdated
| typePackParameters.push_back(resolveTypePack( | ||
| scope, | ||
| typeOrPack.typePack, | ||
| true // todo soon: what does this (inTypeArguments) do? |
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.
| true // todo soon: what does this (inTypeArguments) do? | |
| /* inTypeArguments */ false |
Analysis/src/ConstraintGenerator.cpp
Outdated
| std::vector<TypeId> typeParameters; | ||
| std::vector<TypePackId> typePackParameters; |
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.
Also should be called arguments. Parameters are things you define. You supply arguments to each parameter.
function f(param1, param2) end
f(1, 2) -- two arguments| // FIXME: This triggers a GenericTypePackCountMismatch error, and it's not obvious if the | ||
| // code for explicit types is broken, or if subtyping is broken. |
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.
Probably subtyping tbf, but this might've been fixed since you wrote it.
| Intersection, | ||
| }; | ||
|
|
||
| InterestingEdgeCase interestingEdgeCase; |
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.
Yeah, that would be fine. I think it probably belongs in the error message too, but we'll probably want to play with it more to see if that's actually true. Either way, will make it easier to test and debug anything interacting with intersection.
This adds in support for Explicit type parameter instantiation.
This PR is still a work in progress, but some important notes:
__callare not supported. Whilet<<A>>()is obvious what it should do with__call, it's not obvious whatt<<A>>on its own would be.Both of these are possible to bring later.