steep 0.17.1 → 0.22.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: a1ad7c49806193ddc567206eff7d74ad184bf6e339f15f5a06b54eac2a44798d
4
- data.tar.gz: 7738b5ccd9339e7de6643e8d87b8e3eaf7a0f36a42a4667848ea29cc3637d34a
3
+ metadata.gz: 1008a3723d59bab0d00afb4b385ee2752d8679461416eba84e48cc9ae479b0a4
4
+ data.tar.gz: 58c470fe9d8c619d9d0767a392ab6557b6dc50b007c6c99ff6ad27a79a88ecd4
5
5
  SHA512:
6
- metadata.gz: 68c6694af012124101dbf7d345fd4cab56582968a58cb462c4336558547089a403604606991585d12c5165b2955002f5905fe6b75788e7bab677cb9b6229f1ec
7
- data.tar.gz: 25437e503f4630e92b9fa7cdb31701ae809209f8e300812736a6acacdd181882fd380d277dd672334ae88698198c5ea4a2e0d7d83761614d75db86cf49d9d49e
6
+ metadata.gz: 6f1074ca3634f9df53f361f78a4838912cb7420918f72afdb08e49ab9d64bbe97177780a54648526ff3947b36ab2f0fb2fec3fce73ed97ce0b835359c81ff52d
7
+ data.tar.gz: b1c5b3fb447832fb648a56b4d827592ba0ddd719e384795786e27201a32305ce36a0d93edde61c94a311708599dd7090359bc1f15ae04ef0fa3717bd897cb580
@@ -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,33 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.22.0 (2020-08-03)
6
+
7
+ * Improve signature validation ([#175](https://github.com/soutaro/steep/pull/175), [#177](https://github.com/soutaro/steep/pull/177))
8
+ * Fix boolean literal typing ([#172](https://github.com/soutaro/steep/pull/172))
9
+ * Make exit code success when Steep has unreported type errors ([#171](https://github.com/soutaro/steep/pull/171))
10
+ * Allow `./` prefix for signature pattern ([#170](https://github.com/soutaro/steep/pull/170))
11
+
12
+ ## 0.21.0 (2020-07-20)
13
+
14
+ * Fix LSP hover ([#168](https://github.com/soutaro/steep/pull/168))
15
+ * Nominal subtyping ([#167](https://github.com/soutaro/steep/pull/167))
16
+
17
+ ## 0.20.0 (2020-07-17)
18
+
19
+ * Support singleton class definitions ([#166](https://github.com/soutaro/steep/pull/166))
20
+
21
+ ## 0.19.0 (2020-07-12)
22
+
23
+ * Update RBS. ([#157](https://github.com/soutaro/steep/pull/157))
24
+ * No `initialize` in completion. ([#164](https://github.com/soutaro/steep/pull/164))
25
+ * Granular typing option setup. ([#163](https://github.com/soutaro/steep/pull/163))
26
+
27
+ ## 0.18.0 (2020-07-06)
28
+
29
+ * Sort result of `Pathname#glob` ([#154](https://github.com/soutaro/steep/pull/154))
30
+ * Sort methods in LanguageServer to return non-inherited methods first ([#159](https://github.com/soutaro/steep/pull/159))
31
+
5
32
  ## 0.17.1 (2020-06-15)
6
33
 
7
34
  * Allow RBS gem to be 0.4 ([#153](https://github.com/soutaro/steep/pull/153))
data/Gemfile CHANGED
@@ -5,3 +5,10 @@ gemspec
5
5
 
6
6
  gem "with_steep_types", path: "test/gems/with_steep_types"
7
7
  gem "without_steep_types", path: "test/gems/without_steep_types"
8
+
9
+ gem "rake"
10
+ gem "minitest", "~> 5.0"
11
+ gem "racc", "~> 1.4"
12
+ gem "minitest-reporters"
13
+ gem "minitest-hooks"
14
+ gem "stackprof"
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "stackprof"
4
+
5
+ mode = (ENV["STEEP_STACKPROF_MODE"] || :wall).to_sym
6
+ out = ENV["STEEP_STACKPROF_OUT"] || "tmp/stackprof-#{mode}-steep.dump"
7
+
8
+ def exit(*)
9
+
10
+ end
11
+
12
+
13
+ STDERR.puts "Running profiler: mode=#{mode}, out=#{out}"
14
+ StackProf.run(mode: mode, out: out) do
15
+ load File.join(__dir__, "../exe/steep")
16
+ end
@@ -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
@@ -49,6 +49,10 @@ module Steep
49
49
  Builtin::String
50
50
  when Symbol
51
51
  Builtin::Symbol
52
+ when true
53
+ Builtin::TrueClass
54
+ when false
55
+ Builtin::FalseClass
52
56
  else
53
57
  raise "Unexpected literal type: #{value.inspect}"
54
58
  end
@@ -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
@@ -52,6 +52,13 @@ module Steep
52
52
  true
53
53
  end
54
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
55
62
  end
56
63
  end
57
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:)
@@ -78,6 +79,7 @@ module Steep
78
79
  def self.test_pattern(patterns, path, ext:)
79
80
  patterns.any? do |pattern|
80
81
  p = pattern.end_with?(File::Separator) ? pattern : pattern + File::Separator
82
+ p.delete_prefix!('./')
81
83
  (path.to_s.start_with?(p) && path.extname == ext) || File.fnmatch(pattern, path.to_s)
82
84
  end
83
85
  end
@@ -95,7 +97,7 @@ module Steep
95
97
  end
96
98
 
97
99
  def environment
98
- @environment ||= RBS::Environment.new().tap do |env|
100
+ @environment ||= RBS::Environment.new().yield_self do |env|
99
101
  stdlib_root = options.vendored_stdlib_path || RBS::EnvironmentLoader::STDLIB_ROOT
100
102
  gem_vendor_path = options.vendored_gems_path
101
103
  loader = RBS::EnvironmentLoader.new(stdlib_root: stdlib_root, gem_vendor_path: gem_vendor_path)
@@ -103,6 +105,8 @@ module Steep
103
105
  loader.add(library: lib)
104
106
  end
105
107
  loader.load(env: env)
108
+
109
+ env.resolve_type_names
106
110
  end
107
111
  end
108
112
 
@@ -125,34 +129,50 @@ module Steep
125
129
  if status.is_a?(TypeCheckStatus) && updated_files.empty?
126
130
  yield status.environment, status.subtyping, status.timestamp
127
131
  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
132
+ begin
133
+ env = environment.dup
134
+
135
+ signature_files.each_value do |file|
136
+ if file.status.is_a?(SignatureFile::DeclarationsStatus)
137
+ file.status.declarations.each do |decl|
138
+ env << decl
139
+ end
134
140
  end
135
141
  end
136
- end
137
142
 
138
- definition_builder = RBS::DefinitionBuilder.new(env: env)
139
- factory = AST::Types::Factory.new(builder: definition_builder)
140
- check = Subtyping::Check.new(factory: factory)
143
+ env = env.resolve_type_names
141
144
 
142
- if validate
143
- validator = Signature::Validator.new(checker: check)
144
- validator.validate()
145
+ definition_builder = RBS::DefinitionBuilder.new(env: env)
146
+ factory = AST::Types::Factory.new(builder: definition_builder)
147
+ check = Subtyping::Check.new(factory: factory)
145
148
 
146
- if validator.no_error?
147
- yield env, check, Time.now
149
+ if validate
150
+ validator = Signature::Validator.new(checker: check)
151
+ validator.validate()
152
+
153
+ if validator.no_error?
154
+ yield env, check, Time.now
155
+ else
156
+ @status = SignatureValidationErrorStatus.new(
157
+ errors: validator.each_error.to_a,
158
+ timestamp: Time.now
159
+ )
160
+ end
148
161
  else
149
- @status = SignatureValidationErrorStatus.new(
150
- errors: validator.each_error.to_a,
151
- timestamp: Time.now
152
- )
162
+ yield env, check, Time.now
153
163
  end
154
- else
155
- yield env, check, Time.now
164
+ rescue RBS::DuplicatedDeclarationError => exn
165
+ @status = SignatureValidationErrorStatus.new(
166
+ errors: [
167
+ Signature::Errors::DuplicatedDefinitionError.new(
168
+ name: exn.name,
169
+ location: exn.decls[0].location
170
+ )
171
+ ],
172
+ timestamp: Time.now
173
+ )
174
+ rescue => exn
175
+ @status = SignatureOtherErrorStatus.new(error: exn, timestamp: Time.now)
156
176
  end
157
177
  end
158
178
 
@@ -196,7 +216,7 @@ module Steep
196
216
  def errors
197
217
  case status
198
218
  when TypeCheckStatus
199
- source_files.each_value.flat_map(&:errors)
219
+ source_files.each_value.flat_map(&:errors).select { |error | options.error_to_report?(error) }
200
220
  else
201
221
  []
202
222
  end