steep 0.23.0 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/bin/smoke_runner.rb +3 -4
  4. data/lib/steep.rb +4 -3
  5. data/lib/steep/annotation_parser.rb +2 -4
  6. data/lib/steep/ast/builtin.rb +11 -21
  7. data/lib/steep/ast/types.rb +5 -3
  8. data/lib/steep/ast/types/any.rb +1 -3
  9. data/lib/steep/ast/types/boolean.rb +1 -3
  10. data/lib/steep/ast/types/bot.rb +1 -3
  11. data/lib/steep/ast/types/class.rb +2 -2
  12. data/lib/steep/ast/types/factory.rb +249 -89
  13. data/lib/steep/ast/types/helper.rb +6 -0
  14. data/lib/steep/ast/types/instance.rb +2 -2
  15. data/lib/steep/ast/types/intersection.rb +20 -13
  16. data/lib/steep/ast/types/literal.rb +1 -3
  17. data/lib/steep/ast/types/logic.rb +63 -0
  18. data/lib/steep/ast/types/name.rb +15 -67
  19. data/lib/steep/ast/types/nil.rb +1 -3
  20. data/lib/steep/ast/types/proc.rb +5 -2
  21. data/lib/steep/ast/types/record.rb +9 -4
  22. data/lib/steep/ast/types/self.rb +1 -1
  23. data/lib/steep/ast/types/top.rb +1 -3
  24. data/lib/steep/ast/types/tuple.rb +5 -3
  25. data/lib/steep/ast/types/union.rb +16 -9
  26. data/lib/steep/ast/types/var.rb +2 -2
  27. data/lib/steep/ast/types/void.rb +1 -3
  28. data/lib/steep/drivers/check.rb +4 -0
  29. data/lib/steep/errors.rb +14 -0
  30. data/lib/steep/interface/interface.rb +5 -62
  31. data/lib/steep/interface/method_type.rb +394 -93
  32. data/lib/steep/interface/substitution.rb +48 -6
  33. data/lib/steep/module_helper.rb +25 -0
  34. data/lib/steep/project/completion_provider.rb +48 -51
  35. data/lib/steep/project/file.rb +3 -3
  36. data/lib/steep/project/hover_content.rb +4 -6
  37. data/lib/steep/project/target.rb +5 -2
  38. data/lib/steep/server/base_worker.rb +5 -3
  39. data/lib/steep/server/code_worker.rb +2 -0
  40. data/lib/steep/server/master.rb +10 -1
  41. data/lib/steep/signature/validator.rb +3 -3
  42. data/lib/steep/source.rb +4 -3
  43. data/lib/steep/subtyping/check.rb +46 -59
  44. data/lib/steep/subtyping/constraints.rb +8 -0
  45. data/lib/steep/type_construction.rb +771 -513
  46. data/lib/steep/type_inference/block_params.rb +5 -0
  47. data/lib/steep/type_inference/constant_env.rb +3 -6
  48. data/lib/steep/type_inference/context.rb +8 -0
  49. data/lib/steep/type_inference/context_array.rb +4 -3
  50. data/lib/steep/type_inference/logic.rb +31 -0
  51. data/lib/steep/type_inference/logic_type_interpreter.rb +219 -0
  52. data/lib/steep/type_inference/type_env.rb +2 -2
  53. data/lib/steep/typing.rb +7 -0
  54. data/lib/steep/version.rb +1 -1
  55. data/smoke/alias/a.rb +1 -1
  56. data/smoke/case/a.rb +1 -1
  57. data/smoke/hash/d.rb +1 -1
  58. data/smoke/if/a.rb +1 -1
  59. data/smoke/module/a.rb +1 -1
  60. data/smoke/rescue/a.rb +4 -13
  61. data/smoke/type_case/a.rb +0 -7
  62. data/steep.gemspec +2 -2
  63. metadata +10 -10
  64. data/lib/steep/ast/method_type.rb +0 -126
  65. data/lib/steep/ast/namespace.rb +0 -80
  66. data/lib/steep/names.rb +0 -86
@@ -26,7 +26,32 @@ module Steep
26
26
  end
27
27
 
28
28
  def self.empty
29
- new(dictionary: {}, instance_type: AST::Types::Instance.new, module_type: AST::Types::Class.new, self_type: AST::Types::Self.new)
29
+ new(dictionary: {},
30
+ instance_type: INSTANCE_TYPE,
31
+ module_type: CLASS_TYPE,
32
+ self_type: SELF_TYPE)
33
+ end
34
+
35
+ def empty?
36
+ dictionary.empty? &&
37
+ instance_type.is_a?(AST::Types::Instance) &&
38
+ module_type.is_a?(AST::Types::Class) &&
39
+ self_type.is_a?(AST::Types::Self)
40
+ end
41
+
42
+ INSTANCE_TYPE = AST::Types::Instance.new
43
+ CLASS_TYPE = AST::Types::Class.new
44
+ SELF_TYPE = AST::Types::Self.new
45
+
46
+ def domain
47
+ set = Set.new
48
+
49
+ set.merge(dictionary.keys)
50
+ set << INSTANCE_TYPE unless instance_type.is_a?(AST::Types::Instance)
51
+ set << CLASS_TYPE unless instance_type.is_a?(AST::Types::Class)
52
+ set << SELF_TYPE unless instance_type.is_a?(AST::Types::Self)
53
+
54
+ set
30
55
  end
31
56
 
32
57
  def to_s
@@ -65,22 +90,39 @@ module Steep
65
90
 
66
91
  def except(vars)
67
92
  self.class.new(
68
- dictionary: dictionary.reject {|k, _| vars.include?(k) },
93
+ dictionary: dictionary,
69
94
  instance_type: instance_type,
70
95
  module_type: module_type,
71
96
  self_type: self_type
72
- )
97
+ ).except!(vars)
73
98
  end
74
99
 
75
- def merge!(s)
100
+ def except!(vars)
101
+ vars.each do |var|
102
+ dictionary.delete(var)
103
+ end
104
+
105
+ self
106
+ end
107
+
108
+ def merge!(s, overwrite: false)
76
109
  dictionary.transform_values! {|ty| ty.subst(s) }
77
110
  dictionary.merge!(s.dictionary) do |key, a, b|
78
111
  if a == b
79
112
  a
80
113
  else
81
- raise "Duplicated key on merge!: #{key}, #{a}, #{b}"
114
+ if overwrite
115
+ b
116
+ else
117
+ raise "Duplicated key on merge!: #{key}, #{a}, #{b} (#{self})"
118
+ end
82
119
  end
83
120
  end
121
+
122
+ @instance_type = instance_type.subst(s)
123
+ @module_type = module_type.subst(s)
124
+ @self_type = self_type.subst(s)
125
+
84
126
  self
85
127
  end
86
128
 
@@ -92,7 +134,7 @@ module Steep
92
134
  end
93
135
 
94
136
  def add!(v, ty)
95
- merge!(Substitution.new(dictionary: { v => ty }, instance_type: nil, module_type: nil, self_type: nil))
137
+ merge!(Substitution.new(dictionary: { v => ty }, instance_type: instance_type, module_type: module_type, self_type: self_type))
96
138
  end
97
139
  end
98
140
  end
@@ -0,0 +1,25 @@
1
+ module Steep
2
+ module ModuleHelper
3
+ def module_name_from_node(node)
4
+ case node.type
5
+ when :const, :casgn
6
+ namespace = namespace_from_node(node.children[0]) or return
7
+ name = node.children[1]
8
+ RBS::TypeName.new(name: name, namespace: namespace)
9
+ end
10
+ end
11
+
12
+ def namespace_from_node(node)
13
+ case node&.type
14
+ when nil
15
+ RBS::Namespace.empty
16
+ when :cbase
17
+ RBS::Namespace.root
18
+ when :const
19
+ namespace_from_node(node.children[0])&.yield_self do |parent|
20
+ parent.append(node.children[1])
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -10,13 +10,9 @@ module Steep
10
10
 
11
11
  InstanceVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
12
12
  LocalVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
13
- MethodNameItem = Struct.new(:identifier, :range, :definition, :def_type, :inherited_method, keyword_init: true) do
14
- def method_type
15
- def_type.type
16
- end
17
-
13
+ MethodNameItem = Struct.new(:identifier, :range, :method_def, :method_type, :inherited_method, keyword_init: true) do
18
14
  def comment
19
- def_type.comment
15
+ method_def&.comment
20
16
  end
21
17
  end
22
18
 
@@ -90,7 +86,9 @@ module Steep
90
86
  end
91
87
 
92
88
  def at_end?(pos, of:)
93
- of.last_line == pos.line && of.last_column == pos.column
89
+ if of
90
+ of.last_line == pos.line && of.last_column == pos.column
91
+ end
94
92
  end
95
93
 
96
94
  def range_for(position, prefix: "")
@@ -194,21 +192,25 @@ module Steep
194
192
  return [] unless node
195
193
 
196
194
  if at_end?(shift_pos, of: node.loc)
197
- context = typing.context_at(line: position.line, column: position.column)
198
- receiver_type = case (type = typing.type_of(node: node))
199
- when AST::Types::Self
200
- context.self_type
201
- else
202
- type
203
- end
204
-
205
- items = []
206
- method_items_for_receiver_type(receiver_type,
207
- include_private: false,
208
- prefix: "",
209
- position: position,
210
- items: items)
211
- items
195
+ begin
196
+ context = typing.context_at(line: position.line, column: position.column)
197
+ receiver_type = case (type = typing.type_of(node: node))
198
+ when AST::Types::Self
199
+ context.self_type
200
+ else
201
+ type
202
+ end
203
+
204
+ items = []
205
+ method_items_for_receiver_type(receiver_type,
206
+ include_private: false,
207
+ prefix: "",
208
+ position: position,
209
+ items: items)
210
+ items
211
+ rescue Typing::UnknownNodeError
212
+ []
213
+ end
212
214
  else
213
215
  []
214
216
  end
@@ -230,37 +232,27 @@ module Steep
230
232
 
231
233
  def method_items_for_receiver_type(type, include_private:, prefix:, position:, items:)
232
234
  range = range_for(position, prefix: prefix)
233
- definition = case type
234
- when AST::Types::Name::Instance
235
- type_name = subtyping.factory.type_name_1(type.name)
236
- subtyping.factory.definition_builder.build_instance(type_name)
237
- when AST::Types::Name::Class, AST::Types::Name::Module
238
- type_name = subtyping.factory.type_name_1(type.name)
239
- subtyping.factory.definition_builder.build_singleton(type_name)
240
- when AST::Types::Name::Interface
241
- type_name = subtyping.factory.type_name_1(type.name)
242
- subtyping.factory.definition_builder.build_interface(type_name)
243
- end
244
-
245
- if definition
246
- definition.methods.each do |name, method|
247
- next if disallowed_method?(name)
248
-
249
- if include_private || method.public?
250
- if name.to_s.start_with?(prefix)
251
- if word_name?(name.to_s)
252
- method.defs.each do |def_type|
253
- items << MethodNameItem.new(identifier: name,
254
- range: range,
255
- definition: method,
256
- def_type: def_type,
257
- inherited_method: inherited_method?(method, definition))
258
- end
259
- end
235
+ interface = subtyping.factory.interface(type, self_type: type, private: include_private)
236
+
237
+ interface.methods.each do |name, method_entry|
238
+ next if disallowed_method?(name)
239
+
240
+ if name.to_s.start_with?(prefix)
241
+ if word_name?(name.to_s)
242
+ method_entry.method_types.each do |method_type|
243
+ items << MethodNameItem.new(
244
+ identifier: name,
245
+ range: range,
246
+ method_def: method_type.method_def,
247
+ method_type: method_type.method_def&.type || subtyping.factory.method_type_1(method_type, self_type: type),
248
+ inherited_method: inherited_method?(method_type.method_def, type)
249
+ )
260
250
  end
261
251
  end
262
252
  end
263
253
  end
254
+ rescue
255
+ # nop
264
256
  end
265
257
 
266
258
  def word_name?(name)
@@ -304,8 +296,13 @@ module Steep
304
296
  index
305
297
  end
306
298
 
307
- def inherited_method?(method, definition)
308
- method.implemented_in != definition.type_name
299
+ def inherited_method?(method_def, type)
300
+ case type
301
+ when AST::Types::Name::Instance, AST::Types::Name::Singleton, AST::Types::Name::Interface
302
+ method_def.implemented_in != type.name
303
+ else
304
+ false
305
+ end
309
306
  end
310
307
 
311
308
  def disallowed_method?(name)
@@ -41,8 +41,8 @@ module Steep
41
41
  end
42
42
 
43
43
  def self.type_check(source, subtyping:)
44
- annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: AST::Namespace.root)
45
- const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: [AST::Namespace.root])
44
+ annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: RBS::Namespace.root)
45
+ const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: [RBS::Namespace.root])
46
46
  type_env = TypeInference::TypeEnv.build(annotations: annotations,
47
47
  subtyping: subtyping,
48
48
  const_env: const_env,
@@ -58,7 +58,7 @@ module Steep
58
58
  instance_type: nil,
59
59
  module_type: nil,
60
60
  implement_name: nil,
61
- current_namespace: AST::Namespace.root,
61
+ current_namespace: RBS::Namespace.root,
62
62
  const_env: const_env,
63
63
  class_name: nil
64
64
  ),
@@ -21,9 +21,7 @@ module Steep
21
21
  @project = project
22
22
  end
23
23
 
24
- def method_definition_for(factory, module_name, singleton_method: nil, instance_method: nil)
25
- type_name = factory.type_name_1(module_name)
26
-
24
+ def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
27
25
  case
28
26
  when instance_method
29
27
  factory.definition_builder.build_instance(type_name).methods[instance_method]
@@ -86,16 +84,16 @@ module Steep
86
84
  when AST::Types::Name::Instance
87
85
  method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
88
86
  if method_definition&.defined_in
89
- owner_name = factory.type_name(method_definition.defined_in)
87
+ owner_name = method_definition.defined_in
90
88
  [
91
89
  InstanceMethodName.new(owner_name, method_name),
92
90
  method_definition
93
91
  ]
94
92
  end
95
- when AST::Types::Name::Class
93
+ when AST::Types::Name::Singleton
96
94
  method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
97
95
  if method_definition&.defined_in
98
- owner_name = factory.type_name(method_definition.defined_in)
96
+ owner_name = method_definition.defined_in
99
97
  [
100
98
  SingletonMethodName.new(owner_name, method_name),
101
99
  method_definition
@@ -172,6 +172,7 @@ module Steep
172
172
  timestamp: Time.now
173
173
  )
174
174
  rescue => exn
175
+ Steep.log_error exn
175
176
  @status = SignatureOtherErrorStatus.new(error: exn, timestamp: Time.now)
176
177
  end
177
178
  end
@@ -194,8 +195,10 @@ module Steep
194
195
  type_check_sources = []
195
196
 
196
197
  target_sources.each do |file|
197
- if file.type_check(check, timestamp)
198
- type_check_sources << file
198
+ Steep.logger.tagged("path=#{file.path}") do
199
+ if file.type_check(check, timestamp)
200
+ type_check_sources << file
201
+ end
199
202
  end
200
203
  end
201
204
 
@@ -12,6 +12,7 @@ module Steep
12
12
  @project = project
13
13
  @reader = reader
14
14
  @writer = writer
15
+ @shutdown = false
15
16
  end
16
17
 
17
18
  def handle_request(request)
@@ -28,7 +29,7 @@ module Steep
28
29
  Steep.logger.formatter.push_tags(*tags)
29
30
  Steep.logger.tagged "background" do
30
31
  while job = queue.pop
31
- handle_job(job)
32
+ handle_job(job) unless @shutdown
32
33
  end
33
34
  end
34
35
  end
@@ -38,11 +39,12 @@ module Steep
38
39
  reader.read do |request|
39
40
  case request[:method]
40
41
  when "shutdown"
41
- # nop
42
+ @shutdown = true
43
+ writer.write(id: request[:id], result: nil)
42
44
  when "exit"
43
45
  break
44
46
  else
45
- handle_request(request)
47
+ handle_request(request) unless @shutdown
46
48
  end
47
49
  end
48
50
  ensure
@@ -139,6 +139,8 @@ module Steep
139
139
  end
140
140
 
141
141
  def handle_job(job)
142
+ sleep 0.1
143
+
142
144
  path, version, target = job
143
145
  if !version || target_files[path] == version
144
146
  typecheck_file(path, target)
@@ -23,6 +23,7 @@ module Steep
23
23
  @signature_worker = signature_worker
24
24
  @code_workers = code_workers
25
25
  @worker_to_paths = {}
26
+ @shutdown_request_id = nil
26
27
  end
27
28
 
28
29
  def start
@@ -59,7 +60,14 @@ module Steep
59
60
  end
60
61
 
61
62
  while job = queue.pop
62
- writer.write(job)
63
+ if @shutdown_request_id
64
+ if job[:id] == @shutdown_request_id
65
+ writer.write(job)
66
+ break
67
+ end
68
+ else
69
+ writer.write(job)
70
+ end
63
71
  end
64
72
 
65
73
  writer.io.close
@@ -154,6 +162,7 @@ module Steep
154
162
 
155
163
  when "shutdown"
156
164
  queue << { id: id, result: nil }
165
+ @shutdown_request_id = id
157
166
 
158
167
  when "exit"
159
168
  queue << nil
@@ -130,19 +130,19 @@ module Steep
130
130
  yield
131
131
  rescue RBS::InvalidTypeApplicationError => exn
132
132
  @errors << Errors::InvalidTypeApplicationError.new(
133
- name: factory.type_name(exn.type_name),
133
+ name: exn.type_name,
134
134
  args: exn.args.map {|ty| factory.type(ty) },
135
135
  params: exn.params,
136
136
  location: exn.location
137
137
  )
138
138
  rescue RBS::NoTypeFoundError, RBS::NoSuperclassFoundError, RBS::NoMixinFoundError => exn
139
139
  @errors << Errors::UnknownTypeNameError.new(
140
- name: factory.type_name(exn.type_name),
140
+ name: exn.type_name,
141
141
  location: exn.location
142
142
  )
143
143
  rescue RBS::InvalidOverloadMethodError => exn
144
144
  @errors << Errors::InvalidMethodOverloadError.new(
145
- class_name: factory.type_name(exn.type_name),
145
+ class_name: exn.type_name,
146
146
  method_name: exn.method_name,
147
147
  location: exn.members[0].location
148
148
  )
@@ -38,7 +38,7 @@ module Steep
38
38
  end
39
39
 
40
40
  def self.parser
41
- ::Parser::Ruby25.new(Builder.new).tap do |parser|
41
+ ::Parser::Ruby27.new(Builder.new).tap do |parser|
42
42
  parser.diagnostics.all_errors_are_fatal = true
43
43
  parser.diagnostics.ignore_warnings = true
44
44
  end
@@ -60,7 +60,7 @@ module Steep
60
60
  _, comments, _ = yield_self do
61
61
  buffer = ::Parser::Source::Buffer.new(path.to_s)
62
62
  buffer.source = source_code
63
- parser = ::Parser::Ruby25.new
63
+ parser = ::Parser::Ruby27.new
64
64
 
65
65
  parser.tokenize(buffer)
66
66
  end
@@ -79,6 +79,7 @@ module Steep
79
79
  end
80
80
 
81
81
  mapping = {}
82
+
82
83
  construct_mapping(node: node, annotations: annotations, mapping: mapping)
83
84
 
84
85
  annotations.each do |annot|
@@ -185,7 +186,7 @@ module Steep
185
186
  construct_mapping(node: node.children[0], annotations: annotations, mapping: mapping, line_range: nil)
186
187
  end
187
188
 
188
- if node.loc.else
189
+ if node.children.last
189
190
  else_node = node.children.last
190
191
  else_start = node.loc.else.last_line
191
192
  else_end = node.loc.end.line