-
Notifications
You must be signed in to change notification settings - Fork 70
Add eager inference annotation for polymorphic types #106
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
base: master
Are you sure you want to change the base?
Changes from 26 commits
213ec9f
cb82f7a
bf354a1
8f1c0d9
8a24f5b
9df20a0
e25643f
1943be7
1d36401
1c8d217
2ed0187
b7c2800
b47e000
29384af
f5c5609
b995140
5308d81
c9328c7
27d8c66
cbc02bd
9fa24be
96f8aaa
b83c473
1fee95b
458dcb6
8bb92ba
7d20d52
2463447
6264249
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # Eager Inference Annotations for Polymorphic Types | ||
|
|
||
| ## Summary | ||
|
|
||
| The RFC introduces a feature to annotate polymorphic function types to express that the first instantiation of a polymorphic type `T` is the one that sticks. | ||
|
|
||
| ## Motivation | ||
|
|
||
| The purpose of this feature is to develop syntax to prevent polymorphic types from widening into (e.g., number | string) when a function is implicitly instantiated with different argument types. E.g., `test(1, "a")`. In the following code, Luau's current solver infers `T` to be of a union type: | ||
|
||
|
|
||
| ```luau | ||
| function test<T>(a: T, b: T): T | ||
| return a | ||
| end | ||
|
|
||
| local result = test(1, "string") -- inferred type `T`: number | string" | ||
| ``` | ||
|
|
||
| This behaviour can be useful in some cases but is undesirable when a polymorphic function is intended to constrain the input types to be consistent. | ||
|
||
|
|
||
| ## Design | ||
|
|
||
| We propose adding some symbol as a suffix (or prefix) that annotates the "eager" inference behaviour for a polymorphic type. | ||
| Subsequent usages of type `T` where `T` is "eager" would be ignored during instantiation. | ||
|
||
|
|
||
| ### New Syntax | ||
|
|
||
| The `!` syntax modifier would would enforce an eager inference behaviour for `T!`: | ||
|
|
||
| ```luau | ||
| function test<T!>(a: T, b: T): T | ||
| return a | ||
| end | ||
|
|
||
| test(1, "string") -- TypeError: Expected `number`, got `string` | ||
| ``` | ||
|
|
||
| ## Drawbacks | ||
|
|
||
| - Introduces a new syntax modifier `!`, which may lead to a symbol soup. However, `T!` doesn't seem too shabby next to `T?`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this is actually a reasonably strong argument against this syntax: people might confuse it as having something to do with optionals or There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @Ukendio
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah might lean onto using keywords or putting the annotation as a prefix instead |
||
| - Introduces a simple change to luau's parser, marginally increasing parsing complexity. | ||
|
|
||
| ## Alternatives | ||
| ### Per-usage-bindings | ||
| Flip the relationship being declarared per-type-parameter to per-usage which provides more control in expressing the inference, and could allow both instantiation behaviours of polymorphic types under a uniform syntax. | ||
|
|
||
| A polymorphic typed marked with type `T!` will not contribute to the instantiation of type `T` in the function. Instead, `T` should be inferred on the arguments without the annotation: | ||
|
|
||
| ```luau | ||
| function test<T>(first: T, second: T, third: T!): T | ||
| return first | ||
| end | ||
|
|
||
| test(1, "string", true) -- TypeError: Type `boolean` could not be converted into `number | string` | ||
| ``` | ||
|
|
||
| Notably, this behavior would be identical to other languages, such as typescript's `noinfer<T>`. This has the added drawback that the `!` syntax modifier would need to be barred from return types, as the return type holds no relevance to implicit instantiation. | ||
|
||
|
|
||
|
|
||
| ### Keywords | ||
| Something like `<greedy T>` or `<strict T>` should also be considered if we want to reduce symbols. This idea has merit when considering the potential complexity of type aliases combined with `T!?` | ||
|
||
Uh oh!
There was an error while loading. Please reload this page.