-
Notifications
You must be signed in to change notification settings - Fork 2
Add support for lower bounds in type parameters #45
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
src/parser.c
Outdated
| upper_bound_range.end = parser->current_token.range.end; | ||
| rbs_range_t lower_bound_range = NULL_RANGE; | ||
|
|
||
| for(int bound_parse_attempt = 0; bound_parse_attempt < 2; bound_parse_attempt++) { |
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 loop is to parse both upper bound (<) and lower bound (>) constraints for type parameters. The loop runs at most twice to allow both bound types in either order: [T < UpperBound > LowerBound] or [T > LowerBound < UpperBound]. It detects and prevents duplicate bounds of the same type and exits early if no bounds are present.
src/parser.c
Outdated
| } else if (parser->next_token.type == pRBRACKET) { | ||
| break; | ||
| } else { | ||
| rbs_parser_set_error(parser, parser->next_token, true, "expected ',' or ']' after type parameter, got %s", rbs_token_type_str(parser->next_token.type)); | ||
| return false; |
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 change ensures the parser correctly validates syntax after type parameter bounds. Previously, expressions like [T < String Integer] would be silently accepted despite being invalid.
amomchilov
left a comment
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 a really impressive piece of work!
| You can also specify the _lower bound_ of the type parameter using `>`. This constrains the type parameter to be a supertype of the specified bound. Both an upper and a lower bound can be specified for the same type parameter. | ||
|
|
||
| ```rbs | ||
| class FlexibleProcessor[T > Integer < Numeric] |
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.
Hmmmm I do not like this syntax... Integer < T < Numeric would be much better. 🤔 Let's discuss with @Morriar
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.
Agreed that would be nicer. If only a lower bound was specified, would we want to accept Integer < T and not T > Integer?
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.
While it works well with one letter names mixed with core types, it can become more confusing when using semantic names:
SUV < Car < VehicleWhich one is the type param?
Not that the original syntax is much better though...
Car > SUV < Vehicle I'm not against the proposed Integer < T < Numeric but it's still confusing when using a default type:
Integer < T < Numeric = Integer
In practice, lower bounds are not as used as upper bound and using both would be a really rare occasion. So I'm not sure any syntax matters much?
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.
We can ask Soutaro once we open the PR against ruby/rbs
f5e12ef to
1a2750a
Compare
1a2750a to
8abac1e
Compare
src/parser.c
Outdated
| upper_bound_range.end = parser->current_token.range.end; | ||
| rbs_range_t lower_bound_range = NULL_RANGE; | ||
|
|
||
| for (int bound_parse_attempt = 0; bound_parse_attempt < 2; bound_parse_attempt++) { |
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.
smart 🤯
d047a16 to
2e4b7bc
Compare
| void_type_context_validator(lb) | ||
| no_self_type_validator(lb) | ||
| no_classish_type_validator(lb) | ||
| @validator.validate_type(lb, context: nil) |
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.
Not directly related to this PR, but it feels like these 4 lines can be extracted into a helper method as it's repeated a lot 🤔
| [param.upper_bound_type, param.lower_bound_type].compact.each do |bound| | ||
| bound.free_variables.each do |tv| | ||
| block[tv] | ||
| end |
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.
Do you think this would be better?
| [param.upper_bound_type, param.lower_bound_type].compact.each do |bound| | |
| bound.free_variables.each do |tv| | |
| block[tv] | |
| end | |
| [param.upper_bound_type, param.lower_bound_type].compact.flat_map(&:free_variables).each do |tv| | |
| block[tv] | |
| end |
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.
These are apparently not the same! With the suggested change, tests start failing, but I'm not exactly sure why.
|
For the CI errors I think you need to |
I think it's caused by mismatches on the r2e versions. RBS currently uses v3.1 but we usually install 4.* now. @allcre you can follow the same commands used on CI to install that specific version: We can look at this together in our pairing later. |
487f79c to
c63e115
Compare
This change implements lower bound constraints for generic type parameters in RBS, allowing declarations like `[T > SomeType]`. The implementation includes: - Parser and lexer modifications to handle ">" token in type params - Relevant changes to the Ruby API, like Locator and Validator - Schema updates to typeParam.json - Documentation updates
c63e115 to
ac8348a
Compare
Ticket: https://github.com/Shopify/team-ruby-dx/issues/1453
This change implements lower bound constraints for generic type parameters in RBS, allowing declarations like
[T > SomeType].The implementation includes:
To review
upper_boundis handled and duplicate the logic forlower_bound. Did I miss anything?note: CI is currently failing but this will be fixed by ruby#2482