Skip to content

Add support for lower bounds in type parameters #2490

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

Merged
merged 1 commit into from
May 27, 2025

Conversation

allcre
Copy link
Contributor

@allcre allcre commented May 15, 2025

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

Comment on lines 1449 to +1454
rbs_parser_advance(parser);
}

if (parser->next_token.type == pRBRACKET) {
} 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;
Copy link
Contributor Author

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.

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++) {
Copy link
Contributor Author

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.

@allcre allcre marked this pull request as draft May 15, 2025 16:00
@allcre allcre force-pushed the support-lower-bound branch from 487f79c to c63e115 Compare May 15, 2025 16:32
@allcre allcre marked this pull request as ready for review May 15, 2025 16:38
Copy link
Contributor

@ParadoxV5 ParadoxV5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side Note: In RBS, the generic type specify covariance and contravariance with in/out keywords:

class Covariant[out O] …
class Contravariant[in I] …
def example(src, dst) #: [T] (Covariant[T], Contravariant[T]) -> void
  dst.set src.get
end

Java generics are invariant; instead, each application specifies co- and contravariance through wildcard lower and upper bounds case-by-case:

class Covariant<O> …
class Contravariant<I> …

<T> void example(Covariant<? extends T> src, Contravariant<? super T> dst) {
  dst.set(src.get());
}

In RBS, that is equivalent to:

class Covariant[O] …
class Contravariant[I] …

def example: [T, O < T = T, I > T = T] (Covariant[O], Contravariant[I]) -> void

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
@allcre allcre force-pushed the support-lower-bound branch from c63e115 to ac8348a Compare May 20, 2025 16:03
@soutaro soutaro added this to the RBS 4.0 milestone May 27, 2025
Copy link
Member

@soutaro soutaro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! 🎉

@soutaro soutaro added this pull request to the merge queue May 27, 2025
Merged via the queue into ruby:master with commit 2a73da6 May 27, 2025
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants