steep 0.43.0 → 0.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +3 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +30 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep.rb +4 -1
  10. data/lib/steep/ast/builtin.rb +7 -1
  11. data/lib/steep/ast/types/factory.rb +19 -25
  12. data/lib/steep/diagnostic/ruby.rb +137 -60
  13. data/lib/steep/diagnostic/signature.rb +34 -0
  14. data/lib/steep/equatable.rb +21 -0
  15. data/lib/steep/index/source_index.rb +55 -5
  16. data/lib/steep/interface/block.rb +4 -0
  17. data/lib/steep/interface/function.rb +798 -579
  18. data/lib/steep/server/interaction_worker.rb +239 -20
  19. data/lib/steep/server/master.rb +40 -19
  20. data/lib/steep/server/type_check_worker.rb +68 -0
  21. data/lib/steep/services/file_loader.rb +26 -19
  22. data/lib/steep/services/goto_service.rb +322 -0
  23. data/lib/steep/services/hover_content.rb +131 -79
  24. data/lib/steep/services/type_check_service.rb +25 -0
  25. data/lib/steep/source.rb +7 -10
  26. data/lib/steep/type_construction.rb +496 -518
  27. data/lib/steep/type_inference/block_params.rb +2 -5
  28. data/lib/steep/type_inference/method_params.rb +483 -0
  29. data/lib/steep/type_inference/send_args.rb +610 -128
  30. data/lib/steep/typing.rb +46 -21
  31. data/lib/steep/version.rb +1 -1
  32. data/sig/steep/type_inference/send_args.rbs +42 -0
  33. data/smoke/array/test_expectations.yml +3 -3
  34. data/smoke/block/c.rb +0 -1
  35. data/smoke/class/test_expectations.yml +12 -15
  36. data/smoke/const/test_expectations.yml +0 -10
  37. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  38. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  39. data/smoke/diagnostics-ruby-unsat/Steepfile +5 -0
  40. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  41. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  42. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  43. data/smoke/diagnostics/a.rbs +0 -4
  44. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  45. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  46. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  47. data/smoke/diagnostics/test_expectations.yml +108 -57
  48. data/smoke/ensure/test_expectations.yml +3 -3
  49. data/smoke/enumerator/test_expectations.yml +1 -1
  50. data/smoke/literal/test_expectations.yml +2 -2
  51. data/smoke/method/test_expectations.yml +11 -10
  52. data/smoke/regression/issue_372.rb +8 -0
  53. data/smoke/regression/issue_372.rbs +4 -0
  54. data/smoke/regression/test_expectations.yml +0 -12
  55. data/smoke/rescue/test_expectations.yml +3 -3
  56. data/smoke/toplevel/test_expectations.yml +3 -3
  57. data/smoke/tsort/test_expectations.yml +2 -2
  58. data/steep.gemspec +2 -2
  59. metadata +24 -10
@@ -8,29 +8,36 @@ module Steep
8
8
  end
9
9
 
10
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
11
+ if block_given?
12
+ pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
13
+
14
+ pats.each do |path|
15
+ absolute_path = base_dir + path
16
+
17
+ if absolute_path.file?
18
+ if pattern =~ path
19
+ yield absolute_path.relative_path_from(base_dir)
20
+ end
21
+ else
22
+ files = if absolute_path.directory?
23
+ Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
24
+ else
25
+ Pathname.glob(absolute_path)
26
+ end
27
+
28
+ files.sort.each do |source_path|
29
+ if source_path.file?
30
+ relative_path = source_path.relative_path_from(base_dir)
31
+ unless pattern.ignore?(relative_path)
32
+ yield relative_path
33
+ end
30
34
  end
31
35
  end
32
36
  end
37
+
33
38
  end
39
+ else
40
+ enum_for :each_path_in_patterns, pattern, commandline_patterns
34
41
  end
35
42
  end
36
43
 
@@ -0,0 +1,322 @@
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
+ node = parents[0] if parents[0]&.type == :block
129
+ case call = typing.call_of(node: node)
130
+ when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
131
+ call.method_decls.each do |decl|
132
+ queries << MethodQuery.new(name: decl.method_name, from: :ruby)
133
+ end
134
+ when TypeInference::MethodCall::Untyped
135
+ # nop
136
+ when TypeInference::MethodCall::NoMethodError
137
+ # nop
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ when target_names = type_check.signature_file?(path)
144
+ target_names.each do |target_name|
145
+ signature_service = type_check.signature_services[target_name]
146
+ decls = signature_service.latest_env.declarations.select do |decl|
147
+ buffer_path = Pathname(decl.location.buffer.name)
148
+ buffer_path == relative_path || buffer_path == path
149
+ end
150
+
151
+ locator = RBS::Locator.new(decls: decls)
152
+ last, nodes = locator.find2(line: line, column: column)
153
+ case nodes[0]
154
+ when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
155
+ if last == :name
156
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
157
+ end
158
+ when RBS::AST::Declarations::Constant
159
+ if last == :name
160
+ queries << ConstantQuery.new(name: nodes[0].name, from: :rbs)
161
+ end
162
+ when RBS::AST::Members::MethodDefinition
163
+ if last == :name
164
+ type_name = nodes[1].name
165
+ method_name = nodes[0].name
166
+ if nodes[0].instance?
167
+ queries << MethodQuery.new(
168
+ name: InstanceMethodName.new(type_name: type_name, method_name: method_name),
169
+ from: :rbs
170
+ )
171
+ end
172
+ if nodes[0].singleton?
173
+ queries << MethodQuery.new(
174
+ name: SingletonMethodName.new(type_name: type_name, method_name: method_name),
175
+ from: :rbs
176
+ )
177
+ end
178
+ end
179
+ when RBS::AST::Members::Include, RBS::AST::Members::Extend, RBS::AST::Members::Prepend
180
+ if last == :name
181
+ queries << TypeNameQuery.new(name: nodes[0].name)
182
+ end
183
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton, RBS::Types::Interface, RBS::Types::Alias
184
+ if last == :name
185
+ queries << TypeNameQuery.new(name: nodes[0].name)
186
+ end
187
+ when RBS::AST::Declarations::Class::Super, RBS::AST::Declarations::Module::Self
188
+ if last == :name
189
+ queries << TypeNameQuery.new(name: nodes[0].name)
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ queries
196
+ end
197
+
198
+ def type_check_path(target:, path:, content:, line:, column:)
199
+ signature_service = type_check.signature_services[target.name]
200
+ subtyping = signature_service.current_subtyping or return
201
+ source = Source.parse(content, path: path, factory: subtyping.factory)
202
+ source = source.without_unrelated_defs(line: line, column: column)
203
+ [
204
+ Services::TypeCheckService.type_check(source: source, subtyping: subtyping),
205
+ signature_service
206
+ ]
207
+ rescue
208
+ nil
209
+ end
210
+
211
+ def constant_definition_in_rbs(name, locations:)
212
+ type_check.signature_services.each_value do |signature|
213
+ env = signature.latest_env
214
+
215
+ if entry = env.class_decls[name]
216
+ entry.decls.each do |d|
217
+ locations << d.decl.location[:name]
218
+ end
219
+ end
220
+
221
+ if entry = env.constant_decls[name]
222
+ locations << entry.decl.location[:name]
223
+ end
224
+ end
225
+
226
+ locations
227
+ end
228
+
229
+ def constant_definition_in_ruby(name, locations:)
230
+ type_check.source_files.each do |path, source|
231
+ if typing = source.typing
232
+ entry = typing.source_index.entry(constant: name)
233
+ entry.definitions.each do |node|
234
+ case node.type
235
+ when :class, :module
236
+ locations << node.children[0].location.expression
237
+ when :casgn
238
+ parent = node.children[0]
239
+ location =
240
+ if parent
241
+ parent.location.expression.join(node.location.name)
242
+ else
243
+ node.location.name
244
+ end
245
+ locations << location
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ locations
252
+ end
253
+
254
+ def method_locations(name, in_ruby:, in_rbs:, locations:)
255
+ if in_ruby
256
+ type_check.source_files.each do |path, source|
257
+ if typing = source.typing
258
+ entry = typing.source_index.entry(method: name)
259
+
260
+ if entry.definitions.empty?
261
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
262
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
263
+ entry = typing.source_index.entry(method: initialize)
264
+ end
265
+ end
266
+
267
+ entry.definitions.each do |node|
268
+ case node.type
269
+ when :def
270
+ locations << node.location.name
271
+ when :defs
272
+ locations << node.location.name
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
278
+
279
+ if in_rbs
280
+ type_check.signature_services.each_value do |signature|
281
+ index = signature.latest_rbs_index
282
+
283
+ entry = index.entry(method_name: name)
284
+
285
+ if entry.declarations.empty?
286
+ if name.is_a?(SingletonMethodName) && name.method_name == :new
287
+ initialize = InstanceMethodName.new(method_name: :initialize, type_name: name.type_name)
288
+ entry = index.entry(method_name: initialize)
289
+ end
290
+ end
291
+
292
+ entry.declarations.each do |decl|
293
+ case decl
294
+ when RBS::AST::Members::MethodDefinition
295
+ locations << decl.location[:name]
296
+ when RBS::AST::Members::Alias
297
+ locations << decl.location[:new_name]
298
+ when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
299
+ locations << decl.location[:name]
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ locations
306
+ end
307
+
308
+ def type_name_locations(name, locations: [])
309
+ type_check.signature_services.each_value do |signature|
310
+ index = signature.latest_rbs_index
311
+
312
+ entry = index.entry(type_name: name)
313
+ entry.declarations.each do |decl|
314
+ locations << decl.location[:name]
315
+ end
316
+ end
317
+
318
+ locations
319
+ end
320
+ end
321
+ end
322
+ end
@@ -5,6 +5,10 @@ module Steep
5
5
  VariableContent = Struct.new(:node, :name, :type, :location, keyword_init: true)
6
6
  MethodCallContent = Struct.new(:node, :method_name, :type, :definition, :location, keyword_init: true)
7
7
  DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
8
+ TypeAliasContent = Struct.new(:location, :decl, keyword_init: true)
9
+ ClassContent = Struct.new(:location, :decl, keyword_init: true)
10
+ InterfaceContent = Struct.new(:location, :decl, keyword_init: true)
11
+
8
12
  def comment_string
9
13
  if comments = definition&.comments
10
14
  comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
@@ -50,99 +54,147 @@ module Steep
50
54
  end
51
55
 
52
56
  def content_for(path:, line:, column:)
53
- target = project.target_for_source_path(path)
57
+ target_for_code, targets_for_sigs = project.targets_for_path(path)
58
+
59
+ case
60
+ when target = target_for_code
61
+ Steep.logger.info "target #{target}"
62
+
63
+ hover_for_source(column, line, path, target)
64
+
65
+ when target = targets_for_sigs[0]
66
+ service = self.service.signature_services[target.name]
67
+
68
+ _buffer, decls = service.latest_env.buffers_decls.find do |buffer, _|
69
+ Pathname(buffer.name) == path
70
+ end
71
+
72
+ return if decls.nil?
73
+
74
+ locator = RBS::Locator.new(decls: decls)
75
+ hd, tail = locator.find2(line: line, column: column)
76
+
77
+ case type = tail[0]
78
+ when RBS::Types::Alias
79
+ alias_decl = service.latest_env.alias_decls[type.name]&.decl or raise
80
+
81
+ location = tail[0].location
82
+ TypeAliasContent.new(
83
+ location: location,
84
+ decl: alias_decl
85
+ )
86
+ when RBS::Types::ClassInstance, RBS::Types::ClassSingleton
87
+ if hd == :name
88
+ env = service.latest_env
89
+ class_decl = env.class_decls[type.name]&.decls[0]&.decl or raise
90
+ location = tail[0].location[:name]
91
+ ClassContent.new(
92
+ location: location,
93
+ decl: class_decl
94
+ )
95
+ end
96
+ when RBS::Types::Interface
97
+ env = service.latest_env
98
+ interface_decl = env.interface_decls[type.name]&.decl or raise
99
+ location = type.location[:name]
100
+
101
+ InterfaceContent.new(
102
+ location: location,
103
+ decl: interface_decl
104
+ )
105
+ end
106
+ end
107
+ end
54
108
 
55
- if target
56
- file = service.source_files[path]
57
- typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
109
+ def hover_for_source(column, line, path, target)
110
+ file = service.source_files[path]
111
+ typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
112
+ node, *parents = typing.source.find_nodes(line: line, column: column)
58
113
 
59
- node, *parents = typing.source.find_nodes(line: line, column: column)
114
+ if node
115
+ case node.type
116
+ when :lvar
117
+ var_name = node.children[0]
118
+ context = typing.context_at(line: line, column: column)
119
+ var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
60
120
 
61
- if node
62
- case node.type
63
- when :lvar
64
- var_name = node.children[0]
65
- context = typing.context_at(line: line, column: column)
66
- var_type = context.lvar_env[var_name] || AST::Types::Any.new(location: nil)
121
+ VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
122
+ when :lvasgn
123
+ var_name, rhs = node.children
124
+ context = typing.context_at(line: line, column: column)
125
+ type = context.lvar_env[var_name] || typing.type_of(node: rhs)
67
126
 
68
- VariableContent.new(node: node, name: var_name, type: var_type, location: node.location.name)
69
- when :lvasgn
70
- var_name, rhs = node.children
71
- context = typing.context_at(line: line, column: column)
72
- type = context.lvar_env[var_name] || typing.type_of(node: rhs)
127
+ VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
128
+ when :send
129
+ receiver, method_name, *_ = node.children
73
130
 
74
- VariableContent.new(node: node, name: var_name, type: type, location: node.location.name)
75
- when :send
76
- receiver, method_name, *_ = node.children
77
131
 
132
+ result_node = if parents[0]&.type == :block
133
+ parents[0]
134
+ else
135
+ node
136
+ end
78
137
 
79
- result_node = if parents[0]&.type == :block
80
- parents[0]
138
+ context = typing.context_at(line: line, column: column)
139
+
140
+ receiver_type = if receiver
141
+ typing.type_of(node: receiver)
81
142
  else
82
- node
143
+ context.self_type
83
144
  end
84
145
 
85
- context = typing.context_at(line: line, column: column)
86
-
87
- receiver_type = if receiver
88
- typing.type_of(node: receiver)
89
- else
90
- context.self_type
91
- end
92
-
93
- factory = context.type_env.subtyping.factory
94
- method_name, definition = case receiver_type
95
- when AST::Types::Name::Instance
96
- method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
97
- if method_definition&.defined_in
98
- owner_name = method_definition.defined_in
99
- [
100
- InstanceMethodName.new(owner_name, method_name),
101
- method_definition
102
- ]
103
- end
104
- when AST::Types::Name::Singleton
105
- method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
106
- if method_definition&.defined_in
107
- owner_name = method_definition.defined_in
108
- [
109
- SingletonMethodName.new(owner_name, method_name),
110
- method_definition
111
- ]
112
- end
113
- else
114
- nil
146
+ factory = context.type_env.subtyping.factory
147
+ method_name, definition = case receiver_type
148
+ when AST::Types::Name::Instance
149
+ method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
150
+ if method_definition&.defined_in
151
+ owner_name = method_definition.defined_in
152
+ [
153
+ InstanceMethodName.new(owner_name, method_name),
154
+ method_definition
155
+ ]
115
156
  end
116
-
117
- MethodCallContent.new(
118
- node: node,
119
- method_name: method_name,
120
- type: typing.type_of(node: result_node),
121
- definition: definition,
122
- location: result_node.location.expression
123
- )
124
- when :def, :defs
125
- context = typing.context_at(line: line, column: column)
126
- method_context = context.method_context
127
-
128
- if method_context && method_context.method
129
- DefinitionContent.new(
130
- node: node,
131
- method_name: method_context.name,
132
- method_type: method_context.method_type,
133
- definition: method_context.method,
134
- location: node.loc.expression
135
- )
136
- end
137
- else
138
- type = typing.type_of(node: node)
139
-
140
- TypeContent.new(
157
+ when AST::Types::Name::Singleton
158
+ method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
159
+ if method_definition&.defined_in
160
+ owner_name = method_definition.defined_in
161
+ [
162
+ SingletonMethodName.new(owner_name, method_name),
163
+ method_definition
164
+ ]
165
+ end
166
+ else
167
+ nil
168
+ end
169
+
170
+ MethodCallContent.new(
171
+ node: node,
172
+ method_name: method_name,
173
+ type: typing.type_of(node: result_node),
174
+ definition: definition,
175
+ location: result_node.location.expression
176
+ )
177
+ when :def, :defs
178
+ context = typing.context_at(line: line, column: column)
179
+ method_context = context.method_context
180
+
181
+ if method_context && method_context.method
182
+ DefinitionContent.new(
141
183
  node: node,
142
- type: type,
143
- location: node.location.expression
184
+ method_name: method_context.name,
185
+ method_type: method_context.method_type,
186
+ definition: method_context.method,
187
+ location: node.loc.expression
144
188
  )
145
189
  end
190
+ else
191
+ type = typing.type_of(node: node)
192
+
193
+ TypeContent.new(
194
+ node: node,
195
+ type: type,
196
+ location: node.location.expression
197
+ )
146
198
  end
147
199
  end
148
200
  end