steep 0.46.0 → 0.48.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +0 -1
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +1 -2
  5. data/Gemfile.lock +18 -22
  6. data/README.md +2 -1
  7. data/lib/steep/annotation_parser.rb +1 -1
  8. data/lib/steep/ast/types/factory.rb +161 -137
  9. data/lib/steep/ast/types/var.rb +14 -3
  10. data/lib/steep/diagnostic/ruby.rb +23 -11
  11. data/lib/steep/diagnostic/signature.rb +60 -15
  12. data/lib/steep/interface/method_type.rb +14 -26
  13. data/lib/steep/interface/type_param.rb +103 -0
  14. data/lib/steep/project/dsl.rb +32 -5
  15. data/lib/steep/project/options.rb +1 -0
  16. data/lib/steep/project/target.rb +1 -0
  17. data/lib/steep/server/base_worker.rb +1 -0
  18. data/lib/steep/server/interaction_worker.rb +9 -9
  19. data/lib/steep/server/type_check_worker.rb +2 -2
  20. data/lib/steep/services/hover_content.rb +3 -0
  21. data/lib/steep/services/signature_service.rb +2 -2
  22. data/lib/steep/services/type_check_service.rb +2 -1
  23. data/lib/steep/signature/validator.rb +221 -49
  24. data/lib/steep/source.rb +5 -1
  25. data/lib/steep/subtyping/cache.rb +30 -0
  26. data/lib/steep/subtyping/check.rb +582 -708
  27. data/lib/steep/subtyping/constraints.rb +66 -30
  28. data/lib/steep/subtyping/relation.rb +60 -0
  29. data/lib/steep/subtyping/result.rb +190 -16
  30. data/lib/steep/type_construction.rb +493 -372
  31. data/lib/steep/type_inference/block_params.rb +1 -1
  32. data/lib/steep/type_inference/context.rb +37 -3
  33. data/lib/steep/type_inference/send_args.rb +1 -12
  34. data/lib/steep/version.rb +1 -1
  35. data/lib/steep.rb +5 -5
  36. data/sample/lib/length.rb +35 -0
  37. data/sample/sig/length.rbs +34 -0
  38. data/smoke/diagnostics/test_expectations.yml +4 -4
  39. data/smoke/diagnostics-rbs/nonregular-type-alias.rbs +3 -0
  40. data/smoke/diagnostics-rbs/recursive-type-alias.rbs +3 -0
  41. data/smoke/diagnostics-rbs/test_expectations.yml +57 -12
  42. data/smoke/extension/e.rbs +1 -1
  43. data/steep.gemspec +1 -1
  44. metadata +11 -10
  45. data/lib/steep/drivers/trace_printer.rb +0 -29
  46. data/lib/steep/interface/method.rb +0 -78
  47. data/lib/steep/subtyping/trace.rb +0 -71
  48. data/sig/project.rbi +0 -109
  49. data/sig/steep/type_inference/send_args.rbs +0 -42
@@ -26,20 +26,32 @@ module Steep
26
26
  end
27
27
 
28
28
  module ResultPrinter
29
- def print_result_to(io, level: 1)
30
- printer = Drivers::TracePrinter.new(io)
31
- printer.print result.trace, level: level
32
- end
33
-
34
- def trace_lines
35
- StringIO.new.tap do |io|
36
- print_result_to(io)
37
- end.string.chomp
29
+ def relation_message(relation)
30
+ case
31
+ when relation.type?
32
+ relation.to_s
33
+ when relation.method?
34
+ if relation.super_type.is_a?(Interface::MethodType) && relation.sub_type.is_a?(Interface::MethodType)
35
+ relation.to_s
36
+ end
37
+ when relation.interface?
38
+ nil
39
+ when relation.block?
40
+ nil
41
+ when relation.function?
42
+ nil
43
+ when relation.params?
44
+ nil
45
+ end
38
46
  end
39
47
 
40
48
  def detail_lines
41
49
  StringIO.new.tap do |io|
42
- print_result_to(io)
50
+ result.failure_path&.reverse_each.map do |result|
51
+ relation_message(result.relation)
52
+ end.compact.each.with_index(1) do |message, index|
53
+ io.puts "#{" " * (index)}#{message}"
54
+ end
43
55
  end.string.chomp
44
56
  end
45
57
  end
@@ -440,7 +452,7 @@ module Steep
440
452
  super(node: node)
441
453
  @interface_method = interface_method
442
454
  @annotation_method = annotation_method
443
- @result = result
455
+ @result = relation
444
456
  end
445
457
  end
446
458
 
@@ -38,25 +38,16 @@ module Steep
38
38
  end
39
39
 
40
40
  def self.parser_syntax_error_message(exception)
41
- value = if exception.error_value.is_a?(RBS::Parser::LocatedValue)
42
- exception.error_value.value
43
- else
44
- exception.error_value
45
- end
46
- string = value.to_s
41
+ string = exception.location.source.to_s
47
42
  unless string.empty?
48
43
  string = " (#{string})"
49
44
  end
50
45
 
51
- "Syntax error caused by token `#{exception.token_str}`#{string}"
46
+ "Syntax error caused by token `#{exception.token_type}`#{string}"
52
47
  end
53
48
 
54
49
  def header_line
55
- if exception.is_a?(RBS::Parser::SyntaxError)
56
- SyntaxError.parser_syntax_error_message(exception)
57
- else
58
- exception.message
59
- end
50
+ exception.message
60
51
  end
61
52
  end
62
53
 
@@ -110,6 +101,23 @@ module Steep
110
101
  end
111
102
  end
112
103
 
104
+ class UnsatisfiableTypeApplication < Base
105
+ attr_reader :type_name
106
+ attr_reader :type_arg
107
+ attr_reader :type_param
108
+
109
+ def initialize(type_name:, type_arg:, type_param:, location:)
110
+ super(location: location)
111
+ @type_name = type_name
112
+ @type_arg = type_arg
113
+ @type_param = type_param
114
+ end
115
+
116
+ def header_line
117
+ "Type application of `#{type_name}` doesn't satisfy the constraints: #{type_arg} <: #{type_param.upper_bound}"
118
+ end
119
+ end
120
+
113
121
  class InvalidMethodOverload < Base
114
122
  attr_reader :class_name
115
123
  attr_reader :method_name
@@ -316,12 +324,38 @@ module Steep
316
324
  end
317
325
  end
318
326
 
327
+ class RecursiveTypeAlias < Base
328
+ attr_reader :alias_names
329
+
330
+ def initialize(alias_names:, location:)
331
+ @alias_names = alias_names
332
+ super(location: location)
333
+ end
334
+
335
+ def header_line
336
+ "Type aliases cannot be *directly recursive*: #{alias_names.join(", ")}"
337
+ end
338
+ end
339
+
340
+ class NonregularTypeAlias < Base
341
+ attr_reader :type_name
342
+ attr_reader :nonregular_type
343
+
344
+ def initialize(type_name:, nonregular_type:, location:)
345
+ @type_name = type_name
346
+ @nonregular_type = nonregular_type
347
+ @location = location
348
+ end
349
+
350
+ def header_line
351
+ "Type alias #{type_name} is defined *non-regular*: #{nonregular_type}"
352
+ end
353
+ end
354
+
319
355
  def self.from_rbs_error(error, factory:)
320
356
  case error
321
- when RBS::Parser::SemanticsError, RBS::Parser::LexerError
357
+ when RBS::ParsingError
322
358
  Diagnostic::Signature::SyntaxError.new(error, location: error.location)
323
- when RBS::Parser::SyntaxError
324
- Diagnostic::Signature::SyntaxError.new(error, location: error.error_value.location)
325
359
  when RBS::DuplicatedDeclarationError
326
360
  Diagnostic::Signature::DuplicatedDeclaration.new(
327
361
  type_name: error.name,
@@ -399,6 +433,17 @@ module Steep
399
433
  type_name: error.type_name,
400
434
  member: error.member,
401
435
  )
436
+ when RBS::RecursiveTypeAliasError
437
+ Diagnostic::Signature::RecursiveTypeAlias.new(
438
+ alias_names: error.alias_names,
439
+ location: error.location
440
+ )
441
+ when RBS::NonregularTypeAliasError
442
+ Diagnostic::Signature::NonregularTypeAlias.new(
443
+ type_name: error.diagnostic.type_name,
444
+ nonregular_type: factory.type(error.diagnostic.nonregular_type),
445
+ location: error.location
446
+ )
402
447
  else
403
448
  raise error
404
449
  end
@@ -77,7 +77,7 @@ module Steep
77
77
  end
78
78
 
79
79
  def to_s
80
- type_params = !self.type_params.empty? ? "[#{self.type_params.map{|x| "#{x}" }.join(", ")}] " : ""
80
+ type_params = !self.type_params.empty? ? "[#{self.type_params.join(", ")}] " : ""
81
81
  params = type.params.to_s
82
82
  return_type = type.return_type
83
83
  block = self.block ? " #{self.block}" : ""
@@ -95,11 +95,9 @@ module Steep
95
95
  # Returns a new method type which can be used for the method implementation type of both `self` and `other`.
96
96
  #
97
97
  def unify_overload(other)
98
- type_params = []
99
- s1 = Substitution.build(self.type_params)
100
- type_params.push(*s1.dictionary.values.map(&:name))
101
- s2 = Substitution.build(other.type_params)
102
- type_params.push(*s2.dictionary.values.map(&:name))
98
+ type_params_1, s1 = TypeParam.rename(self.type_params)
99
+ type_params_2, s2 = TypeParam.rename(other.type_params)
100
+ type_params = type_params_1 + type_params_2
103
101
 
104
102
  block = case
105
103
  when self.block && other.block
@@ -134,17 +132,12 @@ module Steep
134
132
  # Returns nil if self and other are incompatible.
135
133
  #
136
134
  def |(other)
137
- self_type_params = Set.new(self.type_params)
138
- other_type_params = Set.new(other.type_params)
139
-
140
- unless (common_type_params = (self_type_params & other_type_params).to_a).empty?
141
- fresh_types = common_type_params.map {|name| AST::Types::Var.fresh(name) }
142
- fresh_names = fresh_types.map(&:name)
143
- subst = Substitution.build(common_type_params, fresh_types)
144
- other = other.instantiate(subst)
145
- type_params = (self_type_params + (other_type_params - common_type_params + Set.new(fresh_names))).to_a
135
+ if other.type_params.empty?
136
+ type_params = self.type_params
146
137
  else
147
- type_params = (self_type_params + other_type_params).to_a
138
+ other_params, s2 = TypeParam.rename(other.type_params)
139
+ other = other.instantiate(s2)
140
+ type_params = self.type_params + other_params
148
141
  end
149
142
 
150
143
  params = self.type.params & other.type.params or return
@@ -182,17 +175,12 @@ module Steep
182
175
  # Returns nil if self and other are incompatible.
183
176
  #
184
177
  def &(other)
185
- self_type_params = Set.new(self.type_params)
186
- other_type_params = Set.new(other.type_params)
187
-
188
- unless (common_type_params = (self_type_params & other_type_params).to_a).empty?
189
- fresh_types = common_type_params.map {|name| AST::Types::Var.fresh(name) }
190
- fresh_names = fresh_types.map(&:name)
191
- subst = Substitution.build(common_type_params, fresh_types)
192
- other = other.subst(subst)
193
- type_params = (self_type_params + (other_type_params - common_type_params + Set.new(fresh_names))).to_a
178
+ if other.type_params.empty?
179
+ type_params = self.type_params
194
180
  else
195
- type_params = (self_type_params + other_type_params).to_a
181
+ other_params, s2 = TypeParam.rename(other.type_params)
182
+ other = other.instantiate(s2)
183
+ type_params = self.type_params + other_params
196
184
  end
197
185
 
198
186
  params = self.type.params | other.type.params
@@ -0,0 +1,103 @@
1
+ module Steep
2
+ module Interface
3
+ class TypeParam
4
+ attr_reader :name
5
+ attr_reader :upper_bound
6
+ attr_reader :variance
7
+ attr_reader :unchecked
8
+ attr_reader :location
9
+
10
+ def initialize(name:, upper_bound:, variance:, unchecked:, location: nil)
11
+ @name = name
12
+ @upper_bound = upper_bound
13
+ @variance = variance
14
+ @unchecked = unchecked
15
+ @location = location
16
+ end
17
+
18
+ def ==(other)
19
+ other.is_a?(TypeParam) &&
20
+ other.name == name &&
21
+ other.upper_bound == upper_bound &&
22
+ other.variance == variance &&
23
+ other.unchecked == unchecked
24
+ end
25
+
26
+ alias eql? ==
27
+
28
+ def hash
29
+ name.hash ^ upper_bound.hash ^ variance.hash ^ unchecked.hash
30
+ end
31
+
32
+ def self.rename(params, conflicting_names = params.map(&:name))
33
+ unless conflicting_names.empty?
34
+ new_names = conflicting_names.map {|n| AST::Types::Var.fresh_name(n) }
35
+ hash = conflicting_names.zip(new_names).to_h
36
+ new_types = new_names.map {|n| AST::Types::Var.new(name: n) }
37
+
38
+ subst = Substitution.build(conflicting_names, new_types)
39
+
40
+ [
41
+ params.map do |param|
42
+ if hash.key?(param.name) || param.upper_bound
43
+ TypeParam.new(
44
+ name: hash[param.name] || param.name,
45
+ upper_bound: param.upper_bound&.subst(subst),
46
+ variance: param.variance,
47
+ unchecked: param.unchecked,
48
+ location: param.location
49
+ )
50
+ else
51
+ param
52
+ end
53
+ end,
54
+ subst
55
+ ]
56
+ else
57
+ [params, Substitution.empty]
58
+ end
59
+ end
60
+
61
+ def to_s
62
+ buf = ""
63
+
64
+ if unchecked
65
+ buf << "unchecked "
66
+ end
67
+
68
+ case variance
69
+ when :covariant
70
+ buf << "out "
71
+ when :contravariant
72
+ buf << "in "
73
+ end
74
+
75
+ buf << name.to_s
76
+
77
+ if upper_bound
78
+ buf << " < #{upper_bound}"
79
+ end
80
+
81
+ buf
82
+ end
83
+
84
+ def update(name: self.name, upper_bound: self.upper_bound, variance: self.variance, unchecked: self.unchecked, location: self.location)
85
+ TypeParam.new(
86
+ name: name,
87
+ upper_bound: upper_bound,
88
+ variance: variance,
89
+ unchecked: unchecked,
90
+ location: location
91
+ )
92
+ end
93
+
94
+ def subst(s)
95
+ if u = upper_bound
96
+ update(upper_bound: u.subst(s))
97
+ else
98
+ self
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -11,8 +11,12 @@ module Steep
11
11
  attr_reader :core_root
12
12
  attr_reader :repo_paths
13
13
  attr_reader :code_diagnostics_config
14
+ attr_reader :project
15
+ attr_reader :collection_config_path
14
16
 
15
- def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [], code_diagnostics_config: {})
17
+ NONE = Object.new.freeze
18
+
19
+ def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [], code_diagnostics_config: {}, project: nil, collection_config_path: NONE)
16
20
  @name = name
17
21
  @sources = sources
18
22
  @libraries = libraries
@@ -22,6 +26,15 @@ module Steep
22
26
  @stdlib_root = nil
23
27
  @repo_paths = []
24
28
  @code_diagnostics_config = code_diagnostics_config
29
+ @project = project
30
+ @collection_config_path =
31
+ case collection_config_path
32
+ when NONE
33
+ path = project&.absolute_path(RBS::Collection::Config::PATH)
34
+ path&.exist? ? path : nil
35
+ else
36
+ collection_config_path
37
+ end
25
38
  end
26
39
 
27
40
  def initialize_copy(other)
@@ -34,6 +47,8 @@ module Steep
34
47
  @core_root = other.core_root
35
48
  @stdlib_root = other.stdlib_root
36
49
  @code_diagnostics_config = other.code_diagnostics_config.dup
50
+ @project = other.project
51
+ @collection_config_path = other.collection_config_path
37
52
  end
38
53
 
39
54
  def check(*args)
@@ -100,13 +115,14 @@ module Steep
100
115
  signatures.push(*args)
101
116
  end
102
117
 
103
- def update(name: self.name, sources: self.sources, libraries: self.libraries, ignored_sources: self.ignored_sources, signatures: self.signatures)
118
+ def update(name: self.name, sources: self.sources, libraries: self.libraries, ignored_sources: self.ignored_sources, signatures: self.signatures, project: self.project)
104
119
  self.class.new(
105
120
  name,
106
121
  sources: sources,
107
122
  libraries: libraries,
108
123
  signatures: signatures,
109
- ignored_sources: ignored_sources
124
+ ignored_sources: ignored_sources,
125
+ project: project,
110
126
  )
111
127
  end
112
128
 
@@ -155,6 +171,14 @@ module Steep
155
171
 
156
172
  yield code_diagnostics_config if block_given?
157
173
  end
174
+
175
+ def collection_config(path)
176
+ @collection_config_path = project.absolute_path(path)
177
+ end
178
+
179
+ def disable_collection
180
+ @collection_config_path = nil
181
+ end
158
182
  end
159
183
 
160
184
  attr_reader :project
@@ -187,10 +211,10 @@ module Steep
187
211
 
188
212
  def target(name, template: nil, &block)
189
213
  target = if template
190
- self.class.templates[template]&.dup&.update(name: name) or
214
+ self.class.templates[template]&.dup&.update(name: name, project: project) or
191
215
  raise "Unknown template: #{template}, available templates: #{@@templates.keys.join(", ")}"
192
216
  else
193
- TargetDSL.new(name, code_diagnostics_config: Diagnostic::Ruby.default.dup)
217
+ TargetDSL.new(name, code_diagnostics_config: Diagnostic::Ruby.default.dup, project: project)
194
218
  end
195
219
 
196
220
  Steep.logger.tagged "target=#{name}" do
@@ -200,6 +224,8 @@ module Steep
200
224
  source_pattern = Pattern.new(patterns: target.sources, ignores: target.ignored_sources, ext: ".rb")
201
225
  signature_pattern = Pattern.new(patterns: target.signatures, ext: ".rbs")
202
226
 
227
+ collection_lock = target.collection_config_path&.then { |p| RBS::Collection::Config.lockfile_of(p) }
228
+
203
229
  Project::Target.new(
204
230
  name: target.name,
205
231
  source_pattern: source_pattern,
@@ -211,6 +237,7 @@ module Steep
211
237
  stdlib_root: target.stdlib_root,
212
238
  repo_paths: target.repo_paths
213
239
  )
240
+ options.collection_lock = collection_lock
214
241
  end,
215
242
  code_diagnostics_config: target.code_diagnostics_config
216
243
  ).tap do |target|
@@ -13,6 +13,7 @@ module Steep
13
13
 
14
14
  attr_reader :libraries
15
15
  attr_accessor :paths
16
+ attr_accessor :collection_lock
16
17
 
17
18
  def initialize
18
19
  @paths = PathOptions.new(repo_paths: [])
@@ -57,6 +57,7 @@ module Steep
57
57
  name, version = lib.split(/:/, 2)
58
58
  loader.add(library: name, version: version)
59
59
  end
60
+ loader.add_collection(options.collection_lock) if options.collection_lock
60
61
 
61
62
  loader
62
63
  end
@@ -14,6 +14,7 @@ module Steep
14
14
  @writer = writer
15
15
  @skip_job = false
16
16
  @shutdown = false
17
+ @skip_jobs_after_shutdown = nil
17
18
  end
18
19
 
19
20
  def skip_jobs_after_shutdown!(flag = true)
@@ -338,7 +338,7 @@ HOVER
338
338
  else
339
339
  ps = params.each.map do |param|
340
340
  s = ""
341
- if param.skip_validation
341
+ if param.unchecked?
342
342
  s << "unchecked "
343
343
  end
344
344
  case param.variance
@@ -383,7 +383,7 @@ HOVER
383
383
  when RBS::AST::Declarations::Interface
384
384
  "interface #{name_and_params(decl.name, decl.type_params)}"
385
385
  end
386
- end
386
+ end
387
387
 
388
388
  def format_completion_item(item)
389
389
  range = LanguageServer::Protocol::Interface::Range.new(
@@ -402,18 +402,18 @@ HOVER
402
402
  LanguageServer::Protocol::Interface::CompletionItem.new(
403
403
  label: item.identifier,
404
404
  kind: LanguageServer::Protocol::Constant::CompletionItemKind::VARIABLE,
405
- detail: "#{item.identifier}: #{item.type}",
405
+ detail: item.type.to_s,
406
406
  text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
407
407
  range: range,
408
- new_text: "#{item.identifier}"
408
+ new_text: item.identifier
409
409
  )
410
410
  )
411
411
  when Services::CompletionProvider::MethodNameItem
412
- label = "def #{item.identifier}: #{item.method_type}"
413
412
  method_type_snippet = method_type_to_snippet(item.method_type)
414
413
  LanguageServer::Protocol::Interface::CompletionItem.new(
415
- label: label,
414
+ label: item.identifier,
416
415
  kind: LanguageServer::Protocol::Constant::CompletionItemKind::METHOD,
416
+ detail: item.method_type.to_s,
417
417
  text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
418
418
  new_text: "#{item.identifier}#{method_type_snippet}",
419
419
  range: range
@@ -423,14 +423,14 @@ HOVER
423
423
  sort_text: item.inherited? ? 'z' : 'a' # Ensure language server puts non-inherited methods before inherited methods
424
424
  )
425
425
  when Services::CompletionProvider::InstanceVariableItem
426
- label = "#{item.identifier}: #{item.type}"
427
426
  LanguageServer::Protocol::Interface::CompletionItem.new(
428
- label: label,
427
+ label: item.identifier,
429
428
  kind: LanguageServer::Protocol::Constant::CompletionItemKind::FIELD,
429
+ detail: item.type.to_s,
430
430
  text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
431
431
  range: range,
432
432
  new_text: item.identifier,
433
- ),
433
+ ),
434
434
  insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET
435
435
  )
436
436
  end
@@ -144,7 +144,7 @@ module Steep
144
144
  if job.guid == current_type_check_guid
145
145
  Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }
146
146
  service.validate_signature(path: project.relative_path(job.path)) do |path, diagnostics|
147
- formatter = Diagnostic::LSPFormatter.new({})
147
+ formatter = Diagnostic::LSPFormatter.new({}, **{})
148
148
 
149
149
  writer.write(
150
150
  method: :"textDocument/publishDiagnostics",
@@ -162,7 +162,7 @@ module Steep
162
162
  if job.guid == current_type_check_guid
163
163
  Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }
164
164
  service.validate_signature(path: job.path) do |path, diagnostics|
165
- formatter = Diagnostic::LSPFormatter.new({})
165
+ formatter = Diagnostic::LSPFormatter.new({}, **{})
166
166
 
167
167
  writer.write(
168
168
  method: :"textDocument/publishDiagnostics",
@@ -74,6 +74,9 @@ module Steep
74
74
  locator = RBS::Locator.new(decls: decls)
75
75
  hd, tail = locator.find2(line: line, column: column)
76
76
 
77
+ # Maybe hover on comment
78
+ return if tail.nil?
79
+
77
80
  case type = tail[0]
78
81
  when RBS::Types::Alias
79
82
  alias_decl = service.latest_env.alias_decls[type.name]&.decl or raise
@@ -224,7 +224,7 @@ module Steep
224
224
  Steep.measure "Loading new decls" do
225
225
  updated_files.each_value do |content|
226
226
  case decls = content.decls
227
- when RBS::ErrorBase
227
+ when RBS::BaseError
228
228
  errors << content.decls
229
229
  else
230
230
  begin
@@ -283,7 +283,7 @@ module Steep
283
283
  def rescue_rbs_error(errors)
284
284
  begin
285
285
  yield
286
- rescue RBS::ErrorBase => exn
286
+ rescue RBS::BaseError => exn
287
287
  errors << exn
288
288
  end
289
289
  end
@@ -366,7 +366,8 @@ module Steep
366
366
  self_type: AST::Builtin::Object.instance_type,
367
367
  type_env: type_env,
368
368
  lvar_env: lvar_env,
369
- call_context: TypeInference::MethodCall::TopLevelContext.new
369
+ call_context: TypeInference::MethodCall::TopLevelContext.new,
370
+ variable_context: TypeInference::Context::TypeVariableContext.empty
370
371
  )
371
372
 
372
373
  typing = Typing.new(source: source, root_context: context)