-
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -650,7 +650,7 @@ _module-type-parameters_ ::= # | |
|
|
||
| Class declaration can have type parameters and superclass. When you omit superclass, `::Object` is assumed. | ||
|
|
||
| * Super class arguments and generic class upperbounds are not *classish-context* nor *self-context* | ||
| * Super class arguments and generic class bounds are not *classish-context* nor *self-context* | ||
|
|
||
| ### Module declaration | ||
|
|
||
|
|
@@ -668,7 +668,7 @@ end | |
|
|
||
| The `Enumerable` module above requires `each` method for enumerating objects. | ||
|
|
||
| * Self type arguments and generic class upperbounds are not *classish-context* nor *self-context* | ||
| * Self type arguments and generic class bounds are not *classish-context* nor *self-context* | ||
|
|
||
| ### Class/module alias declaration | ||
|
|
||
|
|
@@ -764,7 +764,11 @@ _module-type-parameter_ ::= _generics-unchecked_ _generics-variance_ _type-varia | |
| _method-type-param_ ::= _type-variable_ _generics-bound_ | ||
|
|
||
| _generics-bound_ ::= (No type bound) | ||
| | `<` _type_ (The generics parameter is bounded) | ||
| | `<` _type_ (The generics parameter has an upper bound) | ||
| | '>' _type_ (The generics parameter has a lower bound) | ||
|
|
||
| # A type parameter can have both upper and lower bounds, which can be specified in either order: | ||
| # `[T < UpperBound > LowerBound]` or `[T > LowerBound < UpperBound]` | ||
|
|
||
| _default-type_ ::= (No default type) | ||
| | `=` _type_ (The generics parameter has default type) | ||
|
|
@@ -834,13 +838,38 @@ class PrettyPrint[T < _Output] | |
| end | ||
| ``` | ||
|
|
||
| If a type parameter has an upper bound, the type parameter must be instantiated with types that is a subtype of the upper bound. | ||
| If a type parameter has an upper bound, the type parameter must be instantiated with types that are a subtype of the upper bound. | ||
|
|
||
| ```rbs | ||
| type str_printer = PrettyPrint[String] # OK | ||
| type int_printer = PrettyPrint[Integer] # Type error | ||
| ``` | ||
|
|
||
| If a type parameter has a lower bound, the type parameter must be instantiated with types that are a supertype of the lower bound. | ||
|
|
||
| ```rbs | ||
| class PrettyPrint[T > Numeric] | ||
| end | ||
|
|
||
| type obj_printer = PrettyPrint[Object] # OK | ||
| type int_printer = PrettyPrint[Integer] # Type error | ||
| ``` | ||
|
|
||
| A type parameter can have both an upper and a lower bound, and these bounds can be specified in any order. | ||
|
|
||
| ```rbs | ||
| class FlexibleProcessor[T > Integer < Numeric] | ||
|
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. Hmmmm I do not like this syntax...
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. Agreed that would be nicer. If only a lower bound was specified, would we want to accept 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. 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 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 commentThe reason will be displayed to describe this comment to others. Learn more. We can ask Soutaro once we open the PR against ruby/rbs |
||
| # This class processes types T that are supertypes of Integer but also subtypes of Numeric. | ||
| # This includes Integer, Rational, Complex, Float, and Numeric itself. | ||
| def calculate: (T) -> T | ||
| end | ||
|
|
||
| type int_processor = FlexibleProcessor[Integer] # OK (Integer > Integer and Integer < Numeric) | ||
| type num_processor = FlexibleProcessor[Numeric] # OK (Numeric > Integer and Numeric < Numeric) | ||
| type obj_processor = FlexibleProcessor[Object] # Type error (Object is not < Numeric) | ||
| type str_processor = FlexibleProcessor[String] # Type error (String is not > Integer) | ||
| ``` | ||
|
|
||
| The generics type parameter of modules, classes, interfaces, or type aliases can have a default type. | ||
|
|
||
| ```rbs | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,6 +159,13 @@ def validate_class_module_definition | |
| @validator.validate_type(ub, context: nil) | ||
| end | ||
|
|
||
| if lb = param.lower_bound_type | ||
| void_type_context_validator(lb) | ||
| no_self_type_validator(lb) | ||
| no_classish_type_validator(lb) | ||
| @validator.validate_type(lb, context: nil) | ||
|
Comment on lines
+163
to
+166
Member
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. 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 🤔 |
||
| end | ||
|
|
||
| if dt = param.default_type | ||
| void_type_context_validator(dt, true) | ||
| no_self_type_validator(dt) | ||
|
|
@@ -244,6 +251,13 @@ def validate_interface | |
| @validator.validate_type(ub, context: nil) | ||
| end | ||
|
|
||
| if lb = param.lower_bound_type | ||
| void_type_context_validator(lb) | ||
| no_self_type_validator(lb) | ||
| no_classish_type_validator(lb) | ||
| @validator.validate_type(lb, context: nil) | ||
| end | ||
|
|
||
| if dt = param.default_type | ||
| void_type_context_validator(dt, true) | ||
| no_self_type_validator(dt) | ||
|
|
@@ -317,6 +331,13 @@ def validate_type_alias | |
| @validator.validate_type(ub, context: nil) | ||
| end | ||
|
|
||
| if lb = param.lower_bound_type | ||
| void_type_context_validator(lb) | ||
| no_self_type_validator(lb) | ||
| no_classish_type_validator(lb) | ||
| @validator.validate_type(lb, context: nil) | ||
| end | ||
|
|
||
| if dt = param.default_type | ||
| void_type_context_validator(dt, true) | ||
| no_self_type_validator(dt) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -127,8 +127,8 @@ def validate_type_params(params, type_name: , method_name: nil, location:) | |||||||||||||||
| # @type var each_child: ^(Symbol) { (Symbol) -> void } -> void | ||||||||||||||||
| each_child = -> (name, &block) do | ||||||||||||||||
| if param = params.find {|p| p.name == name } | ||||||||||||||||
| if b = param.upper_bound_type | ||||||||||||||||
| b.free_variables.each do |tv| | ||||||||||||||||
| [param.upper_bound_type, param.lower_bound_type].compact.each do |bound| | ||||||||||||||||
| bound.free_variables.each do |tv| | ||||||||||||||||
| block[tv] | ||||||||||||||||
| end | ||||||||||||||||
|
Comment on lines
+130
to
133
Member
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. Do you think this would be better?
Suggested change
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. These are apparently not the same! With the suggested change, tests start failing, but I'm not exactly sure why. |
||||||||||||||||
| end | ||||||||||||||||
|
|
||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.