steep 0.40.0 → 0.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +1 -0
  4. data/bin/output_rebaseline.rb +15 -30
  5. data/bin/output_test.rb +23 -57
  6. data/lib/steep.rb +89 -15
  7. data/lib/steep/annotation_parser.rb +10 -2
  8. data/lib/steep/ast/types/class.rb +4 -0
  9. data/lib/steep/cli.rb +31 -6
  10. data/lib/steep/diagnostic/ruby.rb +13 -8
  11. data/lib/steep/diagnostic/signature.rb +152 -2
  12. data/lib/steep/drivers/annotations.rb +18 -36
  13. data/lib/steep/drivers/check.rb +140 -31
  14. data/lib/steep/drivers/diagnostic_printer.rb +20 -11
  15. data/lib/steep/drivers/langserver.rb +4 -8
  16. data/lib/steep/drivers/print_project.rb +10 -9
  17. data/lib/steep/drivers/stats.rb +135 -119
  18. data/lib/steep/drivers/utils/driver_helper.rb +35 -0
  19. data/lib/steep/drivers/utils/jobs_count.rb +9 -0
  20. data/lib/steep/drivers/validate.rb +29 -18
  21. data/lib/steep/drivers/watch.rb +55 -49
  22. data/lib/steep/drivers/worker.rb +11 -8
  23. data/lib/steep/expectations.rb +159 -0
  24. data/lib/steep/index/signature_symbol_provider.rb +23 -1
  25. data/lib/steep/index/source_index.rb +55 -5
  26. data/lib/steep/interface/block.rb +4 -0
  27. data/lib/steep/project.rb +0 -30
  28. data/lib/steep/project/dsl.rb +5 -3
  29. data/lib/steep/project/pattern.rb +56 -0
  30. data/lib/steep/project/target.rb +11 -227
  31. data/lib/steep/server/base_worker.rb +1 -3
  32. data/lib/steep/server/change_buffer.rb +63 -0
  33. data/lib/steep/server/interaction_worker.rb +72 -57
  34. data/lib/steep/server/master.rb +652 -234
  35. data/lib/steep/server/type_check_worker.rb +304 -0
  36. data/lib/steep/server/worker_process.rb +16 -11
  37. data/lib/steep/{project → services}/completion_provider.rb +5 -5
  38. data/lib/steep/services/content_change.rb +61 -0
  39. data/lib/steep/services/file_loader.rb +48 -0
  40. data/lib/steep/services/goto_service.rb +321 -0
  41. data/lib/steep/{project → services}/hover_content.rb +19 -20
  42. data/lib/steep/services/path_assignment.rb +27 -0
  43. data/lib/steep/services/signature_service.rb +403 -0
  44. data/lib/steep/services/stats_calculator.rb +69 -0
  45. data/lib/steep/services/type_check_service.rb +413 -0
  46. data/lib/steep/signature/validator.rb +187 -85
  47. data/lib/steep/source.rb +21 -18
  48. data/lib/steep/subtyping/check.rb +246 -45
  49. data/lib/steep/subtyping/constraints.rb +4 -4
  50. data/lib/steep/type_construction.rb +428 -193
  51. data/lib/steep/type_inference/block_params.rb +1 -1
  52. data/lib/steep/type_inference/context.rb +22 -0
  53. data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
  54. data/lib/steep/type_inference/logic.rb +1 -1
  55. data/lib/steep/type_inference/logic_type_interpreter.rb +4 -4
  56. data/lib/steep/type_inference/type_env.rb +43 -17
  57. data/lib/steep/version.rb +1 -1
  58. data/smoke/alias/test_expectations.yml +96 -0
  59. data/smoke/and/test_expectations.yml +31 -0
  60. data/smoke/array/test_expectations.yml +103 -0
  61. data/smoke/block/test_expectations.yml +125 -0
  62. data/smoke/case/test_expectations.yml +47 -0
  63. data/smoke/class/test_expectations.yml +120 -0
  64. data/smoke/const/test_expectations.yml +129 -0
  65. data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
  66. data/smoke/diagnostics-rbs/Steepfile +7 -4
  67. data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
  68. data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
  69. data/smoke/{broken → diagnostics-ruby-unsat}/Steepfile +0 -0
  70. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  71. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  72. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  73. data/smoke/diagnostics/a.rbs +0 -4
  74. data/smoke/diagnostics/test_expectations.yml +451 -0
  75. data/smoke/dstr/test_expectations.yml +13 -0
  76. data/smoke/ensure/test_expectations.yml +62 -0
  77. data/smoke/enumerator/test_expectations.yml +135 -0
  78. data/smoke/extension/f.rb +2 -0
  79. data/smoke/extension/f.rbs +3 -0
  80. data/smoke/extension/test_expectations.yml +73 -0
  81. data/smoke/hash/test_expectations.yml +81 -0
  82. data/smoke/hello/test_expectations.yml +25 -0
  83. data/smoke/if/test_expectations.yml +34 -0
  84. data/smoke/implements/b.rb +13 -0
  85. data/smoke/implements/b.rbs +12 -0
  86. data/smoke/implements/test_expectations.yml +23 -0
  87. data/smoke/initialize/test_expectations.yml +1 -0
  88. data/smoke/integer/test_expectations.yml +101 -0
  89. data/smoke/interface/test_expectations.yml +23 -0
  90. data/smoke/kwbegin/test_expectations.yml +17 -0
  91. data/smoke/lambda/test_expectations.yml +39 -0
  92. data/smoke/literal/test_expectations.yml +106 -0
  93. data/smoke/map/test_expectations.yml +1 -0
  94. data/smoke/method/test_expectations.yml +90 -0
  95. data/smoke/module/test_expectations.yml +75 -0
  96. data/smoke/regexp/test_expectations.yml +615 -0
  97. data/smoke/regression/issue_328.rb +1 -0
  98. data/smoke/regression/issue_328.rbs +0 -0
  99. data/smoke/regression/issue_332.rb +11 -0
  100. data/smoke/regression/issue_332.rbs +19 -0
  101. data/smoke/regression/issue_372.rb +8 -0
  102. data/smoke/regression/issue_372.rbs +4 -0
  103. data/smoke/regression/masgn.rb +4 -0
  104. data/smoke/regression/test_expectations.yml +60 -0
  105. data/smoke/regression/thread.rb +7 -0
  106. data/smoke/rescue/test_expectations.yml +79 -0
  107. data/smoke/self/test_expectations.yml +23 -0
  108. data/smoke/skip/test_expectations.yml +23 -0
  109. data/smoke/stdout/test_expectations.yml +1 -0
  110. data/smoke/super/test_expectations.yml +69 -0
  111. data/smoke/toplevel/test_expectations.yml +15 -0
  112. data/smoke/tsort/Steepfile +2 -0
  113. data/smoke/tsort/test_expectations.yml +63 -0
  114. data/smoke/type_case/test_expectations.yml +48 -0
  115. data/smoke/unexpected/Steepfile +5 -0
  116. data/smoke/unexpected/test_expectations.yml +25 -0
  117. data/smoke/unexpected/unexpected.rb +1 -0
  118. data/smoke/unexpected/unexpected.rbs +3 -0
  119. data/smoke/yield/test_expectations.yml +68 -0
  120. data/steep.gemspec +4 -3
  121. metadata +127 -80
  122. data/lib/steep/project/file_loader.rb +0 -68
  123. data/lib/steep/project/signature_file.rb +0 -39
  124. data/lib/steep/project/source_file.rb +0 -129
  125. data/lib/steep/project/stats_calculator.rb +0 -80
  126. data/lib/steep/server/code_worker.rb +0 -150
  127. data/lib/steep/server/signature_worker.rb +0 -157
  128. data/lib/steep/server/utils.rb +0 -69
  129. data/smoke/alias/test.yaml +0 -73
  130. data/smoke/and/test.yaml +0 -24
  131. data/smoke/array/test.yaml +0 -80
  132. data/smoke/block/test.yaml +0 -96
  133. data/smoke/broken/broken.rb +0 -0
  134. data/smoke/broken/broken.rbs +0 -0
  135. data/smoke/broken/test.yaml +0 -6
  136. data/smoke/case/test.yaml +0 -36
  137. data/smoke/class/test.yaml +0 -89
  138. data/smoke/const/test.yaml +0 -96
  139. data/smoke/diagnostics-rbs-duplicated/test.yaml +0 -10
  140. data/smoke/diagnostics-rbs/test.yaml +0 -142
  141. data/smoke/diagnostics/test.yaml +0 -333
  142. data/smoke/dstr/test.yaml +0 -10
  143. data/smoke/ensure/test.yaml +0 -47
  144. data/smoke/enumerator/test.yaml +0 -100
  145. data/smoke/extension/test.yaml +0 -50
  146. data/smoke/hash/test.yaml +0 -62
  147. data/smoke/hello/test.yaml +0 -18
  148. data/smoke/if/test.yaml +0 -27
  149. data/smoke/implements/test.yaml +0 -16
  150. data/smoke/initialize/test.yaml +0 -4
  151. data/smoke/integer/test.yaml +0 -66
  152. data/smoke/interface/test.yaml +0 -16
  153. data/smoke/kwbegin/test.yaml +0 -14
  154. data/smoke/lambda/test.yaml +0 -28
  155. data/smoke/literal/test.yaml +0 -79
  156. data/smoke/map/test.yaml +0 -4
  157. data/smoke/method/test.yaml +0 -71
  158. data/smoke/module/test.yaml +0 -51
  159. data/smoke/regexp/test.yaml +0 -372
  160. data/smoke/regression/test.yaml +0 -38
  161. data/smoke/rescue/test.yaml +0 -60
  162. data/smoke/self/test.yaml +0 -16
  163. data/smoke/skip/test.yaml +0 -16
  164. data/smoke/stdout/test.yaml +0 -4
  165. data/smoke/super/test.yaml +0 -52
  166. data/smoke/toplevel/test.yaml +0 -12
  167. data/smoke/tsort/test.yaml +0 -32
  168. data/smoke/type_case/test.yaml +0 -33
  169. data/smoke/yield/test.yaml +0 -49
@@ -0,0 +1,48 @@
1
+ module Steep
2
+ module Services
3
+ class FileLoader
4
+ attr_reader :base_dir
5
+
6
+ def initialize(base_dir:)
7
+ @base_dir = base_dir
8
+ end
9
+
10
+ def each_path_in_patterns(pattern, commandline_patterns = [])
11
+ pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
12
+
13
+ pats.each do |path|
14
+ absolute_path = base_dir + path
15
+
16
+ if absolute_path.file?
17
+ yield absolute_path.relative_path_from(base_dir)
18
+ else
19
+ files = if absolute_path.directory?
20
+ Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
21
+ else
22
+ Pathname.glob(absolute_path)
23
+ end
24
+
25
+ files.sort.each do |source_path|
26
+ if source_path.file?
27
+ relative_path = source_path.relative_path_from(base_dir)
28
+ unless pattern.ignore?(relative_path)
29
+ yield relative_path
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def load_changes(pattern, command_line_patterns = [], changes:)
38
+ each_path_in_patterns(pattern, command_line_patterns) do |path|
39
+ unless changes.key?(path)
40
+ changes[path] = [ContentChange.string((base_dir + path).read)]
41
+ end
42
+ end
43
+
44
+ changes
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,321 @@
1
+ module Steep
2
+ module Services
3
+ class GotoService
4
+ include ModuleHelper
5
+
6
+ module SourceHelper
7
+ def from_ruby?
8
+ from == :ruby
9
+ end
10
+
11
+ def from_rbs?
12
+ from == :rbs
13
+ end
14
+ end
15
+
16
+ ConstantQuery = Struct.new(:name, :from, keyword_init: true) do
17
+ include SourceHelper
18
+ end
19
+ MethodQuery = Struct.new(:name, :from, keyword_init: true) do
20
+ include SourceHelper
21
+ end
22
+ TypeNameQuery = Struct.new(:name, keyword_init: true)
23
+
24
+ attr_reader :type_check
25
+
26
+ def initialize(type_check:)
27
+ @type_check = type_check
28
+ end
29
+
30
+ def project
31
+ type_check.project
32
+ end
33
+
34
+ def implementation(path:, line:, column:)
35
+ locations = []
36
+
37
+ relative_path = project.relative_path(path)
38
+
39
+ queries = query_at(path: path, line: line, column: column)
40
+ queries.uniq!
41
+
42
+ queries.each do |query|
43
+ case query
44
+ when ConstantQuery
45
+ constant_definition_in_ruby(query.name, locations: locations)
46
+ when MethodQuery
47
+ method_locations(query.name, locations: locations, in_ruby: true, in_rbs: false)
48
+ when TypeNameQuery
49
+ type_name_locations(query.name, locations: locations)
50
+ end
51
+ end
52
+
53
+ locations.uniq
54
+ end
55
+
56
+ def definition(path:, line:, column:)
57
+ locations = []
58
+
59
+ relative_path = project.relative_path(path)
60
+
61
+ queries = query_at(path: path, line: line, column: column)
62
+ queries.uniq!
63
+
64
+ queries.each do |query|
65
+ case query
66
+ when ConstantQuery
67
+ constant_definition_in_rbs(query.name, locations: locations) if query.from_ruby?
68
+ constant_definition_in_ruby(query.name, locations: locations) if query.from_rbs?
69
+ when MethodQuery
70
+ method_locations(
71
+ query.name,
72
+ locations: locations,
73
+ in_ruby: query.from_rbs?,
74
+ in_rbs: query.from_ruby?
75
+ )
76
+ when TypeNameQuery
77
+ type_name_locations(query.name, locations: locations)
78
+ end
79
+ end
80
+
81
+ locations.uniq
82
+ end
83
+
84
+ def test_ast_location(loc, line:, column:)
85
+ return false if line < loc.line
86
+ return false if line == loc.line && column < loc.column
87
+ return false if loc.last_line < line
88
+ return false if line == loc.last_line && loc.last_column < column
89
+ true
90
+ end
91
+
92
+ def query_at(path:, line:, column:)
93
+ queries = []
94
+
95
+ relative_path = project.relative_path(path)
96
+
97
+ case
98
+ when target = type_check.source_file?(relative_path)
99
+ source = type_check.source_files[relative_path]
100
+ typing, signature = type_check_path(target: target, path: relative_path, content: source.content, line: line, column: column)
101
+ if typing
102
+ node, *parents = typing.source.find_nodes(line: line, column: column)
103
+ if node
104
+ case node.type
105
+ when :const, :casgn
106
+ if test_ast_location(node.location.name, line: line, column: column)
107
+ if module_context = typing.context_at(line: line, column: column).module_context
108
+ const_env = module_context.const_env
109
+ const = const_env.lookup_constant(module_name_from_node(node))
110
+ queries << ConstantQuery.new(name: const.name, from: :ruby)
111
+ end
112
+ end
113
+ when :def, :defs
114
+ if test_ast_location(node.location.name, line: line, column: column)
115
+ if method_context = typing.context_at(line: line, column: column).method_context
116
+ type_name = method_context.method.defined_in
117
+ name =
118
+ if method_context.method.defs.any? {|defn| defn.member.singleton? }
119
+ SingletonMethodName.new(type_name: type_name, method_name: method_context.name)
120
+ else
121
+ InstanceMethodName.new(type_name: type_name, method_name: method_context.name)
122
+ end
123
+ queries << MethodQuery.new(name: name, from: :ruby)
124
+ end
125
+ end
126
+ when :send
127
+ if test_ast_location(node.location.selector, line: line, column: column)
128
+ case call = typing.call_of(node: node)
129
+ when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
130
+ call.method_decls.each do |decl|
131
+ queries << MethodQuery.new(name: decl.method_name, from: :ruby)
132
+ end
133
+ when TypeInference::MethodCall::Untyped
134
+ # nop
135
+ when TypeInference::MethodCall::NoMethodError
136
+ # nop
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ when target_names = type_check.signature_file?(path)
143
+ target_names.each do |target_name|
144
+ signature_service = type_check.signature_services[target_name]
145
+ decls = signature_service.latest_env.declarations.select do |decl|
146
+ buffer_path = Pathname(decl.location.buffer.name)
147
+ buffer_path == relative_path || buffer_path == path
148
+ end
149
+
150
+ locator = RBS::Locator.new(decls: decls)
151
+ last, nodes = locator.find2(line: line, column: column)
152
+ case nodes[0]
153
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
154
+ if last == :name
155
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
156
+ end
157
+ when RBS::AST::Declarations::Constant
158
+ if last == :name
159
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
160
+ end
161
+ when RBS::AST::Members::MethodDefinition
162
+ if last == :name
163
+ type_name = nodes[1].name
164
+ method_name = nodes[0].name
165
+ if nodes[0].instance?
166
+ queries << MethodQuery.new(
167
+ name: InstanceMethodName.new(type_name: type_name, method_name: method_name),
168
+ from: :rbs
169
+ )
170
+ end
171
+ if nodes[0].singleton?
172
+ queries << MethodQuery.new(
173
+ name: SingletonMethodName.new(type_name: type_name, method_name: method_name),
174
+ from: :rbs
175
+ )
176
+ end
177
+ end
178
+ when RBS::AST::Members::Include, RBS::AST::Members::Extend, RBS::AST::Members::Prepend
179
+ if last == :name
180
+ queries << TypeNameQuery.new(name: nodes[0].name)
181
+ end
182
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Interface, RBS::Types::Alias
183
+ if last == :name
184
+ queries << TypeNameQuery.new(name: nodes[0].name)
185
+ end
186
+ when RBS::AST::Declarations::Class::Super, RBS::AST::Declarations::Module::Self
187
+ if last == :name
188
+ queries << TypeNameQuery.new(name: nodes[0].name)
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ queries
195
+ end
196
+
197
+ def type_check_path(target:, path:, content:, line:, column:)
198
+ signature_service = type_check.signature_services[target.name]
199
+ subtyping = signature_service.current_subtyping or return
200
+ source = Source.parse(content, path: path, factory: subtyping.factory)
201
+ source = source.without_unrelated_defs(line: line, column: column)
202
+ [
203
+ Services::TypeCheckService.type_check(source: source, subtyping: subtyping),
204
+ signature_service
205
+ ]
206
+ rescue
207
+ nil
208
+ end
209
+
210
+ def constant_definition_in_rbs(name, locations:)
211
+ type_check.signature_services.each_value do |signature|
212
+ env = signature.latest_env
213
+
214
+ if entry = env.class_decls[name]
215
+ entry.decls.each do |d|
216
+ locations << d.decl.location[:name]
217
+ end
218
+ end
219
+
220
+ if entry = env.constant_decls[name]
221
+ locations << entry.decl.location[:name]
222
+ end
223
+ end
224
+
225
+ locations
226
+ end
227
+
228
+ def constant_definition_in_ruby(name, locations:)
229
+ type_check.source_files.each do |path, source|
230
+ if typing = source.typing
231
+ entry = typing.source_index.entry(constant: name)
232
+ entry.definitions.each do |node|
233
+ case node.type
234
+ when :class, :module
235
+ locations << node.children[0].location.expression
236
+ when :casgn
237
+ parent = node.children[0]
238
+ location =
239
+ if parent
240
+ parent.location.expression.join(node.location.name)
241
+ else
242
+ node.location.name
243
+ end
244
+ locations << location
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ locations
251
+ end
252
+
253
+ def method_locations(name, in_ruby:, in_rbs:, locations:)
254
+ if in_ruby
255
+ type_check.source_files.each do |path, source|
256
+ if typing = source.typing
257
+ entry = typing.source_index.entry(method: name)
258
+
259
+ if entry.definitions.empty?
260
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
261
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
262
+ entry = typing.source_index.entry(method: initialize)
263
+ end
264
+ end
265
+
266
+ entry.definitions.each do |node|
267
+ case node.type
268
+ when :def
269
+ locations << node.location.name
270
+ when :defs
271
+ locations << node.location.name
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+ if in_rbs
279
+ type_check.signature_services.each_value do |signature|
280
+ index = signature.latest_rbs_index
281
+
282
+ entry = index.entry(method_name: name)
283
+
284
+ if entry.declarations.empty?
285
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
286
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
287
+ entry = index.entry(method_name: initialize)
288
+ end
289
+ end
290
+
291
+ entry.declarations.each do |decl|
292
+ case decl
293
+ when RBS::AST::Members::MethodDefinition
294
+ locations << decl.location[:name]
295
+ when RBS::AST::Members::Alias
296
+ locations << decl.location[:new_name]
297
+ when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
298
+ locations << decl.location[:name]
299
+ end
300
+ end
301
+ end
302
+ end
303
+
304
+ locations
305
+ end
306
+
307
+ def type_name_locations(name, locations: [])
308
+ type_check.signature_services.each_value do |signature|
309
+ index = signature.latest_rbs_index
310
+
311
+ entry = index.entry(type_name: name)
312
+ entry.declarations.each do |decl|
313
+ locations << decl.location[:name]
314
+ end
315
+ end
316
+
317
+ locations
318
+ end
319
+ end
320
+ end
321
+ end
@@ -1,5 +1,5 @@
1
1
  module Steep
2
- class Project
2
+ module Services
3
3
  class HoverContent
4
4
  TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
5
5
  VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
@@ -15,10 +15,14 @@ module Steep
15
15
  InstanceMethodName = Struct.new(:class_name, :method_name)
16
16
  SingletonMethodName = Struct.new(:class_name, :method_name)
17
17
 
18
- attr_reader :project
18
+ attr_reader :service
19
19
 
20
- def initialize(project:)
21
- @project = project
20
+ def initialize(service:)
21
+ @service = service
22
+ end
23
+
24
+ def project
25
+ service.project
22
26
  end
23
27
 
24
28
  def method_definition_for(factory, type_name, singleton_method: nil, instance_method: nil)
@@ -36,17 +40,11 @@ module Steep
36
40
  end
37
41
  end
38
42
 
39
- def typecheck(target, path:, line:, column:)
40
- target.type_check(target_sources: [], validate_signatures: false)
41
-
42
- case (status = target.status)
43
- when Project::Target::TypeCheckStatus
44
- subtyping = status.subtyping
45
- source = SourceFile
46
- .parse(target.source_files[path].content, path: path, factory: subtyping.factory)
47
- .without_unrelated_defs(line: line, column: column)
48
- SourceFile.type_check(source, subtyping: subtyping)
49
- end
43
+ def typecheck(target, path:, content:, line:, column:)
44
+ subtyping = service.signature_services[target.name].current_subtyping or return
45
+ source = Source.parse(content, path: path, factory: subtyping.factory)
46
+ source = source.without_unrelated_defs(line: line, column: column)
47
+ Services::TypeCheckService.type_check(source: source, subtyping: subtyping)
50
48
  rescue
51
49
  nil
52
50
  end
@@ -55,7 +53,8 @@ module Steep
55
53
  target = project.target_for_source_path(path)
56
54
 
57
55
  if target
58
- typing = typecheck(target, path: path, line: line, column: column) or return
56
+ file = service.source_files[path]
57
+ typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
59
58
 
60
59
  node, *parents = typing.source.find_nodes(line: line, column: column)
61
60
 
@@ -64,15 +63,15 @@ module Steep
64
63
  when :lvar
65
64
  var_name = node.children[0]
66
65
  context = typing.context_at(line: line, column: column)
67
- var_type = context.lvar_env[var_name.name] || AST::Types::Any.new(location: nil)
66
+ var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
68
67
 
69
- VariableContent.new(node: node, name: var_name.name, type: var_type, location: node.location.name)
68
+ VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
70
69
  when :lvasgn
71
70
  var_name, rhs = node.children
72
71
  context = typing.context_at(line: line, column: column)
73
- type = context.lvar_env[var_name.name] || typing.type_of(node: rhs)
72
+ type = context.lvar_env[var_name] || typing.type_of(node: rhs)
74
73
 
75
- VariableContent.new(node: node, name: var_name.name, type: type, location: node.location.name)
74
+ VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
76
75
  when :send
77
76
  receiver, method_name, *_ = node.children
78
77
 
@@ -0,0 +1,27 @@
1
+ module Steep
2
+ module Services
3
+ class PathAssignment
4
+ attr_reader :index, :max_index, :cache
5
+
6
+ def initialize(index:, max_index:)
7
+ @index = index
8
+ @max_index = max_index
9
+ @cache = {}
10
+ end
11
+
12
+ def self.all
13
+ new(index: 0, max_index: 1)
14
+ end
15
+
16
+ def =~(path)
17
+ (cache[path] ||= self.class.index_for(path: path.to_s, max_index: max_index)) == index
18
+ end
19
+
20
+ alias === =~
21
+
22
+ def self.index_for(path:, max_index:)
23
+ Digest::MD5.hexdigest(path).hex % max_index
24
+ end
25
+ end
26
+ end
27
+ end