steep 0.17.1 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
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