steep 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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