rbs 3.4.3 → 3.5.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +7 -0
  3. data/CHANGELOG.md +0 -20
  4. data/Gemfile +12 -1
  5. data/Gemfile.lock +51 -34
  6. data/README.md +2 -1
  7. data/Rakefile +2 -2
  8. data/core/enumerator.rbs +1 -1
  9. data/core/gc.rbs +272 -150
  10. data/core/integer.rbs +4 -3
  11. data/core/io/wait.rbs +4 -4
  12. data/core/io.rbs +10 -3
  13. data/core/kernel.rbs +8 -7
  14. data/core/module.rbs +17 -4
  15. data/core/range.rbs +2 -2
  16. data/core/regexp.rbs +101 -90
  17. data/core/ruby_vm.rbs +103 -103
  18. data/core/string.rbs +3 -3
  19. data/core/symbol.rbs +2 -1
  20. data/core/thread.rbs +1 -1
  21. data/core/time.rbs +24 -4
  22. data/docs/architecture.md +110 -0
  23. data/docs/syntax.md +5 -1
  24. data/ext/rbs_extension/constants.c +2 -0
  25. data/ext/rbs_extension/constants.h +1 -0
  26. data/ext/rbs_extension/location.c +79 -70
  27. data/ext/rbs_extension/location.h +23 -5
  28. data/ext/rbs_extension/parser.c +82 -24
  29. data/ext/rbs_extension/parserstate.c +4 -0
  30. data/ext/rbs_extension/ruby_objs.c +13 -3
  31. data/ext/rbs_extension/ruby_objs.h +1 -0
  32. data/lib/rbs/collection/config.rb +1 -1
  33. data/lib/rbs/collection/sources/git.rb +1 -6
  34. data/lib/rbs/definition_builder/method_builder.rb +1 -1
  35. data/lib/rbs/definition_builder.rb +8 -8
  36. data/lib/rbs/diff.rb +1 -1
  37. data/lib/rbs/environment_loader.rb +2 -1
  38. data/lib/rbs/errors.rb +0 -14
  39. data/lib/rbs/parser_aux.rb +0 -5
  40. data/lib/rbs/prototype/helpers.rb +22 -12
  41. data/lib/rbs/prototype/rb.rb +38 -4
  42. data/lib/rbs/prototype/rbi.rb +30 -20
  43. data/lib/rbs/test/errors.rb +19 -14
  44. data/lib/rbs/test/tester.rb +1 -1
  45. data/lib/rbs/test/type_check.rb +95 -16
  46. data/lib/rbs/types.rb +112 -13
  47. data/lib/rbs/unit_test/spy.rb +1 -1
  48. data/lib/rbs/version.rb +1 -1
  49. data/rbs.gemspec +1 -1
  50. data/sig/environment_loader.rbs +1 -1
  51. data/sig/errors.rbs +1 -1
  52. data/sig/method_types.rbs +3 -3
  53. data/sig/prototype/helpers.rbs +4 -0
  54. data/sig/prototype/rbi.rbs +2 -0
  55. data/sig/types.rbs +54 -4
  56. data/sig/variance_calculator.rbs +2 -2
  57. data/stdlib/csv/0/csv.rbs +4 -1
  58. data/stdlib/fileutils/0/fileutils.rbs +1 -1
  59. data/stdlib/net-http/0/net-http.rbs +29 -27
  60. data/stdlib/socket/0/socket.rbs +2 -2
  61. data/stdlib/timeout/0/timeout.rbs +6 -0
  62. data/stdlib/uri/0/generic.rbs +2 -2
  63. data/stdlib/uri/0/http.rbs +2 -2
  64. metadata +3 -6
  65. data/lib/rbs/parser_compat/lexer_error.rb +0 -6
  66. data/lib/rbs/parser_compat/located_value.rb +0 -7
  67. data/lib/rbs/parser_compat/semantics_error.rb +0 -6
  68. data/lib/rbs/parser_compat/syntax_error.rb +0 -6
@@ -0,0 +1,110 @@
1
+ # Architecture
2
+
3
+ This guide describes the outline of the architecture of RBS library. It helps you to understand the structure and key features of the library to start contributing to the library.
4
+
5
+ ## Bird's Eye View
6
+
7
+ The goal of the library is simple: Read RBS files and generate the structure of Ruby programs.
8
+
9
+ ```
10
+ RBS files
11
+ ↓ -- RBS::Parser
12
+ Syntax tree
13
+
14
+ Environment
15
+ ↓ -- Definition builder
16
+ Definition
17
+ ```
18
+
19
+ The input is RBS files. The gem ships with RBS type definitions of Ruby core library and some of the standard libraries. You write RBS files for your applications or gems.
20
+
21
+ Syntax tree is the next representation. `RBS::Parser` transforms the sequence of characters in RBS files into syntax trees.
22
+
23
+ Syntax tree objects are loaded to `RBS::Environment`. It collects loaded RBS objects, organizes the definitions, and provides some utilities, like resolving type names and finding the declarations.
24
+
25
+ `RBS::Definition` is the goal of the transformation steps. It is associated with a class singleton, a class object, or an interface. You can find the list of available methods and their types, instance variables, and class hierarchies.
26
+
27
+ ## Core classes
28
+
29
+ ### Types
30
+
31
+ Types are defined under `RBS::Types`, like `RBS::Types::ClassInstance` or `RBS::Types::Union`. You will find the definition of each type supported in RBS.
32
+
33
+ ### Parsing RBS files
34
+
35
+ The RBS source code is loaded into `RBS::Buffer`, and `RBS::Parser` is the parser. The parser is implemented in C extension.
36
+
37
+ `RBS::Parser` provides three entrypoints.
38
+
39
+ - `RBS::Parser.parse_method_type` parsers a *method type*. (`[T] (String) { (IO) -> T } -> Array[T]`)
40
+ - `RBS::Parser.parse_type` parses a *type*. (`Hash[Symbol, untyped]`)
41
+ - `RBS::Parser.parse_signature` parses the whole RBS file.
42
+
43
+ ### Environment
44
+
45
+ RBS AST is loaded to `RBS::Environment` by `RBS::EnvironmentLoader`. `Environment` gives *absolute names* to the declarations, and provides an index from the *absolute name* to their declarations.
46
+
47
+ Assume we have the following nested RBS declarations:
48
+
49
+ ```rbs
50
+ module Hello
51
+ class World
52
+ end
53
+ end
54
+
55
+ class Hello::World
56
+ end
57
+ ```
58
+
59
+ And the environment organizes the definitions as follows:
60
+
61
+ - There are two classes `::Hello` and `::Hello::World`
62
+ - It provides a mapping from `::Hello` to it's `module` declaration and `::Hello::World` to it's two `class` declarations
63
+
64
+ ### Definition and DefinitionBuilder
65
+
66
+ `RBS::Definition` tells you:
67
+
68
+ - The set of available methods in a class/module/interface
69
+ - The set of instance variables in a class/module
70
+ - The ancestors in a class/module
71
+
72
+ Definition is constructed for:
73
+
74
+ - A singleton class of a class/module -- `singleton(String)`, `singleton(Array)`,
75
+ - An instance of a class -- `String`, `Array[T]`, or
76
+ - An interface -- `_ToS`
77
+
78
+ Note that generic class instances/interfaces are kept generic. We don't have a definition of `Array[String]` but of `Array[T]`.
79
+
80
+ `DefinitionBuilder` constructs `Definition` of given type names.
81
+
82
+ - `DefinitionBuilder#build_singleton` returns a definition of singleton classes of given class/module.
83
+ - `DefinitionBuilder#build_instance` returns a definition of instances of given class/module.
84
+ - `DefinitionBuilder#build_interface` returns a definition of interfaces.
85
+
86
+ It uses `AncestorBuilder` to construct ancestor chains of the type. `MethodBuilder` constructs sets of available methods based on the ancestor chains.
87
+
88
+ The `#build_singleton` calculates the type of `.new` methods based on the definition of `#initialize` method. This is different from Ruby's implementation -- it reused `Class#new` method but we need the custom implementation to give precise `.new` method type of each class.
89
+
90
+ #### Working with type aliases
91
+
92
+ `DefinitionBuilder#expand_alias` and its variants provide one step *unfold* operation of type aliases.
93
+
94
+ ```ruby
95
+ builder.expand_alias2(TypeName("::int"), []) # => returns `::Integer | ::_ToInt`
96
+ ```
97
+
98
+ We don't have *normalize* operation for type aliases, because RBS allows recursive type alias definition, which cannot be *fully* unfolded.
99
+
100
+ ### Other utilities
101
+
102
+ `RBS::Validator` provides validation of RBS type declaration. It validates that all of the type name references can be resolved, all type applications have correct arity, and so on.
103
+
104
+ `RBS::Test` provides runtime type checking, which confirms if a Ruby object can have an RBS type. It also provides an integration to existing Ruby code so that we run Ruby code, assuming unit tests, with runtime type checking.
105
+
106
+ `RBS::UnitTest` provides utilities to help write unit tests for RBS type definitions. Use the tool to make sure your RBS type definition is consistent with implementation.
107
+
108
+ `RBS::Prototype` is the core of `rbs prototype` feature. It scans Ruby source code or uses reflection features, and it generates the prototype of RBS files.
109
+
110
+ `RBS::Collection` includes `rbs collection` features.
data/docs/syntax.md CHANGED
@@ -45,6 +45,7 @@ _literal_ ::= _string-literal_
45
45
  | `false`
46
46
 
47
47
  _proc_ ::= `^` _parameters?_ _self-type-binding?_ _block?_ `->` _type_
48
+ | `^` `(` `?` `)` `->` _type_ # Proc type with untyped parameter
48
49
  ```
49
50
 
50
51
  ### Class instance type
@@ -310,6 +311,7 @@ end
310
311
 
311
312
  ```markdown
312
313
  _method-type_ ::= _parameters?_ _block?_ `->` _type_ # Method type
314
+ | `(` `?` `)` `->` _type_ # Method type with untyped parameters
313
315
 
314
316
  _parameters?_ ::= (Empty)
315
317
  | _parameters_ (Parameters)
@@ -333,9 +335,11 @@ _var-name_ ::= /[a-z]\w*/
333
335
  _self-type-binding?_ = (Empty)
334
336
  | `[` `self` `:` _type_ `]` (Self type binding)
335
337
 
336
- _block?_ = (No block)
338
+ _block?_ = (No block)
337
339
  | `{` _parameters_ _self-type-binding?_ `->` _type_ `}` (Block)
340
+ | `{` `(` `?` `)` `->` _type_ `}` (Block with untyped parameters)
338
341
  | `?` `{` _parameters_ _self-type-binding?_ `->` _type_ `}` (Optional block)
342
+ | `?` `{` `(` `?` `)` `->` _type_ `}` (Optional block with untyped parameters)
339
343
  ```
340
344
 
341
345
  ### Parameters
@@ -61,6 +61,7 @@ VALUE RBS_Types_ClassInstance;
61
61
  VALUE RBS_Types_ClassSingleton;
62
62
  VALUE RBS_Types_Function_Param;
63
63
  VALUE RBS_Types_Function;
64
+ VALUE RBS_Types_UntypedFunction;
64
65
  VALUE RBS_Types_Interface;
65
66
  VALUE RBS_Types_Intersection;
66
67
  VALUE RBS_Types_Literal;
@@ -138,6 +139,7 @@ void rbs__init_constants(void) {
138
139
  IMPORT_CONSTANT(RBS_Types_ClassInstance, RBS_Types, "ClassInstance");
139
140
  IMPORT_CONSTANT(RBS_Types_ClassSingleton, RBS_Types, "ClassSingleton");
140
141
  IMPORT_CONSTANT(RBS_Types_Function, RBS_Types, "Function");
142
+ IMPORT_CONSTANT(RBS_Types_UntypedFunction, RBS_Types, "UntypedFunction");
141
143
  IMPORT_CONSTANT(RBS_Types_Function_Param, RBS_Types_Function, "Param");
142
144
  IMPORT_CONSTANT(RBS_Types_Interface, RBS_Types, "Interface");
143
145
  IMPORT_CONSTANT(RBS_Types_Intersection, RBS_Types, "Intersection");
@@ -64,6 +64,7 @@ extern VALUE RBS_Types_ClassInstance;
64
64
  extern VALUE RBS_Types_ClassSingleton;
65
65
  extern VALUE RBS_Types_Function_Param;
66
66
  extern VALUE RBS_Types_Function;
67
+ extern VALUE RBS_Types_UntypedFunction;
67
68
  extern VALUE RBS_Types_Interface;
68
69
  extern VALUE RBS_Types_Intersection;
69
70
  extern VALUE RBS_Types_Literal;
@@ -1,83 +1,76 @@
1
1
  #include "rbs_extension.h"
2
2
 
3
+ #define RBS_LOC_REQUIRED_P(loc, i) ((loc)->children->required_p & (1 << (i)))
4
+ #define RBS_LOC_OPTIONAL_P(loc, i) (!RBS_LOC_REQUIRED_P((loc), (i)))
5
+
3
6
  VALUE RBS_Location;
4
7
 
5
- rbs_loc_list *rbs_loc_list_add(rbs_loc_list *list, const ID name, const range r) {
6
- rbs_loc_list *new = malloc(sizeof(rbs_loc_list));
7
- new->next = list;
8
- new->name = name;
9
- new->rg = r;
10
- return new;
8
+ position rbs_loc_position(int char_pos) {
9
+ position pos = { 0, char_pos, -1, -1 };
10
+ return pos;
11
11
  }
12
12
 
13
- rbs_loc_list *rbs_loc_list_dup(rbs_loc_list *list) {
14
- if (list) {
15
- return rbs_loc_list_add(rbs_loc_list_dup(list->next), list->name, list->rg);
16
- } else {
17
- return NULL;
18
- }
13
+ position rbs_loc_position3(int char_pos, int line, int column) {
14
+ position pos = { 0, char_pos, line, column };
15
+ return pos;
19
16
  }
20
17
 
21
- void rbs_loc_list_free(rbs_loc_list *list) {
22
- while (list) {
23
- rbs_loc_list *next = list->next;
24
- free(list);
25
- list = next;
18
+ static void check_children_max(unsigned short n) {
19
+ size_t max = sizeof(rbs_loc_entry_bitmap) * 8;
20
+ if (n > max) {
21
+ rb_raise(rb_eRuntimeError, "Too many children added to location: %d", n);
26
22
  }
27
23
  }
28
24
 
29
- bool rbs_loc_list_find(const rbs_loc_list *list, ID name, range *rg) {
30
- while (list) {
31
- if (list->name == name) {
32
- *rg = list->rg;
33
- return true;
34
- }
25
+ void rbs_loc_alloc_children(rbs_loc *loc, unsigned short cap) {
26
+ check_children_max(cap);
35
27
 
36
- list = list->next;
37
- }
28
+ size_t s = sizeof(rbs_loc_children) + sizeof(rbs_loc_entry) * cap;
29
+ loc->children = malloc(s);
38
30
 
39
- return false;
31
+ loc->children->len = 0;
32
+ loc->children->required_p = 0;
33
+ loc->children->cap = cap;
40
34
  }
41
35
 
42
- size_t rbs_loc_list_size(const rbs_loc_list *list) {
43
- size_t size = 0;
44
-
45
- while (list) {
46
- size += 1;
47
- list = list->next;
36
+ static void check_children_cap(rbs_loc *loc) {
37
+ if (loc->children == NULL) {
38
+ rbs_loc_alloc_children(loc, 1);
39
+ } else {
40
+ if (loc->children->len == loc->children->cap) {
41
+ check_children_max(loc->children->cap + 1);
42
+ size_t s = sizeof(rbs_loc_children) + sizeof(rbs_loc_entry) * (++loc->children->cap);
43
+ loc->children = realloc(loc->children, s);
44
+ }
48
45
  }
49
-
50
- return size;
51
46
  }
52
47
 
53
- position rbs_loc_position(int char_pos) {
54
- position pos = { 0, char_pos, -1, -1 };
55
- return pos;
56
- }
48
+ void rbs_loc_add_required_child(rbs_loc *loc, ID name, range r) {
49
+ check_children_cap(loc);
57
50
 
58
- position rbs_loc_position3(int char_pos, int line, int column) {
59
- position pos = { 0, char_pos, line, column };
60
- return pos;
61
- }
51
+ unsigned short i = loc->children->len++;
52
+ loc->children->entries[i].name = name;
53
+ loc->children->entries[i].rg = r;
62
54
 
63
- void rbs_loc_add_required_child(rbs_loc *loc, ID name, range r) {
64
- loc->requireds = rbs_loc_list_add(loc->requireds, name, r);
55
+ loc->children->required_p |= 1 << i;
65
56
  }
66
57
 
67
58
  void rbs_loc_add_optional_child(rbs_loc *loc, ID name, range r) {
68
- loc->optionals = rbs_loc_list_add(loc->optionals, name, r);
59
+ check_children_cap(loc);
60
+
61
+ unsigned short i = loc->children->len++;
62
+ loc->children->entries[i].name = name;
63
+ loc->children->entries[i].rg = r;
69
64
  }
70
65
 
71
66
  void rbs_loc_init(rbs_loc *loc, VALUE buffer, range rg) {
72
67
  loc->buffer = buffer;
73
68
  loc->rg = rg;
74
- loc->optionals = NULL;
75
- loc->requireds = NULL;
69
+ loc->children = NULL;
76
70
  }
77
71
 
78
72
  void rbs_loc_free(rbs_loc *loc) {
79
- rbs_loc_list_free(loc->optionals);
80
- rbs_loc_list_free(loc->requireds);
73
+ free(loc->children);
81
74
  ruby_xfree(loc);
82
75
  }
83
76
 
@@ -89,7 +82,11 @@ static void rbs_loc_mark(void *ptr)
89
82
 
90
83
  static size_t rbs_loc_memsize(const void *ptr) {
91
84
  const rbs_loc *loc = ptr;
92
- return sizeof(*loc) + (rbs_loc_list_size(loc->optionals) + rbs_loc_list_size(loc->requireds)) * sizeof(rbs_loc_list);
85
+ if (loc->children == NULL) {
86
+ return sizeof(rbs_loc);
87
+ } else {
88
+ return sizeof(rbs_loc) + sizeof(rbs_loc_children) + sizeof(rbs_loc_entry) * loc->children->cap;
89
+ }
93
90
  }
94
91
 
95
92
  static rb_data_type_t location_type = {
@@ -130,8 +127,10 @@ static VALUE location_initialize_copy(VALUE self, VALUE other) {
130
127
 
131
128
  self_loc->buffer = other_loc->buffer;
132
129
  self_loc->rg = other_loc->rg;
133
- self_loc->requireds = rbs_loc_list_dup(other_loc->requireds);
134
- self_loc->optionals = rbs_loc_list_dup(other_loc->optionals);
130
+ if (other_loc->children != NULL) {
131
+ rbs_loc_alloc_children(self_loc, other_loc->children->cap);
132
+ memcpy(self_loc->children, other_loc->children, sizeof(rbs_loc_children) + sizeof(rbs_loc_entry) * other_loc->children->cap);
133
+ }
135
134
 
136
135
  return Qnil;
137
136
  }
@@ -221,18 +220,19 @@ VALUE rbs_new_location(VALUE buffer, range rg) {
221
220
  static VALUE location_aref(VALUE self, VALUE name) {
222
221
  rbs_loc *loc = rbs_check_location(self);
223
222
 
224
- range result;
225
223
  ID id = SYM2ID(name);
226
224
 
227
- if (rbs_loc_list_find(loc->requireds, id, &result)) {
228
- return rbs_new_location(loc->buffer, result);
229
- }
230
-
231
- if (rbs_loc_list_find(loc->optionals, id, &result)) {
232
- if (null_range_p(result)) {
233
- return Qnil;
234
- } else {
235
- return rbs_new_location(loc->buffer, result);
225
+ if (loc->children != NULL) {
226
+ for (unsigned short i = 0; i < loc->children->len; i++) {
227
+ if (loc->children->entries[i].name == id) {
228
+ range result = loc->children->entries[i].rg;
229
+
230
+ if (RBS_LOC_OPTIONAL_P(loc, i) && null_range_p(result)) {
231
+ return Qnil;
232
+ } else {
233
+ return rbs_new_location(loc->buffer, result);
234
+ }
235
+ }
236
236
  }
237
237
  }
238
238
 
@@ -244,11 +244,16 @@ static VALUE location_optional_keys(VALUE self) {
244
244
  VALUE keys = rb_ary_new();
245
245
 
246
246
  rbs_loc *loc = rbs_check_location(self);
247
- rbs_loc_list *list = loc->optionals;
247
+ rbs_loc_children *children = loc->children;
248
+ if (children == NULL) {
249
+ return keys;
250
+ }
248
251
 
249
- while (list) {
250
- rb_ary_push(keys, ID2SYM(list->name));
251
- list = list->next;
252
+ for (unsigned short i = 0; i < children->len; i++) {
253
+ if (RBS_LOC_OPTIONAL_P(loc, i)) {
254
+ rb_ary_push(keys, ID2SYM(children->entries[i].name));
255
+
256
+ }
252
257
  }
253
258
 
254
259
  return keys;
@@ -258,11 +263,15 @@ static VALUE location_required_keys(VALUE self) {
258
263
  VALUE keys = rb_ary_new();
259
264
 
260
265
  rbs_loc *loc = rbs_check_location(self);
261
- rbs_loc_list *list = loc->requireds;
266
+ rbs_loc_children *children = loc->children;
267
+ if (children == NULL) {
268
+ return keys;
269
+ }
262
270
 
263
- while (list) {
264
- rb_ary_push(keys, ID2SYM(list->name));
265
- list = list->next;
271
+ for (unsigned short i = 0; i < children->len; i++) {
272
+ if (RBS_LOC_REQUIRED_P(loc, i)) {
273
+ rb_ary_push(keys, ID2SYM(children->entries[i].name));
274
+ }
266
275
  }
267
276
 
268
277
  return keys;
@@ -9,17 +9,24 @@
9
9
  * */
10
10
  extern VALUE RBS_Location;
11
11
 
12
- typedef struct rbs_loc_list {
12
+ typedef struct {
13
13
  ID name;
14
14
  range rg;
15
- struct rbs_loc_list *next;
16
- } rbs_loc_list;
15
+ } rbs_loc_entry;
16
+
17
+ typedef unsigned int rbs_loc_entry_bitmap;
18
+
19
+ typedef struct {
20
+ unsigned short len;
21
+ unsigned short cap;
22
+ rbs_loc_entry_bitmap required_p;
23
+ rbs_loc_entry entries[0];
24
+ } rbs_loc_children;
17
25
 
18
26
  typedef struct {
19
27
  VALUE buffer;
20
28
  range rg;
21
- rbs_loc_list *requireds;
22
- rbs_loc_list *optionals;
29
+ rbs_loc_children *children;
23
30
  } rbs_loc;
24
31
 
25
32
  /**
@@ -32,13 +39,24 @@ VALUE rbs_new_location(VALUE buffer, range rg);
32
39
  * */
33
40
  rbs_loc *rbs_check_location(VALUE location);
34
41
 
42
+ /**
43
+ * Allocate memory for child locations.
44
+ *
45
+ * Do not call twice for the same location.
46
+ * */
47
+ void rbs_loc_alloc_children(rbs_loc *loc, unsigned short cap);
48
+
35
49
  /**
36
50
  * Add a required child range with given name.
51
+ *
52
+ * Allocate memory for children with rbs_loc_alloc_children before calling this function.
37
53
  * */
38
54
  void rbs_loc_add_required_child(rbs_loc *loc, ID name, range r);
39
55
 
40
56
  /**
41
57
  * Add an optional child range with given name.
58
+ *
59
+ * Allocate memory for children with rbs_loc_alloc_children before calling this function.
42
60
  * */
43
61
  void rbs_loc_add_optional_child(rbs_loc *loc, ID name, range r);
44
62