solargraph 0.45.0 → 0.49.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/CHANGELOG.md +41 -0
  5. data/LICENSE +1 -1
  6. data/README.md +8 -0
  7. data/SPONSORS.md +2 -4
  8. data/lib/solargraph/api_map/store.rb +13 -1
  9. data/lib/solargraph/api_map.rb +55 -32
  10. data/lib/solargraph/cache.rb +51 -0
  11. data/lib/solargraph/complex_type/type_methods.rb +10 -6
  12. data/lib/solargraph/complex_type/unique_type.rb +57 -0
  13. data/lib/solargraph/complex_type.rb +35 -2
  14. data/lib/solargraph/convention/rakefile.rb +17 -0
  15. data/lib/solargraph/convention.rb +2 -0
  16. data/lib/solargraph/diagnostics/require_not_found.rb +16 -0
  17. data/lib/solargraph/diagnostics/rubocop.rb +17 -3
  18. data/lib/solargraph/diagnostics/rubocop_helpers.rb +3 -1
  19. data/lib/solargraph/language_server/host.rb +22 -18
  20. data/lib/solargraph/language_server/message/extended/download_core.rb +1 -5
  21. data/lib/solargraph/language_server/message/initialize.rb +2 -0
  22. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -1
  23. data/lib/solargraph/language_server/message/text_document/hover.rb +16 -4
  24. data/lib/solargraph/language_server/message/text_document/signature_help.rb +1 -6
  25. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +10 -3
  26. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
  27. data/lib/solargraph/library.rb +21 -20
  28. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +12 -2
  29. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +24 -3
  30. data/lib/solargraph/parser/rubyvm/class_methods.rb +7 -2
  31. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +13 -2
  32. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +20 -9
  33. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +14 -3
  34. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +2 -2
  35. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +14 -3
  36. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +4 -2
  37. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  38. data/lib/solargraph/pin/base.rb +5 -2
  39. data/lib/solargraph/pin/block.rb +2 -1
  40. data/lib/solargraph/pin/conversions.rb +2 -6
  41. data/lib/solargraph/pin/method.rb +100 -10
  42. data/lib/solargraph/pin/namespace.rb +4 -1
  43. data/lib/solargraph/pin/parameter.rb +10 -7
  44. data/lib/solargraph/pin/search.rb +56 -0
  45. data/lib/solargraph/pin/signature.rb +23 -0
  46. data/lib/solargraph/pin.rb +2 -0
  47. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  48. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  49. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  50. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  51. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  52. data/lib/solargraph/rbs_map.rb +73 -0
  53. data/lib/solargraph/shell.rb +38 -30
  54. data/lib/solargraph/source/chain/call.rb +34 -23
  55. data/lib/solargraph/source/chain.rb +21 -6
  56. data/lib/solargraph/source.rb +1 -1
  57. data/lib/solargraph/source_map/clip.rb +5 -0
  58. data/lib/solargraph/source_map/mapper.rb +31 -2
  59. data/lib/solargraph/source_map.rb +1 -10
  60. data/lib/solargraph/type_checker/checks.rb +13 -0
  61. data/lib/solargraph/type_checker.rb +88 -68
  62. data/lib/solargraph/version.rb +1 -1
  63. data/lib/solargraph/views/environment.erb +2 -2
  64. data/lib/solargraph/workspace.rb +12 -14
  65. data/lib/solargraph/yard_map/mapper/to_method.rb +7 -4
  66. data/lib/solargraph/yard_map.rb +51 -195
  67. data/lib/solargraph.rb +2 -2
  68. data/solargraph.gemspec +8 -6
  69. metadata +44 -36
  70. data/lib/solargraph/compat.rb +0 -37
  71. data/lib/solargraph/yard_map/core_docs.rb +0 -170
  72. data/lib/solargraph/yard_map/core_fills.rb +0 -208
  73. data/lib/solargraph/yard_map/core_gen.rb +0 -76
  74. data/lib/solargraph/yard_map/rdoc_to_yard.rb +0 -140
  75. data/lib/solargraph/yard_map/stdlib_fills.rb +0 -43
  76. data/yardoc/2.2.2.tar.gz +0 -0
@@ -71,43 +71,47 @@ module Solargraph
71
71
  STDOUT.puts "Configuration file initialized."
72
72
  end
73
73
 
74
- desc 'download-core [VERSION]', 'Download core documentation'
75
- def download_core version = nil
76
- ver = version || Solargraph::YardMap::CoreDocs.best_download
77
- if RUBY_VERSION != ver
78
- puts "Documentation for #{RUBY_VERSION} is not available. Reverting to closest match..."
79
- end
80
- puts "Downloading docs for #{ver}..."
81
- Solargraph::YardMap::CoreDocs.download ver
82
- # Clear cached documentation if it exists
83
- FileUtils.rm_rf Dir.glob(File.join(Solargraph::YardMap::CoreDocs.cache_dir, ver, '*.ser'))
84
- puts "Download complete."
85
- rescue ArgumentError => e
86
- STDERR.puts "ERROR: #{e.message}"
87
- STDERR.puts "Run `solargraph available-cores` for a list."
88
- exit 1
74
+ desc 'download-core [VERSION]', 'Download core documentation [deprecated]'
75
+ long_desc %(
76
+ The `download-core` command is deprecated. Current versions of Solargraph
77
+ use RBS for core and stdlib documentation.
78
+ )
79
+ # @deprecated
80
+ def download_core _version = nil
81
+ puts 'The `download-core` command is deprecated.'
82
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
89
83
  end
90
84
 
91
- desc 'list-cores', 'List the local documentation versions'
85
+ desc 'list-cores', 'List the local documentation versions [deprecated]'
86
+ long_desc %(
87
+ The `list-cores` command is deprecated. Current versions of Solargraph use
88
+ RBS for core and stdlib documentation.
89
+ )
90
+ # @deprecated
92
91
  def list_cores
93
- puts Solargraph::YardMap::CoreDocs.versions.join("\n")
92
+ puts 'The `list-cores` command is deprecated.'
93
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
94
94
  end
95
95
 
96
- desc 'available-cores', 'List available documentation versions'
96
+ desc 'available-cores', 'List available documentation versions [deprecated]'
97
+ long_desc %(
98
+ The `available-cores` command is deprecated. Current versions of Solargraph
99
+ use RBS for core and stdlib documentation.
100
+ )
101
+ # @deprecated
97
102
  def available_cores
98
- puts Solargraph::YardMap::CoreDocs.available.join("\n")
103
+ puts 'The `available-cores` command is deprecated.'
104
+ puts 'Current versions of Solargraph use RBS for core and stdlib documentation.'
99
105
  end
100
106
 
101
107
  desc 'clear', 'Delete all cached documentation'
102
108
  long_desc %(
103
109
  This command will delete all core and gem documentation from the cache.
104
- You can also delete specific gem caches with the `uncache` command or
105
- update documentation for specific Ruby versions with the `download-core`
106
- command.
107
110
  )
111
+ # @deprecated
108
112
  def clear
109
113
  puts "Deleting the cached documentation"
110
- Solargraph::YardMap::CoreDocs.clear
114
+ Solargraph::Cache.clear
111
115
  end
112
116
  map 'clear-cache' => :clear
113
117
  map 'clear-cores' => :clear
@@ -191,18 +195,22 @@ module Solargraph
191
195
  puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
192
196
  end
193
197
 
194
- desc 'bundle', 'Generate documentation for bundled gems'
198
+ desc 'bundle', 'Generate documentation for bundled gems [deprecated]'
199
+ long_desc %(
200
+ The `bundle` command is deprecated. Solargraph currently uses RBS instead.
201
+ )
195
202
  option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
196
203
  option :rebuild, type: :boolean, aliases: :r, desc: 'Rebuild existing documentation', default: false
197
204
  def bundle
198
- Documentor.new(options[:directory], rebuild: options[:rebuild], out: STDOUT).document
205
+ puts 'The `bundle` command is deprecated. Solargraph currently uses RBS instead.'
199
206
  end
200
207
 
201
- desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation'
202
- def rdoc gem, version = '>= 0'
203
- spec = Gem::Specification.find_by_name(gem, version)
204
- puts "Caching #{spec.name} #{spec.version} from RDoc"
205
- Solargraph::YardMap::RdocToYard.run(spec)
208
+ desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation [deprecated]'
209
+ long_desc %(
210
+ The `rdoc` command is deprecated. Solargraph currently uses RBS instead.
211
+ )
212
+ def rdoc _gem, _version = '>= 0'
213
+ puts 'The `rdoc` command is deprecated. Solargraph currently uses RBS instead.'
206
214
  end
207
215
 
208
216
  private
@@ -35,7 +35,10 @@ module Solargraph
35
35
  []
36
36
  end
37
37
  return inferred_pins(found, api_map, name_pin.context, locals) unless found.empty?
38
- pins = api_map.get_method_stack(name_pin.binder.namespace, word, scope: name_pin.binder.scope)
38
+ # @param [ComplexType::UniqueType]
39
+ pins = name_pin.binder.each_unique_type.flat_map do |context|
40
+ api_map.get_method_stack(context.namespace, word, scope: context.scope)
41
+ end
39
42
  return [] if pins.empty?
40
43
  inferred_pins(pins, api_map, name_pin.context, locals)
41
44
  end
@@ -49,36 +52,32 @@ module Solargraph
49
52
  # @return [Array<Pin::Base>]
50
53
  def inferred_pins pins, api_map, context, locals
51
54
  result = pins.map do |p|
52
- overloads = p.docstring.tags(:overload)
55
+ next p unless p.is_a?(Pin::Method)
56
+ overloads = p.signatures
53
57
  # next p if overloads.empty?
54
58
  type = ComplexType::UNDEFINED
55
- # @param [YARD::Tags::OverloadTag]
56
59
  overloads.each do |ol|
57
- next unless arguments_match(arguments, ol.parameters)
58
- next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
60
+ next unless arguments_match(arguments, ol)
61
+ # next if ol.parameters.last && ol.parameters.last.first.start_with?('&') && ol.parameters.last.last.nil? && !with_block?
59
62
  match = true
60
63
  arguments.each_with_index do |arg, idx|
61
- achain = arguments[idx]
62
- next if achain.nil?
63
64
  param = ol.parameters[idx]
64
65
  if param.nil?
65
- match = false unless ol.parameters.last && ol.parameters.last.first.start_with?('*')
66
+ match = false unless ol.parameters.any?(&:restarg?)
66
67
  break
67
68
  end
68
- par = ol.tags(:param).select { |pp| pp.name == param.first }.first
69
- next if par.nil? || par.types.nil? || par.types.empty?
70
- atype = achain.infer(api_map, Pin::ProxyType.anonymous(context), locals)
71
- other = ComplexType.try_parse(*par.types)
69
+ atype = arg.infer(api_map, Pin::ProxyType.anonymous(context), locals)
72
70
  # @todo Weak type comparison
73
- unless atype.tag == other.tag || api_map.super_and_sub?(other.tag, atype.tag)
71
+ # unless atype.tag == param.return_type.tag || api_map.super_and_sub?(param.return_type.tag, atype.tag)
72
+ unless param.return_type.undefined? || atype.name == param.return_type.name || api_map.super_and_sub?(param.return_type.name, atype.name)
74
73
  match = false
75
74
  break
76
75
  end
77
76
  end
78
77
  if match
79
- type = extra_return_type(ol, context)
78
+ type = extra_return_type(p.docstring, context)
80
79
  break if type
81
- type = ComplexType.try_parse(*ol.tag(:return).types).self_to(context.to_s).qualify(api_map, context.namespace) if ol.has_tag?(:return) && ol.tag(:return).types && !ol.tag(:return).types.empty? && (type.nil? || type.undefined?)
80
+ type = with_params(ol.return_type.self_to(context.to_s), context).qualify(api_map, context.namespace) if ol.return_type.defined?
82
81
  type ||= ComplexType::UNDEFINED
83
82
  end
84
83
  break if type.defined?
@@ -107,9 +106,13 @@ module Solargraph
107
106
  p
108
107
  end
109
108
  result.map do |pin|
110
- next pin if pin.return_type.undefined?
111
- selfy = pin.return_type.self_to(context.tag)
112
- selfy == pin.return_type ? pin : pin.proxy(selfy)
109
+ if pin.path == 'Class#new' && context.tag != 'Class'
110
+ pin.proxy(ComplexType.try_parse(context.namespace))
111
+ else
112
+ next pin if pin.return_type.undefined?
113
+ selfy = pin.return_type.self_to(context.tag)
114
+ selfy == pin.return_type ? pin : pin.proxy(selfy)
115
+ end
113
116
  end
114
117
  end
115
118
 
@@ -180,14 +183,15 @@ module Solargraph
180
183
  end
181
184
 
182
185
  # @param arguments [Array<Chain>]
183
- # @param parameters [Array<String>]
186
+ # @param signature [Pin::Signature]
184
187
  # @return [Boolean]
185
- def arguments_match arguments, parameters
188
+ def arguments_match arguments, signature
189
+ parameters = signature.parameters
186
190
  argcount = arguments.length
187
- # argcount -= 1 if !arguments.empty? && arguments.last.links.first.word.start_with?('&')
188
191
  parcount = parameters.length
189
- parcount -= 1 if !parameters.empty? && parameters.last.first.start_with?('&')
190
- return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.first.start_with?('*'))
192
+ parcount -= 1 if !parameters.empty? && parameters.last.block?
193
+ return false if signature.block? && !with_block?
194
+ return false if argcount < parcount && !(argcount == parcount - 1 && parameters.last.restarg?)
191
195
  true
192
196
  end
193
197
 
@@ -198,6 +202,13 @@ module Solargraph
198
202
  pins = api_map.get_method_stack(name_pin.namespace, name_pin.name, scope: name_pin.scope)
199
203
  pins.reject{|p| p.path == name_pin.path}
200
204
  end
205
+
206
+ # @param type [ComplexType]
207
+ # @param context [ComplexType]
208
+ def with_params type, context
209
+ return type unless type.to_s.include?('$')
210
+ ComplexType.try_parse(type.to_s.gsub('$', context.value_types.map(&:tag).join(', ')).gsub('<>', ''))
211
+ end
201
212
  end
202
213
  end
203
214
  end
@@ -63,11 +63,11 @@ module Solargraph
63
63
  working_pin = name_pin
64
64
  links[0..-2].each do |link|
65
65
  pins = link.resolve(api_map, working_pin, locals)
66
- type = infer_first_defined(pins, working_pin, api_map)
66
+ type = infer_first_defined(pins, working_pin, api_map, locals)
67
67
  return [] if type.undefined?
68
68
  working_pin = Pin::ProxyType.anonymous(type)
69
69
  end
70
- links.last.last_context = working_pin
70
+ links.last.last_context = name_pin
71
71
  links.last.resolve(api_map, working_pin, locals)
72
72
  end
73
73
 
@@ -76,8 +76,12 @@ module Solargraph
76
76
  # @param locals [Array<Pin::Base>]
77
77
  # @return [ComplexType]
78
78
  def infer api_map, name_pin, locals
79
+ from_here = base.infer(api_map, name_pin, locals) unless links.length == 1
80
+ if from_here
81
+ name_pin = name_pin.proxy(from_here)
82
+ end
79
83
  pins = define(api_map, name_pin, locals)
80
- type = infer_first_defined(pins, links.last.last_context, api_map)
84
+ type = infer_first_defined(pins, links.last.last_context, api_map, locals)
81
85
  maybe_nil(type)
82
86
  end
83
87
 
@@ -110,9 +114,10 @@ module Solargraph
110
114
  private
111
115
 
112
116
  # @param pins [Array<Pin::Base>]
117
+ # @param context [Pin::Base]
113
118
  # @param api_map [ApiMap]
114
119
  # @return [ComplexType]
115
- def infer_first_defined pins, context, api_map
120
+ def infer_first_defined pins, context, api_map, locals
116
121
  possibles = []
117
122
  pins.each do |pin|
118
123
  # Avoid infinite recursion
@@ -121,8 +126,18 @@ module Solargraph
121
126
  type = pin.typify(api_map)
122
127
  @@inference_stack.pop
123
128
  if type.defined?
124
- possibles.push type
125
- break if pin.is_a?(Pin::Method)
129
+ if type.parameterized?
130
+ type = type.resolve_parameters(pin.closure, context)
131
+ # idx = pin.closure.parameters.index(type.subtypes.first.name)
132
+ # next if idx.nil?
133
+ # param_type = context.return_type.all_params[idx]
134
+ # next unless param_type
135
+ # type = ComplexType.try_parse(param_type.to_s)
136
+ end
137
+ if type.defined?
138
+ possibles.push type
139
+ break if pin.is_a?(Pin::Method)
140
+ end
126
141
  end
127
142
  end
128
143
  if possibles.empty?
@@ -360,7 +360,7 @@ module Solargraph
360
360
  skip = nil
361
361
  comments.lines.each { |l|
362
362
  # Trim the comment and minimum leading whitespace
363
- p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
363
+ p = l.force_encoding('UTF-8').encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
364
364
  if p.strip.empty?
365
365
  next unless started
366
366
  ctxt.concat p
@@ -43,6 +43,11 @@ module Solargraph
43
43
  # @return [ComplexType]
44
44
  def infer
45
45
  result = cursor.chain.infer(api_map, block, locals)
46
+ if result.tag == 'Class'
47
+ # HACK: Exception to return Object from Class#new
48
+ dfn = cursor.chain.define(api_map, block, locals).first
49
+ return ComplexType.try_parse('Object') if dfn && dfn.path == 'Class#new'
50
+ end
46
51
  return result unless result.tag == 'self'
47
52
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).namespace)
48
53
  end
@@ -12,7 +12,7 @@ module Solargraph
12
12
 
13
13
  private_class_method :new
14
14
 
15
- MACRO_REGEXP = /(@\!method|@\!attribute|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
15
+ MACRO_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
16
16
 
17
17
  # Generate the data.
18
18
  #
@@ -24,6 +24,8 @@ module Solargraph
24
24
  @code = source.code
25
25
  @comments = source.comments
26
26
  @pins, @locals = Parser.map(source)
27
+ @pins.each { |p| p.source = :code }
28
+ @locals.each { |l| l.source = :code }
27
29
  process_comment_directives
28
30
  [@pins, @locals]
29
31
  # rescue Exception => e
@@ -56,8 +58,10 @@ module Solargraph
56
58
  @pins ||= []
57
59
  end
58
60
 
61
+ # @param position [Solargraph::Position]
62
+ # @return [Solargraph::Pin::Closure]
59
63
  def closure_at(position)
60
- @pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
64
+ pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
61
65
  end
62
66
 
63
67
  def process_comment source_position, comment_position, comment
@@ -147,6 +151,27 @@ module Solargraph
147
151
  pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
148
152
  end
149
153
  end
154
+ when 'visibility'
155
+ begin
156
+ kind = directive.tag.text&.to_sym
157
+ return unless [:private, :protected, :public].include?(kind)
158
+
159
+ name = directive.tag.name
160
+ closure = closure_at(source_position) || @pins.first
161
+ if closure.location.range.start.line < comment_position.line
162
+ closure = closure_at(comment_position)
163
+ end
164
+ if closure.is_a?(Pin::Method) && no_empty_lines?(comment_position.line, source_position.line)
165
+ # @todo Smelly instance variable access
166
+ closure.instance_variable_set(:@visibility, kind)
167
+ else
168
+ matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == namespace && pin.context.scope == namespace.is_a?(Pin::Singleton) ? :class : :instance }
169
+ matches.each do |pin|
170
+ # @todo Smelly instance variable access
171
+ pin.instance_variable_set(:@visibility, kind)
172
+ end
173
+ end
174
+ end
150
175
  when 'parse'
151
176
  begin
152
177
  ns = closure_at(source_position)
@@ -176,6 +201,10 @@ module Solargraph
176
201
  end
177
202
  end
178
203
 
204
+ def no_empty_lines?(line1, line2)
205
+ @code.lines[line1..line2].none? { |line| line.strip.empty? }
206
+ end
207
+
179
208
  def remove_inline_comment_hashes comment
180
209
  ctxt = ''
181
210
  num = nil
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'jaro_winkler'
4
3
  require 'yard'
5
4
  require 'yard-solargraph'
6
5
  require 'set'
@@ -76,8 +75,7 @@ module Solargraph
76
75
  # @param query [String]
77
76
  # @return [Array<Pin::Base>]
78
77
  def query_symbols query
79
- return document_symbols if query && query.empty?
80
- document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
78
+ Pin::Search.new(document_symbols, query).results
81
79
  end
82
80
 
83
81
  # @param position [Position]
@@ -178,12 +176,5 @@ module Solargraph
178
176
  # Assuming the root pin is always valid
179
177
  found || pins.first
180
178
  end
181
-
182
- # @param str1 [String]
183
- # @param str2 [String]
184
- # @return [Boolean]
185
- def fuzzy_string_match str1, str2
186
- JaroWinkler.distance(str1, str2) > 0.6
187
- end
188
179
  end
189
180
  end
@@ -61,6 +61,19 @@ module Solargraph
61
61
  false
62
62
  end
63
63
 
64
+ # @param api_map [ApiMap]
65
+ # @param inferred [ComplexType]
66
+ # @param expected [ComplexType]
67
+ # @return [Boolean]
68
+ def all_types_match? api_map, inferred, expected
69
+ return duck_types_match?(api_map, expected, inferred) if expected.duck_type?
70
+ inferred.each do |inf|
71
+ next if inf.duck_type?
72
+ return false unless expected.any? { |exp| exp == inf || either_way?(api_map, inf, exp) }
73
+ end
74
+ true
75
+ end
76
+
64
77
  # @param api_map [ApiMap]
65
78
  # @param expected [ComplexType]
66
79
  # @param inferred [ComplexType]