rbs 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5318ae7911a3e7e4e1bed761e0c7b8d1fc248e698b0d53f8a39d388da5617f0
4
- data.tar.gz: d90f20d41372bcc852f49b844aa6b6b5367d9d88ec686a13ab00841f1cf1e2ed
3
+ metadata.gz: ce3b2807a94277727870ef841bdb1e3a96567098948930ab6885e9fba2fc3ccf
4
+ data.tar.gz: 5d4a01b26887124240ec757b8a0374c79d56c3daf8b32431a571a3ba401112cc
5
5
  SHA512:
6
- metadata.gz: 702ae082267eb6a087e19c5a37a83aaaeea0f76e83eba7cc984a15cca869745d1b934231bf6910dbbba972a06301948eca740aa2a8fc49c378487a030befe909
7
- data.tar.gz: 8f467c52d50c25886965e1762f7c52f246cb90fa313c7d0a9400051f32c7f3603ada0142cf90ebfad4b56ccbaf57bacd5d1467cb8daf20247254c90937b9c599
6
+ metadata.gz: 7978edfd75f809eb604edb58e0c35ff9a1e85b0e34f7462399f76deb36c5a6a0c61030d1fc3a3bb42d689395a0372995e03e41dd47223063084703dc207294d6
7
+ data.tar.gz: e1216599f496cd883e8b301d1040f395984d3fc3029ba65fa6c2f63ab3e431a96bc8369ff06bd3f97390dd78e0a10279e1e556ba2c25ac4ef5af6dfaf9aafa77
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.6.0 (2020-07-12)
6
+
7
+ * Signature update for `Logger`.
8
+ * Clean `Environment#inspect`. [#331](https://github.com/ruby/rbs/pull/331)
9
+ * Module self type syntax update. [#329](https://github.com/ruby/rbs/pull/329)
10
+ * Better validation. [#328](https://github.com/ruby/rbs/pull/328)
11
+ * Parser performance improvement. [#327](https://github.com/ruby/rbs/pull/327)
12
+ * Runtime type checking performance improvements with sampling [#323](https://github.com/ruby/rbs/pull/323)
13
+
5
14
  ## 0.5.0 (2020-07-04)
6
15
 
7
16
  * Signature updates for `Mutex_m`, `IO`, and `Enumerable`.
data/Gemfile CHANGED
@@ -13,6 +13,8 @@ gem "minitest-reporters"
13
13
  gem "json"
14
14
  gem "json-schema"
15
15
  gem 'stackprof'
16
+ gem "goodcheck"
16
17
 
17
18
  # Test gems
18
19
  gem "rbs-amber", path: "test/assets/test-gem"
20
+
data/Rakefile CHANGED
@@ -78,11 +78,10 @@ namespace :generate do
78
78
  def call
79
79
  ERB.new(<<~ERB, trim_mode: "-").result(binding)
80
80
  require_relative "test_helper"
81
- require 'rbs/test/test_helper'
82
81
 
83
82
  <%- unless class_methods.empty? -%>
84
83
  class <%= klass %>SingletonTest < Minitest::Test
85
- include RBS::Test::TypeAssertions
84
+ include TypeAssertions
86
85
 
87
86
  # library "pathname", "set", "securerandom" # Declare library signatures to load
88
87
  testing "singleton(::<%= klass %>)"
@@ -100,7 +99,7 @@ namespace :generate do
100
99
 
101
100
  <%- unless instance_methods.empty? -%>
102
101
  class <%= klass %>Test < Minitest::Test
103
- include RBS::Test::TypeAssertions
102
+ include TypeAssertions
104
103
 
105
104
  # library "pathname", "set", "securerandom" # Declare library signatures to load
106
105
  testing "::<%= klass %>"
@@ -120,7 +120,6 @@ The test scripts would look like the following:
120
120
  ```rb
121
121
  class StringTest < StdlibTest
122
122
  target String
123
- using hook.refinement
124
123
 
125
124
  def test_gsub
126
125
  s = "string"
@@ -136,7 +135,6 @@ end
136
135
 
137
136
  You need two method calls, `target` and `using`.
138
137
  `target` method call tells which class is the subject of the class.
139
- `using hook.refinement` installs a special instrumentation for stdlib, based on refinements.
140
138
  And you write the sample programs which calls all of the patterns of overloads.
141
139
 
142
140
  Note that the instrumentation is based on refinements and you need to write all method calls in the unit class definitions.
@@ -166,7 +166,7 @@ end
166
166
 
167
167
  ### Proc type
168
168
 
169
- Proc type denots type of procedures, `Proc` instances.
169
+ Proc type denotes type of procedures, `Proc` instances.
170
170
 
171
171
  ```
172
172
  ^(Integer) -> String # A procedure with an `Integer` parameter and returns `String`
@@ -348,7 +348,7 @@ attr_reader id: Integer
348
348
  # @id: Integer
349
349
  # def id: () -> Integer
350
350
 
351
- # Defines `name=` method and `raw_name` instance variable.
351
+ # Defines `name=` method and `@raw_name` instance variable.
352
352
  attr_writer name (@raw_name) : String
353
353
  # @raw_name: String
354
354
  # def name=: (String) -> String
@@ -408,7 +408,10 @@ _class-decl_ ::= `class` _class-name_ _module-type-parameters_ _members_ `end`
408
408
  | `class` _class-name_ _module-type-parameters_ `<` _class-name_ _type-arguments_ _members_ `end`
409
409
 
410
410
  _module-decl_ ::= `module` _module-name_ _module-type-parameters_ _members_ `end`
411
- | `module` _module-name_ _module-type-parameters_ `:` _class-name_ _type-arguments_ _members_ `end`
411
+ | `module` _module-name_ _module-type-parameters_ `:` _module-self-types_ _members_ `end`
412
+
413
+ _module-self-types_ ::= _class-name_ _type-arguments_ `,` _module-self-types_ (Class instance)
414
+ | _interface-name_ _type-arguments_ `,` _module-self-types_ (Interface)
412
415
 
413
416
  _interface-decl_ ::= `interface` _interface-name_ _module-type-parameters_ _interface-members_ `end`
414
417
 
@@ -0,0 +1,65 @@
1
+ rules:
2
+ - id: rbs.no_mark
3
+ pattern: 💪👽🚨
4
+ message: Do you forget to delete `arglists` section?
5
+ glob:
6
+ - "stdlib/**/*.rbs"
7
+ fail:
8
+ - |
9
+ # arglists 💪👽🚨 << Delete this section
10
+ # File.absolute_path?(file_name) -> true or false
11
+ #
12
+
13
+ - id: rbs.no_arg
14
+ pattern:
15
+ regexp: arg\d+
16
+ message: |
17
+ Stop using parameter names like `arg0` or `arg1`
18
+
19
+ The parameter names like `arg0` or `arg1` is not informative enough.
20
+ Try finding good parameter names from documents or arglists.
21
+ If you cannot find a good name, just delete the name of the parameters.
22
+ justification:
23
+ - Documents (comments) may contain that pattern.
24
+ glob:
25
+ - "stdlib/**/*.rbs"
26
+ fail:
27
+ - "def `send`: (String | Symbol arg0, *untyped arg1) -> untyped"
28
+ pass:
29
+ - "def `send`: (String | Symbol, *untyped) -> untyped"
30
+
31
+ - id: deprecate_stdlib_test
32
+ pattern:
33
+ token: < StdlibTest
34
+ message: |
35
+ StdlibTest is deprecated
36
+
37
+ We recommend writing tests based on `TypeAssertions` and `#assert_send_type`.
38
+ justification:
39
+ - When you are updating existing tests.
40
+ - When you are writing tests for callback, which cannot be done with `#assert_send_type`.
41
+ glob:
42
+ - "test/stdlib/**/*_test.rb"
43
+ fail:
44
+ - |
45
+ class IntegerTest < StdlibTest
46
+ target Integer
47
+
48
+ def test_plus
49
+ 1 + 2
50
+ end
51
+ end
52
+ pass:
53
+ - |
54
+ class IntegerTest < Minitest::Test
55
+ include TypeAssertions
56
+
57
+ testing "Integer"
58
+
59
+ def test_plus
60
+ assert_send_type "(::Integer) -> ::Integer",
61
+ 1, :+, 2
62
+ end
63
+ end
64
+
65
+
data/lib/rbs.rb CHANGED
@@ -36,6 +36,7 @@ require "rbs/type_name_resolver"
36
36
  require "rbs/environment_walker"
37
37
  require "rbs/vendorer"
38
38
  require "rbs/validator"
39
+ require "rbs/factory"
39
40
 
40
41
  begin
41
42
  require "rbs/parser"
@@ -204,6 +204,44 @@ module RBS
204
204
  end
205
205
 
206
206
  class Module < Base
207
+ class Self
208
+ attr_reader :name
209
+ attr_reader :args
210
+ attr_reader :location
211
+
212
+ def initialize(name:, args:, location:)
213
+ @name = name
214
+ @args = args
215
+ @location = location
216
+ end
217
+
218
+ def ==(other)
219
+ other.is_a?(Self) && other.name == name && other.args == args
220
+ end
221
+
222
+ alias eql? ==
223
+
224
+ def hash
225
+ self.class.hash ^ name.hash ^ args.hash ^ location.hash
226
+ end
227
+
228
+ def to_json(*a)
229
+ {
230
+ name: name,
231
+ args: args,
232
+ location: location
233
+ }.to_json(*a)
234
+ end
235
+
236
+ def to_s
237
+ if args.empty?
238
+ name.to_s
239
+ else
240
+ "#{name}[#{args.join(", ")}]"
241
+ end
242
+ end
243
+ end
244
+
207
245
  include NestedDeclarationHelper
208
246
  include MixinHelper
209
247
 
@@ -212,13 +250,13 @@ module RBS
212
250
  attr_reader :members
213
251
  attr_reader :location
214
252
  attr_reader :annotations
215
- attr_reader :self_type
253
+ attr_reader :self_types
216
254
  attr_reader :comment
217
255
 
218
- def initialize(name:, type_params:, members:, self_type:, annotations:, location:, comment:)
256
+ def initialize(name:, type_params:, members:, self_types:, annotations:, location:, comment:)
219
257
  @name = name
220
258
  @type_params = type_params
221
- @self_type = self_type
259
+ @self_types = self_types
222
260
  @members = members
223
261
  @annotations = annotations
224
262
  @location = location
@@ -229,14 +267,14 @@ module RBS
229
267
  other.is_a?(Module) &&
230
268
  other.name == name &&
231
269
  other.type_params == type_params &&
232
- other.self_type == self_type &&
270
+ other.self_types == self_types &&
233
271
  other.members == members
234
272
  end
235
273
 
236
274
  alias eql? ==
237
275
 
238
276
  def hash
239
- self.class.hash ^ name.hash ^ type_params.hash ^ self_type.hash ^ members.hash
277
+ self.class.hash ^ name.hash ^ type_params.hash ^ self_types.hash ^ members.hash
240
278
  end
241
279
 
242
280
  def to_json(*a)
@@ -245,7 +283,7 @@ module RBS
245
283
  name: name,
246
284
  type_params: type_params,
247
285
  members: members,
248
- self_type: self_type,
286
+ self_types: self_types,
249
287
  annotations: annotations,
250
288
  location: location,
251
289
  comment: comment
@@ -48,7 +48,7 @@ module RBS
48
48
  def instance_ancestors(type_name, building_ancestors: [])
49
49
  as = instance_ancestors_cache[type_name] and return as
50
50
 
51
- entry = env.class_decls[type_name]
51
+ entry = env.class_decls[type_name] or raise "Unknown name for instance_ancestors: #{type_name}"
52
52
  params = entry.type_params.each.map(&:name)
53
53
  args = Types::Variable.build(params)
54
54
  self_ancestor = Definition::Ancestor::Instance.new(name: type_name, args: args)
@@ -77,6 +77,8 @@ module RBS
77
77
  super_args = []
78
78
  end
79
79
 
80
+ NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
81
+
80
82
  super_ancestors = instance_ancestors(super_name, building_ancestors: building_ancestors)
81
83
  ancestors.unshift(*super_ancestors.apply(super_args, location: primary.decl.location))
82
84
  end
@@ -100,7 +102,7 @@ module RBS
100
102
  def singleton_ancestors(type_name, building_ancestors: [])
101
103
  as = singleton_ancestor_cache[type_name] and return as
102
104
 
103
- entry = env.class_decls[type_name]
105
+ entry = env.class_decls[type_name] or raise "Unknown name for singleton_ancestors: #{type_name}"
104
106
  self_ancestor = Definition::Ancestor::Singleton.new(name: type_name)
105
107
 
106
108
  RecursiveAncestorError.check!(self_ancestor,
@@ -123,6 +125,8 @@ module RBS
123
125
  super_name = BuiltinNames::Object.name
124
126
  end
125
127
 
128
+ NoSuperclassFoundError.check!(super_name, env: env, location: primary.decl.location)
129
+
126
130
  super_ancestors = singleton_ancestors(super_name, building_ancestors: building_ancestors)
127
131
  ancestors.unshift(*super_ancestors.ancestors)
128
132
  else
@@ -143,6 +147,8 @@ module RBS
143
147
  case member
144
148
  when AST::Members::Extend
145
149
  if member.name.class?
150
+ NoMixinFoundError.check!(member.name, env: env, member: member)
151
+
146
152
  module_ancestors = instance_ancestors(member.name, building_ancestors: building_ancestors)
147
153
  ancestors.unshift(*module_ancestors.apply(member.args, location: member.location))
148
154
  end
@@ -174,6 +180,8 @@ module RBS
174
180
  case member
175
181
  when AST::Members::Include
176
182
  if member.name.class?
183
+ NoMixinFoundError.check!(member.name, env: env, member: member)
184
+
177
185
  module_name = member.name
178
186
  module_args = member.args.map {|type| type.sub(align_params) }
179
187
 
@@ -197,6 +205,8 @@ module RBS
197
205
  decl.each_mixin do |member|
198
206
  case member
199
207
  when AST::Members::Prepend
208
+ NoMixinFoundError.check!(member.name, env: env, member: member)
209
+
200
210
  module_name = member.name
201
211
  module_args = member.args.map {|type| type.sub(align_params) }
202
212
 
@@ -222,7 +232,7 @@ module RBS
222
232
 
223
233
  def build_instance(type_name)
224
234
  try_cache type_name, cache: instance_cache do
225
- entry = env.class_decls[type_name]
235
+ entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}"
226
236
 
227
237
  case entry
228
238
  when Environment::ClassEntry, Environment::ModuleEntry
@@ -243,11 +253,18 @@ module RBS
243
253
  end
244
254
 
245
255
  if entry.is_a?(Environment::ModuleEntry)
246
- if self_type_ancestor = module_self_ancestor(type_name, entry)
247
- definition_pairs.push [
248
- self_type_ancestor,
249
- build_interface(self_type_ancestor.name)
250
- ]
256
+ entry.self_types.each do |module_self|
257
+ ancestor = Definition::Ancestor::Instance.new(name: module_self.name, args: module_self.args)
258
+ definition_pairs.push(
259
+ [
260
+ ancestor,
261
+ if module_self.name.interface?
262
+ build_interface(module_self.name)
263
+ else
264
+ build_instance(module_self.name)
265
+ end
266
+ ]
267
+ )
251
268
  end
252
269
  end
253
270
 
@@ -259,32 +276,9 @@ module RBS
259
276
  end
260
277
  end
261
278
 
262
- def module_self_ancestor(type_name, entry)
263
- self_decls = entry.decls.select {|d| d.decl.self_type }
264
-
265
- return if self_decls.empty?
266
-
267
- selfs = self_decls.map do |d|
268
- Definition::Ancestor::Instance.new(
269
- name: d.decl.self_type.name,
270
- args: d.decl.self_type.args
271
- )
272
- end
273
-
274
- selfs.uniq!
275
-
276
- return selfs[0] if selfs.size == 1
277
-
278
- raise ModuleSelfTypeMismatchError.new(
279
- name: type_name,
280
- entry: entry,
281
- location: self_decls[0].decl.location
282
- )
283
- end
284
-
285
279
  def build_singleton(type_name)
286
280
  try_cache type_name, cache: singleton_cache do
287
- entry = env.class_decls[type_name]
281
+ entry = env.class_decls[type_name] or raise "Unknown name for build_singleton: #{type_name}"
288
282
 
289
283
  case entry
290
284
  when Environment::ClassEntry, Environment::ModuleEntry
@@ -350,6 +344,8 @@ module RBS
350
344
  when AST::Members::Include, AST::Members::Extend
351
345
  if member.name.interface?
352
346
  if (kind == :instance && member.is_a?(AST::Members::Include)) || (kind == :singleton && member.is_a?(AST::Members::Extend))
347
+ NoMixinFoundError.check!(member.name, env: env, member: member)
348
+
353
349
  interface_name = member.name
354
350
  interface_args = member.args
355
351
 
@@ -867,7 +863,7 @@ module RBS
867
863
 
868
864
  def build_interface(type_name)
869
865
  try_cache(type_name, cache: interface_cache) do
870
- entry = env.interface_decls[type_name]
866
+ entry = env.interface_decls[type_name] or raise "Unknown name for build_interface: #{type_name}"
871
867
  declaration = entry.decl
872
868
 
873
869
  self_type = Types::Interface.new(
@@ -893,6 +889,8 @@ module RBS
893
889
  end
894
890
 
895
891
  include_members.each do |member|
892
+ NoMixinFoundError.check!(member.name, env: env, member: member)
893
+
896
894
  mixin = build_interface(member.name)
897
895
 
898
896
  args = member.args
@@ -957,7 +955,8 @@ module RBS
957
955
  end
958
956
 
959
957
  def expand_alias(type_name)
960
- env.alias_decls[type_name].decl.type
958
+ entry = env.alias_decls[type_name] or raise "Unknown name for expand_alias: #{type_name}"
959
+ entry.decl.type
961
960
  end
962
961
  end
963
962
  end
@@ -34,56 +34,49 @@ module RBS
34
34
 
35
35
  def insert(decl:, outer:)
36
36
  decls << D.new(decl: decl, outer: outer)
37
+ @primary = nil
37
38
  end
38
39
 
39
- def type_params
40
- primary.decl.type_params
41
- end
42
- end
40
+ def validate_type_params
41
+ unless decls.empty?
42
+ hd_decl, *tl_decls = decls
43
+ hd_params = hd_decl.decl.type_params
44
+ hd_names = hd_params.params.map(&:name)
43
45
 
44
- class ModuleEntry < MultiEntry
45
- def insert(decl:, outer:)
46
- unless decl.is_a?(AST::Declarations::Module)
47
- raise MixedClassModuleDeclarationError.new(name: name, decl: decl)
48
- end
46
+ tl_decls.each do |tl_decl|
47
+ tl_params = tl_decl.decl.type_params
49
48
 
50
- unless decls.empty?
51
- names = decls[0].decl.type_params.each.map(&:name)
52
- unless names.size == decl.type_params.each.size && decls[0].decl.type_params == decl.type_params.rename_to(names)
53
- raise GenericParameterMismatchError.new(name: name, decl: decl)
49
+ unless hd_params.size == tl_params.size && hd_params == tl_params.rename_to(hd_names)
50
+ raise GenericParameterMismatchError.new(name: name, decl: tl_decl.decl)
51
+ end
54
52
  end
55
53
  end
54
+ end
56
55
 
57
- super(decl: decl, outer: outer)
56
+ def type_params
57
+ primary.decl.type_params
58
58
  end
59
+ end
59
60
 
60
- def primary
61
- @primary ||= decls.find {|d| d.decl.self_type } || decls.first
61
+ class ModuleEntry < MultiEntry
62
+ def self_types
63
+ decls.flat_map do |d|
64
+ d.decl.self_types
65
+ end.uniq
62
66
  end
63
67
 
64
- def self_type
65
- primary.decl.self_type
68
+ def primary
69
+ @primary ||= begin
70
+ validate_type_params
71
+ decls.first
72
+ end
66
73
  end
67
74
  end
68
75
 
69
76
  class ClassEntry < MultiEntry
70
- def insert(decl:, outer:)
71
- unless decl.is_a?(AST::Declarations::Class)
72
- raise MixedClassModuleDeclarationError.new(name: name, decl: decl)
73
- end
74
-
75
- unless decls.empty?
76
- names = decls[0].decl.type_params.each.map(&:name)
77
- unless names.size == decl.type_params.each.size && decls[0].decl.type_params == decl.type_params.rename_to(names)
78
- raise GenericParameterMismatchError.new(name: name, decl: decl)
79
- end
80
- end
81
-
82
- super(decl: decl, outer: outer)
83
- end
84
-
85
77
  def primary
86
78
  @primary ||= begin
79
+ validate_type_params
87
80
  decls.find {|d| d.decl.super_class } || decls.first
88
81
  end
89
82
  end
@@ -157,7 +150,18 @@ module RBS
157
150
  end
158
151
  end
159
152
 
160
- class_decls[name].insert(decl: decl, outer: outer)
153
+ existing_entry = class_decls[name]
154
+
155
+ case
156
+ when decl.is_a?(AST::Declarations::Module) && existing_entry.is_a?(ModuleEntry)
157
+ # OK
158
+ when decl.is_a?(AST::Declarations::Class) && existing_entry.is_a?(ClassEntry)
159
+ # OK
160
+ else
161
+ raise DuplicatedDeclarationError.new(name, decl, existing_entry.primary.decl)
162
+ end
163
+
164
+ existing_entry.insert(decl: decl, outer: outer)
161
165
 
162
166
  prefix = outer + [decl]
163
167
  ns = name.to_namespace
@@ -255,8 +259,12 @@ module RBS
255
259
  AST::Declarations::Module.new(
256
260
  name: decl.name.with_prefix(prefix),
257
261
  type_params: decl.type_params,
258
- self_type: decl.self_type&.yield_self do |self_type|
259
- absolute_type(resolver, self_type, context: context)
262
+ self_types: decl.self_types.map do |module_self|
263
+ AST::Declarations::Module::Self.new(
264
+ name: absolute_type_name(resolver, module_self.name, context: context),
265
+ args: module_self.args.map {|type| absolute_type(resolver, type, context: context) },
266
+ location: module_self.location
267
+ )
260
268
  end,
261
269
  members: decl.members.map do |member|
262
270
  case member
@@ -406,5 +414,10 @@ module RBS
406
414
  absolute_type_name(resolver, name, context: context)
407
415
  end
408
416
  end
417
+
418
+ def inspect
419
+ ivars = %i[@buffers @declarations @class_decls @interface_decls @alias_decls @constant_decls @global_decls]
420
+ "\#<RBS::Environment #{ivars.map { |iv| "#{iv}=(#{instance_variable_get(iv).size} items)"}.join(' ')}>"
421
+ end
409
422
  end
410
423
  end