steep 1.4.0.dev.1 → 1.4.0.dev.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -2
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +13 -15
  5. data/Gemfile.steep +1 -2
  6. data/Gemfile.steep.lock +20 -18
  7. data/README.md +7 -1
  8. data/Steepfile +16 -3
  9. data/bin/rbs +0 -1
  10. data/guides/README.md +5 -0
  11. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +143 -0
  12. data/guides/src/getting-started/getting-started.md +164 -0
  13. data/guides/src/nil-optional/nil-optional.md +195 -0
  14. data/lib/steep/annotation_parser.rb +40 -20
  15. data/lib/steep/ast/types/factory.rb +56 -10
  16. data/lib/steep/ast/types/name.rb +10 -0
  17. data/lib/steep/diagnostic/ruby.rb +80 -5
  18. data/lib/steep/diagnostic/signature.rb +40 -0
  19. data/lib/steep/drivers/check.rb +4 -4
  20. data/lib/steep/index/rbs_index.rb +12 -3
  21. data/lib/steep/index/signature_symbol_provider.rb +1 -1
  22. data/lib/steep/interface/block.rb +10 -0
  23. data/lib/steep/module_helper.rb +13 -11
  24. data/lib/steep/path_helper.rb +4 -0
  25. data/lib/steep/project/target.rb +1 -3
  26. data/lib/steep/server/interaction_worker.rb +102 -72
  27. data/lib/steep/server/lsp_formatter.rb +14 -5
  28. data/lib/steep/services/completion_provider.rb +10 -12
  29. data/lib/steep/services/goto_service.rb +15 -14
  30. data/lib/steep/services/hover_provider/rbs.rb +29 -9
  31. data/lib/steep/services/hover_provider/ruby.rb +16 -10
  32. data/lib/steep/services/signature_service.rb +36 -39
  33. data/lib/steep/services/type_name_completion.rb +157 -0
  34. data/lib/steep/signature/validator.rb +28 -6
  35. data/lib/steep/source.rb +1 -0
  36. data/lib/steep/subtyping/check.rb +1 -1
  37. data/lib/steep/type_construction.rb +414 -239
  38. data/lib/steep/type_inference/block_params.rb +13 -0
  39. data/lib/steep/type_inference/constant_env.rb +7 -3
  40. data/lib/steep/type_inference/context.rb +3 -3
  41. data/lib/steep/type_inference/method_params.rb +42 -16
  42. data/lib/steep/type_inference/send_args.rb +79 -50
  43. data/lib/steep/type_inference/type_env.rb +7 -1
  44. data/lib/steep/version.rb +1 -1
  45. data/lib/steep.rb +1 -0
  46. data/rbs_collection.steep.lock.yaml +9 -41
  47. data/rbs_collection.steep.yaml +11 -8
  48. data/sample/lib/conference.rb +22 -0
  49. data/sample/sig/conference.rbs +28 -0
  50. data/sig/shims/language-server_protocol.rbs +12 -0
  51. data/sig/shims/parser/nodes.rbs +37 -0
  52. data/sig/shims/parser.rbs +1 -0
  53. data/sig/shims/string.rbs +4 -0
  54. data/sig/steep/annotation_parser.rbs +3 -2
  55. data/sig/steep/ast/annotation/collection.rbs +1 -1
  56. data/sig/steep/ast/types/factory.rbs +12 -8
  57. data/sig/steep/ast/types/name.rbs +4 -0
  58. data/sig/steep/diagnostic/lsp_formatter.rbs +1 -1
  59. data/sig/steep/diagnostic/ruby.rbs +38 -2
  60. data/sig/steep/diagnostic/signature.rbs +18 -14
  61. data/sig/steep/drivers/check.rbs +1 -1
  62. data/sig/steep/drivers/checkfile.rbs +1 -1
  63. data/sig/steep/drivers/diagnostic_printer.rbs +1 -1
  64. data/sig/steep/drivers/watch.rbs +1 -1
  65. data/sig/steep/index/rbs_index.rbs +6 -2
  66. data/sig/steep/index/signature_symbol_provider.rbs +1 -1
  67. data/sig/steep/interface/block.rbs +2 -0
  68. data/sig/steep/interface/builder.rbs +5 -3
  69. data/sig/steep/interface/method_type.rbs +5 -3
  70. data/sig/steep/module_helper.rbs +9 -0
  71. data/sig/steep/path_helper.rbs +3 -1
  72. data/sig/steep/project/target.rbs +7 -7
  73. data/sig/steep/server/base_worker.rbs +1 -1
  74. data/sig/steep/server/interaction_worker.rbs +46 -17
  75. data/sig/steep/server/lsp_formatter.rbs +4 -2
  76. data/sig/steep/server/master.rbs +1 -1
  77. data/sig/steep/server/type_check_worker.rbs +7 -5
  78. data/sig/steep/server/worker_process.rbs +6 -4
  79. data/sig/steep/services/completion_provider.rbs +8 -0
  80. data/sig/steep/services/hover_provider/rbs.rbs +6 -4
  81. data/sig/steep/services/hover_provider/ruby.rbs +8 -4
  82. data/sig/steep/services/signature_service.rbs +27 -3
  83. data/sig/steep/services/type_name_completion.rbs +122 -0
  84. data/sig/steep/signature/validator.rbs +9 -5
  85. data/sig/steep/type_construction.rbs +100 -31
  86. data/sig/steep/type_inference/block_params.rbs +4 -0
  87. data/sig/steep/type_inference/constant_env.rbs +2 -0
  88. data/sig/steep/type_inference/context.rbs +70 -22
  89. data/sig/steep/type_inference/method_params.rbs +43 -24
  90. data/sig/steep/type_inference/multiple_assignment.rbs +1 -1
  91. data/sig/steep/type_inference/send_args.rbs +13 -3
  92. data/sig/steep/typing.rbs +7 -2
  93. data/smoke/diagnostics/test_expectations.yml +1 -0
  94. data/smoke/regexp/a.rb +2 -2
  95. data/steep.gemspec +0 -1
  96. metadata +11 -17
@@ -75,7 +75,7 @@ module Steep
75
75
  end
76
76
  end
77
77
 
78
- FileStatus = _ = Struct.new(:path, :content, :decls, keyword_init: true)
78
+ FileStatus = _ = Struct.new(:path, :content, :signature, keyword_init: true)
79
79
 
80
80
  def initialize(env:)
81
81
  builder = RBS::DefinitionBuilder.new(env: env)
@@ -150,7 +150,7 @@ module Steep
150
150
  def apply_changes(files, changes)
151
151
  Steep.logger.tagged "#apply_changes" do
152
152
  Steep.measure2 "Applying change" do |sampler|
153
- changes.each.with_object({}) do |pair, update|
153
+ changes.each.with_object({}) do |pair, update| # $ Hash[Pathname, FileStatus]
154
154
  path, cs = pair
155
155
  sampler.sample "#{path}" do
156
156
  old_text = files[path]&.content
@@ -158,17 +158,18 @@ module Steep
158
158
 
159
159
  buffer = RBS::Buffer.new(name: path, content: content)
160
160
 
161
- update[path] = begin
162
- FileStatus.new(path: path, content: content, decls: RBS::Parser.parse_signature(buffer))
163
- rescue ArgumentError => exn
164
- error = Diagnostic::Signature::UnexpectedError.new(
165
- message: exn.message,
166
- location: RBS::Location.new(buffer: buffer, start_pos: 0, end_pos: content.size)
167
- )
168
- FileStatus.new(path: path, content: content, decls: error)
169
- rescue RBS::ParsingError => exn
170
- FileStatus.new(path: path, content: content, decls: exn)
171
- end
161
+ update[path] =
162
+ begin
163
+ FileStatus.new(path: path, content: content, signature: RBS::Parser.parse_signature(buffer))
164
+ rescue ArgumentError => exn
165
+ error = Diagnostic::Signature::UnexpectedError.new(
166
+ message: exn.message,
167
+ location: RBS::Location.new(buffer: buffer, start_pos: 0, end_pos: content.size)
168
+ )
169
+ FileStatus.new(path: path, content: content, signature: error)
170
+ rescue RBS::ParsingError => exn
171
+ FileStatus.new(path: path, content: content, signature: exn)
172
+ end
172
173
  end
173
174
  end
174
175
  end
@@ -181,16 +182,16 @@ module Steep
181
182
  paths = Set.new(updates.each_key)
182
183
  paths.merge(pending_changed_paths)
183
184
 
184
- if updates.each_value.any? {|file| !file.decls.is_a?(Array) }
185
- diagnostics = []
185
+ if updates.each_value.any? {|file| !file.signature.is_a?(Array) }
186
+ diagnostics = [] #: Array[Diagnostic::Signature::Base]
186
187
 
187
188
  updates.each_value do |file|
188
- unless file.decls.is_a?(Array)
189
- diagnostic = if file.decls.is_a?(Diagnostic::Signature::Base)
190
- file.decls
189
+ unless file.signature.is_a?(Array)
190
+ diagnostic = if file.signature.is_a?(Diagnostic::Signature::Base)
191
+ file.signature
191
192
  else
192
193
  # factory is not used here because the error is a syntax error.
193
- Diagnostic::Signature.from_rbs_error(file.decls, factory: _ = nil)
194
+ Diagnostic::Signature.from_rbs_error(file.signature, factory: _ = nil)
194
195
  end
195
196
  diagnostics << diagnostic
196
197
  end
@@ -204,9 +205,7 @@ module Steep
204
205
  )
205
206
  else
206
207
  files = self.files.merge(updates)
207
- updated_files = paths.each_with_object({}) do |path, hash|
208
- hash[path] = files[path]
209
- end
208
+ updated_files = files.slice(*paths.to_a)
210
209
  result =
211
210
  Steep.measure "#update_env with updated #{paths.size} files" do
212
211
  update_env(updated_files, paths: paths)
@@ -229,33 +228,29 @@ module Steep
229
228
  end
230
229
 
231
230
  def update_env(updated_files, paths:)
231
+
232
232
  Steep.logger.tagged "#update_env" do
233
- # @type var errors: Array[RBS::BaseError]
234
- errors = []
235
- new_decls = Set[].compare_by_identity
233
+ errors = [] #: Array[RBS::BaseError]
234
+ new_decls = Set[].compare_by_identity #: Set[RBS::AST::Declarations::t]
236
235
 
237
236
  env =
238
237
  Steep.measure "Deleting out of date decls" do
239
- latest_env.reject do |decl|
240
- if decl.location
241
- paths.include?(decl.location.buffer.name)
242
- end
243
- end
238
+ bufs = latest_env.buffers.select {|buf| paths.include?(buf.name) }
239
+ latest_env.unload(Set.new(bufs))
244
240
  end
245
241
 
246
242
  Steep.measure "Loading new decls" do
247
243
  updated_files.each_value do |content|
248
- case decls = content.decls
249
- when RBS::BaseError
250
- errors << decls
244
+ case content.signature
245
+ when RBS::ParsingError
246
+ errors << content.signature
251
247
  when Diagnostic::Signature::UnexpectedError
252
- return [decls]
248
+ return [content.signature]
253
249
  else
254
250
  begin
255
- decls.each do |decl|
256
- env << decl
257
- new_decls << decl
258
- end
251
+ buffer, dirs, decls = content.signature
252
+ env.add_signature(buffer: buffer, directives: dirs, decls: decls)
253
+ new_decls.merge(decls)
259
254
  rescue RBS::LoadingError => exn
260
255
  errors << exn
261
256
  end
@@ -375,8 +370,10 @@ module Steep
375
370
  type_name_from_decl(member, set: set)
376
371
  end
377
372
  end
378
- when RBS::AST::Declarations::Alias
373
+ when RBS::AST::Declarations::TypeAlias
379
374
  set << decl.name
375
+ when RBS::AST::Declarations::ClassAlias, RBS::AST::Declarations::ModuleAlias
376
+ set << decl.new_name
380
377
  end
381
378
  end
382
379
 
@@ -0,0 +1,157 @@
1
+ module Steep
2
+ module Services
3
+ class TypeNameCompletion
4
+ module Prefix
5
+ RawIdentPrefix = _ = Struct.new(:ident) do
6
+ # @implements RawIdentPrefix
7
+
8
+ def const_name?
9
+ ident.start_with?(/[A-Z]/)
10
+ end
11
+
12
+ def size
13
+ ident.length
14
+ end
15
+ end
16
+
17
+ NamespacedIdentPrefix = _ = Struct.new(:namespace, :ident, :size) do
18
+ # @implements NamespacedIdentPrefix
19
+
20
+ def const_name?
21
+ ident.start_with?(/[A-Z]/)
22
+ end
23
+ end
24
+
25
+ NamespacePrefix = _ = Struct.new(:namespace, :size)
26
+
27
+ def self.parse(buffer, line:, column:)
28
+ pos = buffer.loc_to_pos([line, column])
29
+ prefix = buffer.content[0...pos] or raise
30
+ prefix.reverse!
31
+
32
+ case prefix
33
+ when /\A((::\w+[A-Z])+(::)?)/
34
+ NamespacePrefix.new(RBS::Namespace.parse($1.reverse), $1.size)
35
+ when /\A::/
36
+ NamespacePrefix.new(RBS::Namespace.root, 2)
37
+ when /\A(\w*[A-Za-z_])((::\w+[A-Z])+(::)?)/
38
+ NamespacedIdentPrefix.new(RBS::Namespace.parse($2.reverse), $1.reverse, $1.size + $2.size)
39
+ when /\A(\w*[A-Za-z_])::/
40
+ NamespacedIdentPrefix.new(RBS::Namespace.root, $1.reverse, $1.size + 2)
41
+ when /\A(\w*[A-Za-z_])/
42
+ RawIdentPrefix.new($1.reverse)
43
+ end
44
+ end
45
+ end
46
+
47
+ attr_reader :env, :context, :type_name_resolver, :map
48
+
49
+ def initialize(env:, context:, dirs:)
50
+ @env = env
51
+ @context = context
52
+
53
+ table = RBS::Environment::UseMap::Table.new()
54
+ table.known_types.merge(env.class_decls.keys)
55
+ table.known_types.merge(env.class_alias_decls.keys)
56
+ table.known_types.merge(env.type_alias_decls.keys)
57
+ table.known_types.merge(env.interface_decls.keys)
58
+ table.compute_children
59
+
60
+ @map = RBS::Environment::UseMap.new(table: table)
61
+ dirs.each do |dir|
62
+ dir.clauses.each do |clause|
63
+ @map.build_map(clause)
64
+ end
65
+ end
66
+
67
+ @type_name_resolver = RBS::Resolver::TypeNameResolver.new(env)
68
+ end
69
+
70
+ def each_outer_module(context = self.context, &block)
71
+ if block
72
+ if (parent, con = context)
73
+ namespace = each_outer_module(parent, &block)
74
+ case con
75
+ when false
76
+ namespace
77
+ when RBS::TypeName
78
+ ns = con.with_prefix(namespace).to_namespace
79
+ yield(ns)
80
+ ns
81
+ end
82
+ else
83
+ yield(RBS::Namespace.root)
84
+ RBS::Namespace.root
85
+ end
86
+ else
87
+ enum_for :each_outer_module
88
+ end
89
+ end
90
+
91
+ def each_type_name(&block)
92
+ if block
93
+ map.instance_eval do
94
+ @map.each_key do |name|
95
+ yield RBS::TypeName.new(name: name, namespace: RBS::Namespace.empty)
96
+ end
97
+ end
98
+ env.class_decls.each_key(&block)
99
+ env.class_alias_decls.each_key(&block)
100
+ env.type_alias_decls.each_key(&block)
101
+ env.interface_decls.each_key(&block)
102
+ else
103
+ enum_for :each_type_name
104
+ end
105
+ end
106
+
107
+ def resolve_name_in_context(name)
108
+ if resolved_name = map.resolve?(name)
109
+ return [resolved_name, name]
110
+ end
111
+
112
+ name.absolute? or raise
113
+
114
+ name.namespace.path.reverse_each.inject(RBS::TypeName.new(namespace: RBS::Namespace.empty, name: name.name)) do |relative_name, component|
115
+ if type_name_resolver.resolve(relative_name, context: context) == name
116
+ return [name, relative_name]
117
+ end
118
+
119
+ RBS::TypeName.new(
120
+ namespace: RBS::Namespace.new(path: [component, *relative_name.namespace.path], absolute: false),
121
+ name: name.name
122
+ )
123
+ end
124
+
125
+ if type_name_resolver.resolve(name.relative!, context: context) == name && !map.resolve?(name.relative!)
126
+ [name, name.relative!]
127
+ else
128
+ [name, name]
129
+ end
130
+ end
131
+
132
+ def find_type_names(prefix)
133
+ case prefix
134
+ when Prefix::RawIdentPrefix
135
+ each_type_name.filter do |type_name|
136
+ type_name.split.any? {|sym| sym.to_s.downcase.include?(prefix.ident.downcase) }
137
+ end
138
+ when Prefix::NamespacedIdentPrefix
139
+ absolute_namespace = type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
140
+
141
+ each_type_name.filter do|name|
142
+ name.namespace == absolute_namespace &&
143
+ name.name.to_s.downcase.include?(prefix.ident.downcase)
144
+ end
145
+ when Prefix::NamespacePrefix
146
+ absolute_namespace = type_name_resolver.resolve(prefix.namespace.to_type_name, context: context)&.to_namespace || prefix.namespace
147
+ each_type_name.filter {|name| name.namespace == absolute_namespace }
148
+ else
149
+ # Returns all of the accessible type names from the context
150
+ namespaces = each_outer_module.to_set
151
+ # Relative type name means a *use*d type name
152
+ each_type_name.filter {|name| namespaces.include?(name.namespace) || !name.absolute? }
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -36,7 +36,7 @@ module Steep
36
36
  end
37
37
 
38
38
  def type_name_resolver
39
- @type_name_resolver ||= RBS::TypeNameResolver.from_env(env)
39
+ @type_name_resolver ||= RBS::Resolver::TypeNameResolver.new(env)
40
40
  end
41
41
 
42
42
  def validator
@@ -112,7 +112,7 @@ module Steep
112
112
  type.args
113
113
  ]
114
114
  when RBS::Types::Alias
115
- entry = env.alias_decls[type.name]
115
+ entry = env.type_alias_decls[type.name]
116
116
 
117
117
  [
118
118
  type.name,
@@ -135,7 +135,7 @@ module Steep
135
135
  def validate_type(type)
136
136
  Steep.logger.debug "#{Location.to_string type.location}: Validating #{type}..."
137
137
 
138
- validator.validate_type type, context: [RBS::Namespace.root]
138
+ validator.validate_type(type, context: nil)
139
139
  validate_type_application(type)
140
140
  end
141
141
 
@@ -235,7 +235,7 @@ module Steep
235
235
  end
236
236
  end
237
237
 
238
- def validate_one_class(name)
238
+ def validate_one_class_decl(name)
239
239
  rescue_validation_errors(name) do
240
240
  Steep.logger.debug { "Validating class definition `#{name}`..." }
241
241
 
@@ -390,6 +390,17 @@ module Steep
390
390
  end
391
391
  end
392
392
 
393
+ def validate_one_class(name)
394
+ entry = env.constant_entry(name)
395
+
396
+ case entry
397
+ when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
398
+ validate_one_class_decl(name)
399
+ when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
400
+ validate_one_class_alias(name, entry)
401
+ end
402
+ end
403
+
393
404
  def validate_ancestor_application(name, ancestor)
394
405
  unless ancestor.args.empty?
395
406
  definition =
@@ -465,6 +476,10 @@ module Steep
465
476
  validate_one_class(name)
466
477
  end
467
478
 
479
+ env.class_alias_decls.each do |name, entry|
480
+ validate_one_class_alias(name, entry)
481
+ end
482
+
468
483
  env.interface_decls.each_key do |name|
469
484
  validate_one_interface(name)
470
485
  end
@@ -497,7 +512,7 @@ module Steep
497
512
  end
498
513
  end
499
514
 
500
- def validate_one_alias(name, entry = env.alias_decls[name])
515
+ def validate_one_alias(name, entry = env.type_alias_decls[name])
501
516
  rescue_validation_errors(name) do
502
517
  Steep.logger.debug "Validating alias `#{name}`..."
503
518
  upper_bounds = entry.decl.type_params.each.with_object({}) do |param, bounds|
@@ -512,8 +527,15 @@ module Steep
512
527
  end
513
528
  end
514
529
 
530
+ def validate_one_class_alias(name, entry)
531
+ rescue_validation_errors(name) do
532
+ Steep.logger.debug "Validating class/module alias `#{name}`..."
533
+ validator.validate_class_alias(entry: entry)
534
+ end
535
+ end
536
+
515
537
  def validate_alias
516
- env.alias_decls.each do |name, entry|
538
+ env.type_alias_decls.each do |name, entry|
517
539
  validate_one_alias(name, entry)
518
540
  end
519
541
  end
data/lib/steep/source.rb CHANGED
@@ -20,6 +20,7 @@ module Steep
20
20
  self.emit_lambda = true
21
21
  self.emit_procarg0 = true
22
22
  self.emit_kwargs = true
23
+ self.emit_forward_arg = true
23
24
  end
24
25
 
25
26
  def self.new_parser
@@ -619,7 +619,7 @@ module Steep
619
619
  return true
620
620
  end
621
621
 
622
- relation.sub_type == relation.super_type
622
+ builder.factory.normalize_type(relation.sub_type) == builder.factory.normalize_type(relation.super_type)
623
623
  end
624
624
 
625
625
  def check_interface(relation)