steep 0.16.3 → 0.20.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b1c04c7f20a2ed355b58570363447b3e8f2bd1710407de1e23c7b9fbe279cb8
4
- data.tar.gz: 62101db41144f3fd218ee8478ab377f3414ad1d8a7689ac73356aa28bf7f6842
3
+ metadata.gz: 566e77aa4db03cb06ae80569f4db9f5409e65199b1af4af9fc6f2598e911f694
4
+ data.tar.gz: 41f1d54c5196fdec7cc58751899aec208066d845eef717234bb37266313c7d8d
5
5
  SHA512:
6
- metadata.gz: d8ac130b1adb7755709f4b1590939b442d6d4b4aa5ea38a95423db539a1b52b0c4078abf1a543b92a84477d99846d5ab30060dc26c693f52785de0c205041a2d
7
- data.tar.gz: e7ccec14707e49d51b88429ab0922c4e6fbbc190bbafb0e107c30ea681b04415245e40708909fd28458a89a565a816fd88a6bfa1c14b76e24185a2ece153148c
6
+ metadata.gz: 46366ed11a6328a6a237c52042ef49eb12d5ce3db111fb55c5038109b62aa471ba6634c8c060575f6862658dcc0f388684a083f9a691becd6d90f076acb05908
7
+ data.tar.gz: 9cb15861e6de6b5209dd82745f1c7cf67c212e3e15cc9c1f92956b84089801f994c7c1cd79ff8972f37da229530e7354d237ce4a74ce844083daf656936286dc
@@ -14,6 +14,10 @@ jobs:
14
14
  container_tag:
15
15
  - 2.6.5-bionic
16
16
  - 2.7.0-bionic
17
+ task:
18
+ - test
19
+ - smoke
20
+ - build
17
21
  container:
18
22
  image: rubylang/ruby:${{ matrix.container_tag }}
19
23
  steps:
@@ -24,4 +28,4 @@ jobs:
24
28
  gem install bundler
25
29
  bundle install --jobs 4 --retry 3
26
30
  bin/setup
27
- bundle exec rake build test smoke
31
+ bundle exec rake ${{matrix.task}}
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.20.0 (2020-07-17)
6
+
7
+ * Support singleton class definitions ([#166](https://github.com/soutaro/steep/pull/166))
8
+
9
+ ## 0.19.0 (2020-07-12)
10
+
11
+ * Update RBS. ([#157](https://github.com/soutaro/steep/pull/157))
12
+ * No `initialize` in completion. ([#164](https://github.com/soutaro/steep/pull/164))
13
+ * Granular typing option setup. ([#163](https://github.com/soutaro/steep/pull/163))
14
+
15
+ ## 0.18.0 (2020-07-06)
16
+
17
+ * Sort result of `Pathname#glob` ([#154](https://github.com/soutaro/steep/pull/154))
18
+ * Sort methods in LanguageServer to return non-inherited methods first ([#159](https://github.com/soutaro/steep/pull/159))
19
+
20
+ ## 0.17.1 (2020-06-15)
21
+
22
+ * Allow RBS gem to be 0.4 ([#153](https://github.com/soutaro/steep/pull/153))
23
+
24
+ ## 0.17.0 (2020-06-13)
25
+
26
+ * Fix `steep watch` and `steep langserver` to correctly handle error message filterings based on options ([#152](https://github.com/soutaro/steep/pull/152))
27
+ * Fix typing of collections ([#151](https://github.com/soutaro/steep/pull/151))
28
+
5
29
  ## 0.16.3
6
30
 
7
31
  * Fix `steep watch` ([#147](https://github.com/soutaro/steep/pull/147))
@@ -12,6 +12,7 @@ require 'language_server-protocol'
12
12
  require "etc"
13
13
  require "open3"
14
14
  require "stringio"
15
+ require 'uri'
15
16
 
16
17
  require "rbs"
17
18
 
@@ -8,6 +8,10 @@ module Steep
8
8
  @definition_builder = builder
9
9
  end
10
10
 
11
+ def type_name_resolver
12
+ @type_name_resolver ||= RBS::TypeNameResolver.from_env(definition_builder.env)
13
+ end
14
+
11
15
  def type(type)
12
16
  case type
13
17
  when RBS::Types::Bases::Any
@@ -277,8 +281,7 @@ module Steep
277
281
 
278
282
  def unfold(type_name)
279
283
  type_name_1(type_name).yield_self do |type_name|
280
- decl = definition_builder.env.find_alias(type_name) or raise "Unknown type name: #{type_name}"
281
- type(definition_builder.env.absolute_type(decl.type, namespace: type_name.namespace))
284
+ type(definition_builder.expand_alias(type_name))
282
285
  end
283
286
  end
284
287
 
@@ -331,7 +334,7 @@ module Steep
331
334
  method.method_types.map do |type|
332
335
  method_type(type, self_type: self_type) {|ty| ty.subst(subst) }
333
336
  end,
334
- incompatible: method.attributes.include?(:incompatible)
337
+ incompatible: name == :initialize || name == :new
335
338
  )
336
339
  end
337
340
  end
@@ -339,8 +342,7 @@ module Steep
339
342
  when Name::Interface
340
343
  Interface::Interface.new(type: self_type, private: private).tap do |interface|
341
344
  type_name = type_name_1(type.name)
342
- decl = definition_builder.env.find_class(type_name) or raise "Unknown class: #{type_name}"
343
- definition = definition_builder.build_interface(type_name, decl)
345
+ definition = definition_builder.build_interface(type_name)
344
346
 
345
347
  subst = Interface::Substitution.build(
346
348
  definition.type_params,
@@ -363,7 +365,7 @@ module Steep
363
365
  definition = definition_builder.build_singleton(type_name_1(type.name))
364
366
 
365
367
  instance_type = Name::Instance.new(name: type.name,
366
- args: definition.declaration.type_params.each.map {Any.new(location: nil)},
368
+ args: definition.type_params.map {Any.new(location: nil)},
367
369
  location: nil)
368
370
  subst = Interface::Substitution.build(
369
371
  [],
@@ -543,12 +545,12 @@ module Steep
543
545
 
544
546
  def module_name?(type_name)
545
547
  name = type_name_1(type_name)
546
- env.class?(name) && env.find_class(name).is_a?(RBS::AST::Declarations::Module)
548
+ entry = env.class_decls[name] and entry.is_a?(RBS::Environment::ModuleEntry)
547
549
  end
548
550
 
549
551
  def class_name?(type_name)
550
552
  name = type_name_1(type_name)
551
- env.class?(name) && env.find_class(name).is_a?(RBS::AST::Declarations::Class)
553
+ entry = env.class_decls[name] and entry.is_a?(RBS::Environment::ClassEntry)
552
554
  end
553
555
 
554
556
  def env
@@ -556,13 +558,14 @@ module Steep
556
558
  end
557
559
 
558
560
  def absolute_type(type, namespace:)
559
- type(env.absolute_type(type_1(type),
560
- namespace: namespace_1(namespace)) {|type| type.name.absolute! })
561
+ absolute_type = type_1(type).map_type_name do |name|
562
+ absolute_type_name(name, namespace: namespace) || name.absolute!
563
+ end
564
+ type(absolute_type)
561
565
  end
562
566
 
563
567
  def absolute_type_name(type_name, namespace:)
564
- type(env.absolute_type_name(type_name_1(type_name),
565
- namespace: namespace_1(namespace)) {|name| name.absolute! })
568
+ type_name_resolver.resolve(type_name, context: namespace_1(namespace).ascend)
566
569
  end
567
570
  end
568
571
  end
@@ -53,18 +53,7 @@ module Steep
53
53
  status.type_check_sources.each do |source_file|
54
54
  case source_file.status
55
55
  when Project::SourceFile::TypeCheckStatus
56
- source_file.errors.reject do |error|
57
- case
58
- when error.is_a?(Errors::FallbackAny)
59
- target.options.allow_fallback_any
60
- when error.is_a?(Errors::MethodDefinitionMissing)
61
- target.options.allow_missing_definitions
62
- when error.is_a?(Errors::NoMethod)
63
- target.options.allow_unknown_method_calls
64
- when error.is_a?(Errors::UnknownConstantAssigned)
65
- target.options.allow_unknown_constant_assignment
66
- end
67
- end.each do |error|
56
+ source_file.errors.select {|error| target.options.error_to_report?(error) }.each do |error|
68
57
  error.print_to stdout
69
58
  end
70
59
  when Project::SourceFile::TypeCheckErrorStatus
@@ -10,7 +10,15 @@ module Steep
10
10
 
11
11
  InstanceVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
12
12
  LocalVariableItem = Struct.new(:identifier, :range, :type, keyword_init: true)
13
- MethodNameItem = Struct.new(:identifier, :range, :definition, :method_type, keyword_init: true)
13
+ MethodNameItem = Struct.new(:identifier, :range, :definition, :def_type, :inherited_method, keyword_init: true) do
14
+ def method_type
15
+ def_type.type
16
+ end
17
+
18
+ def comment
19
+ def_type.comment
20
+ end
21
+ end
14
22
 
15
23
  attr_reader :source_text
16
24
  attr_reader :path
@@ -231,20 +239,22 @@ module Steep
231
239
  subtyping.factory.definition_builder.build_singleton(type_name)
232
240
  when AST::Types::Name::Interface
233
241
  type_name = subtyping.factory.type_name_1(type.name)
234
- interface = subtyping.factory.env.find_class(type_name)
235
- subtyping.factory.definition_builder.build_interface(type_name, interface)
242
+ subtyping.factory.definition_builder.build_interface(type_name)
236
243
  end
237
244
 
238
245
  if definition
239
246
  definition.methods.each do |name, method|
247
+ next if disallowed_method?(name)
248
+
240
249
  if include_private || method.public?
241
250
  if name.to_s.start_with?(prefix)
242
251
  if word_name?(name.to_s)
243
- method.method_types.each do |method_type|
252
+ method.defs.each do |def_type|
244
253
  items << MethodNameItem.new(identifier: name,
245
254
  range: range,
246
255
  definition: method,
247
- method_type: method_type)
256
+ def_type: def_type,
257
+ inherited_method: inherited_method?(method, definition))
248
258
  end
249
259
  end
250
260
  end
@@ -293,6 +303,17 @@ module Steep
293
303
 
294
304
  index
295
305
  end
306
+
307
+ def inherited_method?(method, definition)
308
+ method.implemented_in != definition.type_name
309
+ end
310
+
311
+ def disallowed_method?(name)
312
+ # initialize isn't invoked by developers when creating
313
+ # instances of new classes, so don't show it as
314
+ # an LSP option
315
+ name == :initialize
316
+ end
296
317
  end
297
318
  end
298
319
  end
@@ -10,6 +10,7 @@ module Steep
10
10
  attr_reader :no_builtin
11
11
  attr_reader :vendor_dir
12
12
  attr_reader :strictness_level
13
+ attr_reader :typing_option_hash
13
14
 
14
15
  def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [])
15
16
  @name = name
@@ -19,6 +20,7 @@ module Steep
19
20
  @ignored_sources = ignored_sources
20
21
  @vendor_dir = nil
21
22
  @strictness_level = :default
23
+ @typing_option_hash = {}
22
24
  end
23
25
 
24
26
  def initialize_copy(other)
@@ -29,6 +31,7 @@ module Steep
29
31
  @ignored_sources = other.ignored_sources.dup
30
32
  @vendor_dir = other.vendor_dir
31
33
  @strictness_level = other.strictness_level
34
+ @typing_option_hash = other.typing_option_hash
32
35
  end
33
36
 
34
37
  def check(*args)
@@ -43,8 +46,9 @@ module Steep
43
46
  libraries.push(*args)
44
47
  end
45
48
 
46
- def typing_options(level)
49
+ def typing_options(level = @strictness_level, **hash)
47
50
  @strictness_level = level
51
+ @typing_option_hash = hash
48
52
  end
49
53
 
50
54
  def signature(*args)
@@ -128,6 +132,8 @@ module Steep
128
132
  options.apply_lenient_typing_options!
129
133
  end
130
134
 
135
+ options.merge!(target.typing_option_hash)
136
+
131
137
  case target.vendor_dir
132
138
  when Array
133
139
  options.vendored_stdlib_path = target.vendor_dir[0]
@@ -95,6 +95,13 @@ module Steep
95
95
  source: source,
96
96
  timestamp: Time.now
97
97
  )
98
+ rescue RBS::NoTypeFoundError,
99
+ RBS::NoMixinFoundError,
100
+ RBS::NoSuperclassFoundError,
101
+ RBS::DuplicatedMethodDefinitionError,
102
+ RBS::InvalidTypeApplicationError => exn
103
+ # Skip logging known signature errors (they are handled with load_signatures(validate: true))
104
+ @status = TypeCheckErrorStatus.new(error: exn)
98
105
  rescue => exn
99
106
  Steep.log_error(exn)
100
107
  @status = TypeCheckErrorStatus.new(error: exn)
@@ -20,7 +20,7 @@ module Steep
20
20
  Pathname.glob(absolute_path)
21
21
  end
22
22
 
23
- files.each do |source_path|
23
+ files.sort.each do |source_path|
24
24
  yield project.relative_path(source_path)
25
25
  end
26
26
  end
@@ -4,7 +4,13 @@ module Steep
4
4
  TypeContent = Struct.new(:node, :type, :location, keyword_init: true)
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
- DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true)
7
+ DefinitionContent = Struct.new(:node, :method_name, :method_type, :definition, :location, keyword_init: true) do
8
+ def comment_string
9
+ if comments = definition&.comments
10
+ comments.map {|c| c.string.chomp }.uniq.join("\n----\n")
11
+ end
12
+ end
13
+ end
8
14
 
9
15
  InstanceMethodName = Struct.new(:class_name, :method_name)
10
16
  SingletonMethodName = Struct.new(:class_name, :method_name)
@@ -80,7 +86,7 @@ module Steep
80
86
  when AST::Types::Name::Instance
81
87
  method_definition = method_definition_for(factory, receiver_type.name, instance_method: method_name)
82
88
  if method_definition&.defined_in
83
- owner_name = factory.type_name(method_definition.defined_in.name.absolute!)
89
+ owner_name = factory.type_name(method_definition.defined_in)
84
90
  [
85
91
  InstanceMethodName.new(owner_name, method_name),
86
92
  method_definition
@@ -89,7 +95,7 @@ module Steep
89
95
  when AST::Types::Name::Class
90
96
  method_definition = method_definition_for(factory, receiver_type.name, singleton_method: method_name)
91
97
  if method_definition&.defined_in
92
- owner_name = factory.type_name(method_definition.defined_in.name.absolute!)
98
+ owner_name = factory.type_name(method_definition.defined_in)
93
99
  [
94
100
  SingletonMethodName.new(owner_name, method_name),
95
101
  method_definition
@@ -37,6 +37,28 @@ module Steep
37
37
  self.allow_unknown_constant_assignment = true
38
38
  self.allow_unknown_method_calls = true
39
39
  end
40
+
41
+ def error_to_report?(error)
42
+ case
43
+ when error.is_a?(Errors::FallbackAny)
44
+ !allow_fallback_any
45
+ when error.is_a?(Errors::MethodDefinitionMissing)
46
+ !allow_missing_definitions
47
+ when error.is_a?(Errors::NoMethod)
48
+ !allow_unknown_method_calls
49
+ when error.is_a?(Errors::UnknownConstantAssigned)
50
+ !allow_unknown_constant_assignment
51
+ else
52
+ true
53
+ end
54
+ end
55
+
56
+ def merge!(hash)
57
+ self.allow_fallback_any = hash[:allow_fallback_any] if hash.key?(:allow_fallback_any)
58
+ self.allow_missing_definitions = hash[:allow_missing_definitions] if hash.key?(:allow_missing_definitions)
59
+ self.allow_unknown_constant_assignment = hash[:allow_unknown_constant_assignment] if hash.key?(:allow_unknown_constant_assignment)
60
+ self.allow_unknown_method_calls = hash[:allow_unknown_method_calls] if hash.key?(:allow_unknown_method_calls)
61
+ end
40
62
  end
41
63
  end
42
64
  end
@@ -15,6 +15,7 @@ module Steep
15
15
 
16
16
  SignatureSyntaxErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
17
17
  SignatureValidationErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
18
+ SignatureOtherErrorStatus = Struct.new(:timestamp, :error, keyword_init: true)
18
19
  TypeCheckStatus = Struct.new(:environment, :subtyping, :type_check_sources, :timestamp, keyword_init: true)
19
20
 
20
21
  def initialize(name:, options:, source_patterns:, ignore_patterns:, signature_patterns:)
@@ -95,7 +96,7 @@ module Steep
95
96
  end
96
97
 
97
98
  def environment
98
- @environment ||= RBS::Environment.new().tap do |env|
99
+ @environment ||= RBS::Environment.new().yield_self do |env|
99
100
  stdlib_root = options.vendored_stdlib_path || RBS::EnvironmentLoader::STDLIB_ROOT
100
101
  gem_vendor_path = options.vendored_gems_path
101
102
  loader = RBS::EnvironmentLoader.new(stdlib_root: stdlib_root, gem_vendor_path: gem_vendor_path)
@@ -103,6 +104,8 @@ module Steep
103
104
  loader.add(library: lib)
104
105
  end
105
106
  loader.load(env: env)
107
+
108
+ env.resolve_type_names
106
109
  end
107
110
  end
108
111
 
@@ -125,34 +128,40 @@ module Steep
125
128
  if status.is_a?(TypeCheckStatus) && updated_files.empty?
126
129
  yield status.environment, status.subtyping, status.timestamp
127
130
  else
128
- env = environment.dup
129
-
130
- signature_files.each_value do |file|
131
- if file.status.is_a?(SignatureFile::DeclarationsStatus)
132
- file.status.declarations.each do |decl|
133
- env << decl
131
+ begin
132
+ env = environment.dup
133
+
134
+ signature_files.each_value do |file|
135
+ if file.status.is_a?(SignatureFile::DeclarationsStatus)
136
+ file.status.declarations.each do |decl|
137
+ env << decl
138
+ end
134
139
  end
135
140
  end
136
- end
137
141
 
138
- definition_builder = RBS::DefinitionBuilder.new(env: env)
139
- factory = AST::Types::Factory.new(builder: definition_builder)
140
- check = Subtyping::Check.new(factory: factory)
142
+ env = env.resolve_type_names
141
143
 
142
- if validate
143
- validator = Signature::Validator.new(checker: check)
144
- validator.validate()
144
+ definition_builder = RBS::DefinitionBuilder.new(env: env)
145
+ factory = AST::Types::Factory.new(builder: definition_builder)
146
+ check = Subtyping::Check.new(factory: factory)
145
147
 
146
- if validator.no_error?
147
- yield env, check, Time.now
148
+ if validate
149
+ validator = Signature::Validator.new(checker: check)
150
+ validator.validate()
151
+
152
+ if validator.no_error?
153
+ yield env, check, Time.now
154
+ else
155
+ @status = SignatureValidationErrorStatus.new(
156
+ errors: validator.each_error.to_a,
157
+ timestamp: Time.now
158
+ )
159
+ end
148
160
  else
149
- @status = SignatureValidationErrorStatus.new(
150
- errors: validator.each_error.to_a,
151
- timestamp: Time.now
152
- )
161
+ yield env, check, Time.now
153
162
  end
154
- else
155
- yield env, check, Time.now
163
+ rescue => exn
164
+ @status = SignatureOtherErrorStatus.new(error: exn, timestamp: Time.now)
156
165
  end
157
166
  end
158
167
 
@@ -47,7 +47,7 @@ module Steep
47
47
 
48
48
  Steep.logger.info "Finished type checking: #{path}@#{target.name}"
49
49
 
50
- diagnostics = source_diagnostics(source)
50
+ diagnostics = source_diagnostics(source, target.options)
51
51
 
52
52
  writer.write(
53
53
  method: :"textDocument/publishDiagnostics",
@@ -58,7 +58,7 @@ module Steep
58
58
  )
59
59
  end
60
60
 
61
- def source_diagnostics(source)
61
+ def source_diagnostics(source, options)
62
62
  case status = source.status
63
63
  when Project::SourceFile::ParseErrorStatus
64
64
  []
@@ -80,7 +80,7 @@ module Steep
80
80
  )
81
81
  ]
82
82
  when Project::SourceFile::TypeCheckStatus
83
- status.typing.errors.map do |error|
83
+ status.typing.errors.select {|error| options.error_to_report?(error) }.map do |error|
84
84
  loc = error.location_to_str
85
85
 
86
86
  LSP::Interface::Diagnostic.new(
@@ -110,7 +110,7 @@ HOVER
110
110
  def #{content.method_name}: #{content.method_type}
111
111
  ```
112
112
  HOVER
113
- if (comment = content.definition.comment)
113
+ if (comment = content.comment_string)
114
114
  string << "\n----\n\n#{comment.string}\n"
115
115
  end
116
116
 
@@ -190,8 +190,9 @@ HOVER
190
190
  new_text: "#{item.identifier}#{method_type_snippet}",
191
191
  range: range
192
192
  ),
193
- documentation: item.definition.comment&.string,
194
- insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET
193
+ documentation: item.comment&.string,
194
+ insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET,
195
+ sort_text: item.inherited_method ? 'z' : 'a' # Ensure language server puts non-inherited methods before inherited methods
195
196
  )
196
197
  when Project::CompletionProvider::InstanceVariableItem
197
198
  label = "#{item.identifier}: #{item.type}"
@@ -114,6 +114,7 @@ module Steep
114
114
  end
115
115
  else
116
116
  Steep.logger.info "Unexpected target status: #{status.class}"
117
+ {}
117
118
  end
118
119
 
119
120
  diagnostics.each do |path, diags|
@@ -35,6 +35,14 @@ module Steep
35
35
  checker.factory.definition_builder
36
36
  end
37
37
 
38
+ def type_name_resolver
39
+ @type_name_resolver ||= RBS::TypeNameResolver.from_env(env)
40
+ end
41
+
42
+ def validator
43
+ @validator ||= RBS::Validator.new(env: env, resolver: type_name_resolver)
44
+ end
45
+
38
46
  def factory
39
47
  checker.factory
40
48
  end
@@ -47,57 +55,69 @@ module Steep
47
55
  validate_global
48
56
  end
49
57
 
50
- def validate_one_decl(name, decl)
51
- case decl
52
- when Declarations::Class
53
- rescue_validation_errors do
54
- Steep.logger.debug "#{Location.to_string decl.location}:\tValidating class definition `#{name}`..."
55
- builder.build_instance(decl.name.absolute!).each_type do |type|
56
- env.validate type, namespace: RBS::Namespace.root
58
+ def validate_type(type)
59
+ Steep.logger.debug "#{Location.to_string type.location}: Validating #{type}..."
60
+ validator.validate_type type, context: [RBS::Namespace.root]
61
+ end
62
+
63
+ def validate_one_class(name)
64
+ rescue_validation_errors do
65
+ Steep.logger.debug "Validating class definition `#{name}`..."
66
+ Steep.logger.tagged "#{name}" do
67
+ builder.build_instance(name).each_type do |type|
68
+ validate_type type
57
69
  end
58
- builder.build_singleton(decl.name.absolute!).each_type do |type|
59
- env.validate type, namespace: RBS::Namespace.root
70
+ builder.build_singleton(name).each_type do |type|
71
+ validate_type type
60
72
  end
61
73
  end
62
- when Declarations::Interface
63
- rescue_validation_errors do
64
- Steep.logger.debug "#{Location.to_string decl.location}:\tValidating interface `#{name}`..."
65
- builder.build_interface(decl.name.absolute!, decl).each_type do |type|
66
- env.validate type, namespace: RBS::Namespace.root
74
+ end
75
+ end
76
+
77
+ def validate_one_interface(name)
78
+ rescue_validation_errors do
79
+ Steep.logger.debug "Validating interface `#{name}`..."
80
+ Steep.logger.tagged "#{name}" do
81
+ builder.build_interface(name).each_type do |type|
82
+ validate_type type
67
83
  end
68
84
  end
69
85
  end
70
86
  end
71
87
 
72
88
  def validate_decl
73
- env.each_decl do |name, decl|
74
- validate_one_decl name, decl
89
+ env.class_decls.each_key do |name|
90
+ validate_one_class(name)
91
+ end
92
+
93
+ env.interface_decls.each_key do |name|
94
+ validate_one_interface(name)
75
95
  end
76
96
  end
77
97
 
78
98
  def validate_const
79
- env.each_constant do |name, decl|
99
+ env.constant_decls.each do |name, entry|
80
100
  rescue_validation_errors do
81
- Steep.logger.debug "#{Location.to_string decl.location}:\tValidating constant `#{name}`..."
82
- env.validate(decl.type, namespace: name.namespace)
101
+ Steep.logger.debug "Validating constant `#{name}`..."
102
+ validate_type entry.decl.type
83
103
  end
84
104
  end
85
105
  end
86
106
 
87
107
  def validate_global
88
- env.each_global do |name, decl|
108
+ env.global_decls.each do |name, entry|
89
109
  rescue_validation_errors do
90
- Steep.logger.debug "#{Location.to_string decl.location}:\tValidating global `#{name}`..."
91
- env.validate(decl.type, namespace: RBS::Namespace.root)
110
+ Steep.logger.debug "Validating global `#{name}`..."
111
+ validate_type entry.decl.type
92
112
  end
93
113
  end
94
114
  end
95
115
 
96
116
  def validate_alias
97
- env.each_alias do |name, decl|
117
+ env.alias_decls.each do |name, entry|
98
118
  rescue_validation_errors do
99
- Steep.logger.debug "#{Location.to_string decl.location}:\tValidating alias `#{name}`..."
100
- env.validate(decl.type, namespace: name.namespace)
119
+ Steep.logger.debug "Validating alias `#{name}`..."
120
+ validate_type(entry.decl.type)
101
121
  end
102
122
  end
103
123
  end
@@ -108,10 +128,10 @@ module Steep
108
128
  @errors << Errors::InvalidTypeApplicationError.new(
109
129
  name: factory.type_name(exn.type_name),
110
130
  args: exn.args.map {|ty| factory.type(ty) },
111
- params: exn.params.each.map(&:name),
131
+ params: exn.params,
112
132
  location: exn.location
113
133
  )
114
- rescue RBS::NoTypeFoundError => exn
134
+ rescue RBS::NoTypeFoundError, RBS::NoSuperclassFoundError, RBS::NoMixinFoundError => exn
115
135
  @errors << Errors::UnknownTypeNameError.new(
116
136
  name: factory.type_name(exn.type_name),
117
137
  location: exn.location
@@ -37,7 +37,6 @@ module Steep
37
37
  attr_reader :source
38
38
  attr_reader :annotations
39
39
  attr_reader :typing
40
- attr_reader :type_env
41
40
 
42
41
  attr_reader :context
43
42
 
@@ -169,7 +168,7 @@ module Steep
169
168
 
170
169
  super_method = if definition
171
170
  if (this_method = definition.methods[method_name])
172
- if module_context&.class_name == checker.factory.type_name(this_method.defined_in.name.absolute!)
171
+ if module_context&.class_name == checker.factory.type_name(this_method.defined_in)
173
172
  this_method.super_method
174
173
  else
175
174
  this_method
@@ -231,6 +230,39 @@ module Steep
231
230
  )
232
231
  end
233
232
 
233
+ def implement_module(module_name:, super_name: nil, annotations:)
234
+ if (annotation = annotations.implement_module_annotation)
235
+ absolute_name(annotation.name.name).yield_self do |absolute_name|
236
+ if checker.factory.class_name?(absolute_name) || checker.factory.module_name?(absolute_name)
237
+ AST::Annotation::Implements::Module.new(
238
+ name: absolute_name,
239
+ args: annotation.name.args
240
+ )
241
+ else
242
+ Steep.logger.error "Unknown class name given to @implements: #{annotation.name.name}"
243
+ nil
244
+ end
245
+ end
246
+ else
247
+ name = nil
248
+ name ||= absolute_name(module_name).yield_self do |absolute_name|
249
+ absolute_name if checker.factory.class_name?(absolute_name) || checker.factory.module_name?(absolute_name)
250
+ end
251
+ name ||= super_name && absolute_name(super_name).yield_self do |absolute_name|
252
+ absolute_name if checker.factory.class_name?(absolute_name) || checker.factory.module_name?(absolute_name)
253
+ end
254
+
255
+ if name
256
+ absolute_name_ = checker.factory.type_name_1(name)
257
+ entry = checker.factory.env.class_decls[absolute_name_]
258
+ AST::Annotation::Implements::Module.new(
259
+ name: name,
260
+ args: entry.type_params.each.map(&:name)
261
+ )
262
+ end
263
+ end
264
+ end
265
+
234
266
  def for_module(node)
235
267
  new_module_name = Names::Module.from_node(node.children.first) or raise "Unexpected module name: #{node.children.first}"
236
268
  new_namespace = nested_namespace_for_module(new_module_name)
@@ -241,35 +273,14 @@ module Steep
241
273
  annots = source.annotations(block: node, factory: checker.factory, current_module: new_namespace)
242
274
  module_type = AST::Builtin::Module.instance_type
243
275
 
244
- implement_module_name = yield_self do
245
- if (annotation = annots.implement_module_annotation)
246
- absolute_name(annotation.name.name).yield_self do |absolute_name|
247
- if checker.factory.module_name?(absolute_name)
248
- AST::Annotation::Implements::Module.new(name: absolute_name,
249
- args: annotation.name.args)
250
- else
251
- Steep.logger.error "Unknown module name given to @implements: #{annotation.name.name}"
252
- nil
253
- end
254
- end
255
- else
256
- absolute_name(new_module_name).yield_self do |absolute_name|
257
- if checker.factory.module_name?(absolute_name)
258
- absolute_name_ = checker.factory.type_name_1(absolute_name)
259
- decl = checker.factory.env.find_class(absolute_name_)
260
- AST::Annotation::Implements::Module.new(name: absolute_name,
261
- args: decl.type_params.each.map(&:name))
262
- end
263
- end
264
- end
265
- end
276
+ implement_module_name = implement_module(module_name: new_module_name, annotations: annots)
266
277
 
267
278
  if implement_module_name
268
279
  module_name = implement_module_name.name
269
280
  module_args = implement_module_name.args.map {|x| AST::Types::Var.new(name: x)}
270
281
 
271
282
  type_name_ = checker.factory.type_name_1(implement_module_name.name)
272
- module_decl = checker.factory.definition_builder.env.find_class(type_name_)
283
+ module_entry = checker.factory.definition_builder.env.class_decls[type_name_]
273
284
  instance_def = checker.factory.definition_builder.build_instance(type_name_)
274
285
  module_def = checker.factory.definition_builder.build_singleton(type_name_)
275
286
 
@@ -277,9 +288,22 @@ module Steep
277
288
  types: [
278
289
  AST::Types::Name::Instance.new(name: module_name, args: module_args),
279
290
  AST::Builtin::Object.instance_type,
280
- module_decl.self_type&.yield_self {|ty|
281
- absolute_type = checker.factory.env.absolute_type(ty, namespace: module_decl.name.absolute!.namespace)
282
- checker.factory.type(absolute_type)
291
+ *module_entry.self_types.map {|module_self|
292
+ type = case
293
+ when module_self.name.interface?
294
+ RBS::Types::Interface.new(
295
+ name: module_self.name,
296
+ args: module_self.args,
297
+ location: module_self.location
298
+ )
299
+ when module_self.name.class?
300
+ RBS::Types::ClassInstance.new(
301
+ name: module_self.name,
302
+ args: module_self.args,
303
+ location: module_self.location
304
+ )
305
+ end
306
+ checker.factory.type(type)
283
307
  }
284
308
  ].compact
285
309
  )
@@ -340,34 +364,7 @@ module Steep
340
364
 
341
365
  annots = source.annotations(block: node, factory: checker.factory, current_module: new_namespace)
342
366
 
343
- implement_module_name = yield_self do
344
- if (annotation = annots.implement_module_annotation)
345
- absolute_name(annotation.name.name).yield_self do |absolute_name|
346
- if checker.factory.class_name?(absolute_name)
347
- AST::Annotation::Implements::Module.new(name: absolute_name,
348
- args: annotation.name.args)
349
- else
350
- Steep.logger.error "Unknown class name given to @implements: #{annotation.name.name}"
351
- nil
352
- end
353
- end
354
- else
355
- name = nil
356
- name ||= absolute_name(new_class_name).yield_self do |absolute_name|
357
- absolute_name if checker.factory.class_name?(absolute_name)
358
- end
359
- name ||= super_class_name && absolute_name(super_class_name).yield_self do |absolute_name|
360
- absolute_name if checker.factory.class_name?(absolute_name)
361
- end
362
-
363
- if name
364
- absolute_name_ = checker.factory.type_name_1(name)
365
- decl = checker.factory.env.find_class(absolute_name_)
366
- AST::Annotation::Implements::Module.new(name: name,
367
- args: decl.type_params.each.map(&:name))
368
- end
369
- end
370
- end
367
+ implement_module_name = implement_module(module_name: new_class_name, super_name: super_class_name, annotations: annots)
371
368
 
372
369
  if annots.implement_module_annotation
373
370
  new_class_name = implement_module_name.name
@@ -436,6 +433,83 @@ module Steep
436
433
  )
437
434
  end
438
435
 
436
+ def for_sclass(node, type)
437
+ annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
438
+
439
+ instance_type = if type.is_a?(AST::Types::Self)
440
+ context.self_type
441
+ else
442
+ type
443
+ end
444
+
445
+ module_type = case instance_type
446
+ when AST::Types::Name::Class
447
+ AST::Builtin::Class.instance_type
448
+ when AST::Types::Name::Module
449
+ AST::Builtin::Module.instance_type
450
+ when AST::Types::Name::Instance
451
+ instance_type.to_class(constructor: nil)
452
+ else
453
+ raise "Unexpected type for sclass node: #{type}"
454
+ end
455
+
456
+ instance_definition = case instance_type
457
+ when AST::Types::Name::Class, AST::Types::Name::Module
458
+ type_name = checker.factory.type_name_1(instance_type.name)
459
+ checker.factory.definition_builder.build_singleton(type_name)
460
+ when AST::Types::Name::Instance
461
+ type_name = checker.factory.type_name_1(instance_type.name)
462
+ checker.factory.definition_builder.build_instance(type_name)
463
+ end
464
+
465
+ module_definition = case module_type
466
+ when AST::Types::Name::Class, AST::Types::Name::Module
467
+ type_name = checker.factory.type_name_1(instance_type.name)
468
+ checker.factory.definition_builder.build_singleton(type_name)
469
+ else
470
+ nil
471
+ end
472
+
473
+ module_context = TypeInference::Context::ModuleContext.new(
474
+ instance_type: annots.instance_type || instance_type,
475
+ module_type: annots.self_type || annots.module_type || module_type,
476
+ implement_name: nil,
477
+ current_namespace: current_namespace,
478
+ const_env: self.module_context.const_env,
479
+ class_name: self.module_context.class_name,
480
+ module_definition: module_definition,
481
+ instance_definition: instance_definition
482
+ )
483
+
484
+ type_env = TypeInference::TypeEnv.build(annotations: annots,
485
+ subtyping: checker,
486
+ const_env: self.module_context.const_env,
487
+ signatures: checker.factory.env)
488
+
489
+ lvar_env = TypeInference::LocalVariableTypeEnv.empty(
490
+ subtyping: checker,
491
+ self_type: module_context.module_type
492
+ ).annotate(annots)
493
+
494
+ body_context = TypeInference::Context.new(
495
+ method_context: nil,
496
+ block_context: nil,
497
+ module_context: module_context,
498
+ break_context: nil,
499
+ self_type: module_context.module_type,
500
+ type_env: type_env,
501
+ lvar_env: lvar_env
502
+ )
503
+
504
+ self.class.new(
505
+ checker: checker,
506
+ source: source,
507
+ annotations: annots,
508
+ typing: typing,
509
+ context: body_context
510
+ )
511
+ end
512
+
439
513
  def for_branch(node, truthy_vars: Set.new, type_case_override: nil, break_context: context.break_context)
440
514
  annots = source.annotations(block: node, factory: checker.factory, current_module: current_namespace)
441
515
 
@@ -565,6 +639,7 @@ module Steep
565
639
  add_typing(node, type: AST::Builtin.any_type)
566
640
  else
567
641
  rhs_result = synthesize(rhs, hint: hint || context.lvar_env.declared_types[name]&.type)
642
+
568
643
  constr = rhs_result.constr.update_lvar_env do |lvar_env|
569
644
  lvar_env.assign(name, node: node, type: rhs_result.type) do |declared_type, actual_type, result|
570
645
  typing.add_error(Errors::IncompatibleAssignment.new(node: node,
@@ -1037,10 +1112,10 @@ module Steep
1037
1112
  case child.type
1038
1113
  when :pair
1039
1114
  key, value = child.children
1040
- key_types << synthesize(key).type.yield_self do |type|
1115
+ key_types << synthesize(key, hint: key_hint).type.yield_self do |type|
1041
1116
  select_super_type(type, key_hint)
1042
1117
  end
1043
- value_types << synthesize(value).type.yield_self do |type|
1118
+ value_types << synthesize(value, hint: value_hint).type.yield_self do |type|
1044
1119
  select_super_type(type, value_hint)
1045
1120
  end
1046
1121
  when :kwsplat
@@ -1115,6 +1190,25 @@ module Steep
1115
1190
  add_typing(node, type: AST::Builtin.nil_type)
1116
1191
  end
1117
1192
 
1193
+ when :sclass
1194
+ yield_self do
1195
+ type, constr = synthesize(node.children[0])
1196
+ constructor = constr.for_sclass(node, type)
1197
+
1198
+ constructor.typing.add_context_for_node(node, context: constructor.context)
1199
+ constructor.typing.add_context_for_body(node, context: constructor.context)
1200
+
1201
+ constructor.synthesize(node.children[1]) if node.children[1]
1202
+
1203
+ if constructor.module_context.instance_definition && module_context.module_definition
1204
+ if constructor.module_context.instance_definition.type_name == module_context.module_definition.type_name
1205
+ module_context.defined_module_methods.merge(constructor.module_context.defined_instance_methods)
1206
+ end
1207
+ end
1208
+
1209
+ add_typing(node, type: AST::Builtin.nil_type)
1210
+ end
1211
+
1118
1212
  when :self
1119
1213
  add_typing node, type: AST::Types::Self.new
1120
1214
 
@@ -1256,7 +1350,7 @@ module Steep
1256
1350
  end
1257
1351
  end
1258
1352
  else
1259
- [select_super_type(synthesize(e).type, element_hint)]
1353
+ [select_super_type(synthesize(e, hint: element_hint).type, element_hint)]
1260
1354
  end
1261
1355
  end
1262
1356
  array_type = AST::Builtin::Array.instance_type(AST::Types::Union.build(types: element_types))
@@ -1992,9 +2086,11 @@ module Steep
1992
2086
  end
1993
2087
  end
1994
2088
  rescue => exn
1995
- $stderr.puts exn.inspect
1996
- exn.backtrace.each do |t|
1997
- $stderr.puts t
2089
+ case exn
2090
+ when RBS::NoTypeFoundError, RBS::NoMixinFoundError, RBS::NoSuperclassFoundError, RBS::InvalidTypeApplicationError
2091
+ # ignore known RBS errors.
2092
+ else
2093
+ Steep.log_error(exn, message: "Unexpected error in #type_send: #{exn.message} (#{exn.class})")
1998
2094
  end
1999
2095
 
2000
2096
  fallback_to_any node do
@@ -2750,13 +2846,18 @@ module Steep
2750
2846
  end
2751
2847
 
2752
2848
  def validate_method_definitions(node, module_name)
2849
+ module_name_1 = checker.factory.type_name_1(module_name.name)
2850
+ member_decl_count = checker.factory.env.class_decls[module_name_1].decls.count {|d| d.decl.each_member.count > 0 }
2851
+
2852
+ return unless member_decl_count == 1
2853
+
2753
2854
  expected_instance_method_names = (module_context.instance_definition&.methods || {}).each.with_object(Set[]) do |(name, method), set|
2754
- if method.implemented_in == module_context.instance_definition.declaration
2855
+ if method.implemented_in == module_context.instance_definition.type_name
2755
2856
  set << name
2756
2857
  end
2757
2858
  end
2758
2859
  expected_module_method_names = (module_context.module_definition&.methods || {}).each.with_object(Set[]) do |(name, method), set|
2759
- if method.implemented_in == module_context.module_definition.declaration
2860
+ if method.implemented_in == module_context.module_definition.type_name
2760
2861
  set << name
2761
2862
  end
2762
2863
  end
@@ -2948,7 +3049,7 @@ module Steep
2948
3049
  def to_instance_type(type, args: nil)
2949
3050
  args = args || case type
2950
3051
  when AST::Types::Name::Class, AST::Types::Name::Module
2951
- checker.factory.env.find_class(checker.factory.type_name_1(type.name)).type_params.each.map { AST::Builtin.any_type }
3052
+ checker.factory.env.class_decls[checker.factory.type_name_1(type.name)].type_params.each.map { AST::Builtin.any_type }
2952
3053
  else
2953
3054
  raise "unexpected type to to_instance_type: #{type}"
2954
3055
  end
@@ -31,8 +31,8 @@ module Steep
31
31
  annotations.const_types.each do |name, type|
32
32
  env.set(const: name, type: type)
33
33
  end
34
- signatures.name_to_global.each do |name, global|
35
- type = signatures.absolute_type(global.type, namespace: RBS::Namespace.root) {|ty| ty.name.absolute! }
34
+ signatures.global_decls.each do |name, entry|
35
+ type = entry.decl.type
36
36
  env.set(gvar: name, type: subtyping.factory.type(type))
37
37
  end
38
38
  end
@@ -95,6 +95,12 @@ module Steep
95
95
  end_pos = node.loc.end.begin_pos
96
96
  add_context(begin_pos..end_pos, context: context)
97
97
 
98
+ when :sclass
99
+ name_node = node.children[0]
100
+ begin_pos = name_node.loc.expression.end_pos
101
+ end_pos = node.loc.end.begin_pos
102
+ add_context(begin_pos..end_pos, context: context)
103
+
98
104
  when :def, :defs
99
105
  args_node = case node.type
100
106
  when :def
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.16.3"
2
+ VERSION = "0.20.0"
3
3
  end
@@ -1,9 +1,10 @@
1
- extension Object (X)
1
+
2
+ class Object
2
3
  def try: [A] { (instance) -> A } -> A
3
4
  def f: -> Object
4
5
  end
5
6
 
6
- extension Kernel (X)
7
+ module Kernel
7
8
  def new_module_method: () -> void
8
9
  end
9
10
 
@@ -2,7 +2,6 @@ class NumberLike
2
2
  def to_number: -> Integer
3
3
  end
4
4
 
5
- extension Integer (NumberLike)
6
- def `+`: (NumberLike) -> NumberLike
7
- | super
5
+ class Integer
6
+ overload def `+`: (NumberLike) -> NumberLike
8
7
  end
@@ -1,12 +1,12 @@
1
1
  class A
2
2
  def foo: -> _Foo
3
3
  def hello: -> void
4
- end
5
4
 
6
- class A::Object
7
- def object?: -> bool
8
- end
5
+ class Object
6
+ def object?: -> bool
7
+ end
9
8
 
10
- interface A::_Foo
11
- def foo: -> Object
9
+ interface _Foo
10
+ def foo: -> Object
11
+ end
12
12
  end
@@ -41,5 +41,5 @@ Gem::Specification.new do |spec|
41
41
  spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
42
42
  spec.add_runtime_dependency "listen", "~> 3.1"
43
43
  spec.add_runtime_dependency "language_server-protocol", "~> 3.14.0.2"
44
- spec.add_runtime_dependency "rbs", "~> 0.3.1"
44
+ spec.add_runtime_dependency "rbs", ">= 0.6.0", '< 0.7.0'
45
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.3
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-27 00:00:00.000000000 Z
11
+ date: 2020-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -188,16 +188,22 @@ dependencies:
188
188
  name: rbs
189
189
  requirement: !ruby/object:Gem::Requirement
190
190
  requirements:
191
- - - "~>"
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: 0.6.0
194
+ - - "<"
192
195
  - !ruby/object:Gem::Version
193
- version: 0.3.1
196
+ version: 0.7.0
194
197
  type: :runtime
195
198
  prerelease: false
196
199
  version_requirements: !ruby/object:Gem::Requirement
197
200
  requirements:
198
- - - "~>"
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: 0.6.0
204
+ - - "<"
199
205
  - !ruby/object:Gem::Version
200
- version: 0.3.1
206
+ version: 0.7.0
201
207
  description: Gradual Typing for Ruby
202
208
  email:
203
209
  - matsumoto@soutaro.com