steep 1.5.2 → 1.6.0.pre.1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-windows.yml +1 -2
  3. data/.github/workflows/ruby.yml +1 -2
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +2 -4
  6. data/Gemfile.lock +37 -19
  7. data/gemfile_steep/Gemfile.lock +4 -4
  8. data/lib/steep/ast/types/logic.rb +6 -0
  9. data/lib/steep/cli.rb +39 -19
  10. data/lib/steep/interface/builder.rb +9 -0
  11. data/lib/steep/path_helper.rb +2 -0
  12. data/lib/steep/server/change_buffer.rb +9 -0
  13. data/lib/steep/server/delay_queue.rb +41 -0
  14. data/lib/steep/server/interaction_worker.rb +4 -2
  15. data/lib/steep/server/master.rb +106 -10
  16. data/lib/steep/server/type_check_worker.rb +10 -3
  17. data/lib/steep/services/completion_provider.rb +1 -1
  18. data/lib/steep/services/stats_calculator.rb +2 -2
  19. data/lib/steep/services/type_name_completion.rb +86 -15
  20. data/lib/steep/signature/validator.rb +9 -2
  21. data/lib/steep/subtyping/check.rb +24 -18
  22. data/lib/steep/type_construction.rb +60 -18
  23. data/lib/steep/type_inference/logic_type_interpreter.rb +26 -0
  24. data/lib/steep/type_inference/method_params.rb +1 -1
  25. data/lib/steep/version.rb +1 -1
  26. data/lib/steep.rb +1 -3
  27. data/sig/shims/language-server_protocol.rbs +12 -0
  28. data/sig/steep/ast/types/logic.rbs +5 -0
  29. data/sig/steep/ast/types.rbs +1 -1
  30. data/sig/steep/cli.rbs +2 -0
  31. data/sig/steep/diagnostic/ruby.rbs +7 -7
  32. data/sig/steep/server/change_buffer.rbs +4 -0
  33. data/sig/steep/server/delay_queue.rbs +37 -0
  34. data/sig/steep/server/master.rbs +4 -0
  35. data/sig/steep/services/stats_calculator.rbs +30 -6
  36. data/sig/steep/services/type_name_completion.rbs +13 -0
  37. data/sig/steep/signature/validator.rbs +5 -0
  38. data/sig/steep/subtyping/check.rbs +1 -1
  39. data/sig/steep/subtyping/relation.rbs +11 -1
  40. data/sig/steep/subtyping/result.rbs +1 -1
  41. data/sig/steep/type_construction.rbs +1 -1
  42. data/smoke/block/test_expectations.yml +10 -14
  43. data/smoke/enumerator/test_expectations.yml +10 -10
  44. data/smoke/integer/test_expectations.yml +5 -16
  45. data/smoke/regression/hello world.rb +1 -0
  46. data/smoke/regression/test_expectations.yml +12 -0
  47. data/steep.gemspec +1 -1
  48. metadata +8 -7
  49. data/lib/steep/shims/filter_map.rb +0 -30
  50. data/lib/steep/shims/symbol_start_with.rb +0 -18
@@ -98,19 +98,19 @@ module Steep
98
98
  end
99
99
 
100
100
  class UnresolvedOverloading < Base
101
- attr_reader node: untyped
101
+ attr_reader node (): Parser::AST::Node
102
102
 
103
- attr_reader receiver_type: untyped
103
+ attr_reader receiver_type: AST::Types::t
104
104
 
105
- attr_reader method_name: untyped
105
+ attr_reader method_name: Symbol
106
106
 
107
- attr_reader method_types: untyped
107
+ attr_reader method_types: Array[Interface::MethodType]
108
108
 
109
- def initialize: (node: untyped, receiver_type: untyped, method_name: untyped, method_types: untyped) -> void
109
+ def initialize: (node: Parser::AST::Node, receiver_type: AST::Types::t, method_name: Symbol, method_types: Array[Interface::MethodType]) -> void
110
110
 
111
- def header_line: () -> ::String
111
+ def header_line: () -> String
112
112
 
113
- def detail_lines: () -> untyped
113
+ def detail_lines: () -> String
114
114
  end
115
115
 
116
116
  class ArgumentTypeMismatch < Base
@@ -27,6 +27,10 @@ module Steep
27
27
  # Load changes from a request with `DidChangeTextDocumentParams` into `buffered_changes`
28
28
  #
29
29
  def collect_changes: (untyped request) -> void
30
+
31
+ # Reset the content of `uri` to `text`
32
+ #
33
+ def reset_change: (uri: String, text: String) -> void
30
34
  end
31
35
  end
32
36
  end
@@ -0,0 +1,37 @@
1
+ module Steep
2
+ module Server
3
+ # DelayQueue provides a queue that delays running given job
4
+ #
5
+ # 1. The `delay` is specific to a DelayQueue instance, not job specific
6
+ # 2. It executes only the last job
7
+ #
8
+ # ```ruby
9
+ # queue = DelayQueue.new(delay: 0.5)
10
+ # queue.execute { pp 1 }
11
+ # queue.execute { pp 2 }
12
+ # queue.execute { pp 3 }
13
+ #
14
+ # # => Will print only `3`, and the jobs printing `1` and `2` will be discarded
15
+ # ```
16
+ #
17
+ # The job will run on `#thread`.
18
+ #
19
+ class DelayQueue
20
+ attr_reader delay: Float
21
+
22
+ attr_reader thread: Thread
23
+
24
+ attr_reader queue: Thread::Queue
25
+
26
+ attr_reader last_task: Proc
27
+
28
+ def initialize: (delay: Float) -> void
29
+
30
+ # The `#execute` method is not thread safe
31
+ #
32
+ # You should synchronize yourself if you want to call the method from multiple threads.
33
+ #
34
+ def execute: () { () -> void } -> void
35
+ end
36
+ end
37
+ end
@@ -225,6 +225,8 @@ module Steep
225
225
 
226
226
  attr_accessor typecheck_automatically: bool
227
227
 
228
+ attr_reader start_type_checking_queue: DelayQueue
229
+
228
230
  def initialize: (project: Project, reader: untyped, writer: untyped, interaction_worker: WorkerProcess?, typecheck_workers: Array[WorkerProcess], ?queue: Thread::Queue) -> void
229
231
 
230
232
  # Start the Steep language server
@@ -252,6 +254,8 @@ module Steep
252
254
 
253
255
  def work_done_progress_supported?: () -> bool
254
256
 
257
+ def file_system_watcher_supported?: () -> bool
258
+
255
259
  def process_message_from_client: (untyped message) -> void
256
260
 
257
261
  def process_message_from_worker: (untyped message, worker: WorkerProcess) -> void
@@ -1,17 +1,41 @@
1
1
  module Steep
2
2
  module Services
3
3
  class StatsCalculator
4
- SuccessStats: untyped
4
+ class SuccessStats
5
+ attr_reader target: Project::Target
5
6
 
6
- ErrorStats: untyped
7
+ attr_reader path: Pathname
7
8
 
8
- attr_reader service: untyped
9
+ attr_reader typed_calls_count: Integer
9
10
 
10
- def initialize: (service: untyped) -> void
11
+ attr_reader untyped_calls_count: Integer
11
12
 
12
- def project: () -> untyped
13
+ attr_reader error_calls_count: Integer
13
14
 
14
- def calc_stats: (untyped target, file: untyped) -> untyped
15
+ def initialize: (target: Project::Target, path: Pathname, typed_calls_count: Integer, untyped_calls_count: Integer, error_calls_count: Integer) -> void
16
+
17
+ def as_json: () -> Hash[Symbol, untyped]
18
+ end
19
+
20
+ class ErrorStats
21
+ attr_reader target: Project::Target
22
+
23
+ attr_reader path: Pathname
24
+
25
+ def initialize: (target: Project::Target, path: Pathname) -> void
26
+
27
+ def as_json: () -> Hash[Symbol, untyped]
28
+ end
29
+
30
+ type stats = SuccessStats | ErrorStats
31
+
32
+ attr_reader service: TypeCheckService
33
+
34
+ def initialize: (service: TypeCheckService) -> void
35
+
36
+ def project: () -> Project
37
+
38
+ def calc_stats: (Project::Target target, file: TypeCheckService::SourceFile) -> stats
15
39
  end
16
40
  end
17
41
  end
@@ -112,9 +112,22 @@ module Steep
112
112
 
113
113
  def format_constant_name: (TypeName) -> String
114
114
 
115
+ def resolve_used_name: (TypeName) -> TypeName?
116
+
117
+ private
118
+
119
+ # Yield type names defined in the environment
120
+ #
121
+ # * Yields an absolute type name if it is defined in the environment
122
+ # * Yields an relative type name if it is imported with `use` declerative
123
+ #
124
+ # Alias classes/modules and types under them are yielded.
125
+ #
115
126
  def each_type_name: () { (TypeName) -> void } -> void
116
127
  | () -> Enumerator[TypeName, void]
117
128
 
129
+ def each_type_name_under: (TypeName module_name, TypeName normalized_name, table: Hash[Namespace, Array[TypeName]]) { (TypeName) -> void } -> void
130
+
118
131
  def each_outer_module: (?Resolver::context) { (Namespace) -> void } -> Namespace
119
132
  | () -> Enumerator[Namespace, void]
120
133
  end
@@ -66,6 +66,11 @@ module Steep
66
66
 
67
67
  def validate_one_global: (Symbol name, RBS::Environment::GlobalEntry) -> void
68
68
 
69
+ # Validate type alias
70
+ #
71
+ # 1. Make sure the outer namespace of given `name` exists
72
+ # 2. Make sure the type alias is valid with respect to `RBS::Validator`
73
+ #
69
74
  def validate_one_alias: (RBS::TypeName name, ?RBS::Environment::TypeAliasEntry entry) -> void
70
75
 
71
76
  def validate_one_class_decl: (RBS::TypeName) -> void
@@ -123,7 +123,7 @@ module Steep
123
123
  # Returns nil if there is no path.
124
124
  def hole_path: (AST::Types::t `type`, ?Array[AST::Types::t] path) -> Array[AST::Types::t]?
125
125
 
126
- def Relation: [T < Object] (T sub, T sup) -> Relation[T]
126
+ def Relation: [T < Relation::_Subject] (T sub, T sup) -> Relation[T]
127
127
  end
128
128
  end
129
129
  end
@@ -1,6 +1,16 @@
1
1
  module Steep
2
2
  module Subtyping
3
- class Relation[out Subject < Object]
3
+ class Relation[out Subject < _Subject]
4
+ interface _Subject
5
+ def hash: () -> Integer
6
+
7
+ def is_a?: (Module) -> bool
8
+
9
+ def class: () -> Class
10
+
11
+ def !: () -> bool
12
+ end
13
+
4
14
  attr_reader sub_type: Subject
5
15
 
6
16
  attr_reader super_type: Subject
@@ -45,7 +45,7 @@ module Steep
45
45
  @failure: bool
46
46
 
47
47
  # Returns `false` if no future `#add` changes the result.
48
- def add: [T < Object] (*Relation[T] relations) { (Relation[T]) -> t? } -> bool
48
+ def add: [T < Relation::_Subject] (*Relation[T] relations) { (Relation[T]) -> t? } -> bool
49
49
 
50
50
  # Returns `false` if no future `#add` changes the result.
51
51
  def add_result: (t?) -> bool
@@ -271,7 +271,7 @@ module Steep
271
271
  def calculate_interface: (AST::Types::t `type`, private: bool) -> Interface::Shape?
272
272
  | (AST::Types::t `type`, Symbol method_name, private: bool) -> Interface::Shape::Entry?
273
273
 
274
- def expand_self: (untyped `type`) -> untyped
274
+ def expand_self: (AST::Types::t `type`) -> AST::Types::t
275
275
 
276
276
  SPECIAL_METHOD_NAMES: Hash[Symbol, Set[method_name]]
277
277
 
@@ -98,31 +98,27 @@
98
98
  - range:
99
99
  start:
100
100
  line: 10
101
- character: 0
101
+ character: 12
102
102
  end:
103
103
  line: 10
104
- character: 29
104
+ character: 28
105
105
  severity: ERROR
106
106
  message: |-
107
- Cannot find compatible overloading of method `map` of type `::Array[::Integer]`
108
- Method types:
109
- def map: [U] () { (::Integer) -> U } -> ::Array[U]
110
- | () -> ::Enumerator[::Integer, ::Array[untyped]]
111
- code: Ruby::UnresolvedOverloading
107
+ Cannot pass a value of type `::Proc` as a block-pass-argument of type `^(::Integer) -> U(3)`
108
+ ::Proc <: ^(::Integer) -> U(3)
109
+ code: Ruby::BlockTypeMismatch
112
110
  - range:
113
111
  start:
114
112
  line: 11
115
- character: 0
113
+ character: 12
116
114
  end:
117
115
  line: 11
118
- character: 21
116
+ character: 20
119
117
  severity: ERROR
120
118
  message: |-
121
- Cannot find compatible overloading of method `map` of type `::Array[::Integer]`
122
- Method types:
123
- def map: [U] () { (::Integer) -> U } -> ::Array[U]
124
- | () -> ::Enumerator[::Integer, ::Array[untyped]]
125
- code: Ruby::UnresolvedOverloading
119
+ Cannot pass a value of type `::Proc` as a block-pass-argument of type `^(::Integer) -> U(4)`
120
+ ::Proc <: ^(::Integer) -> U(4)
121
+ code: Ruby::BlockTypeMismatch
126
122
  - file: e.rb
127
123
  diagnostics:
128
124
  - range:
@@ -10,11 +10,11 @@
10
10
  character: 3
11
11
  severity: ERROR
12
12
  message: |-
13
- Cannot find compatible overloading of method `with_object` of type `::Enumerator[::Integer, ::Array[::Integer]]`
14
- Method types:
15
- def with_object: [U] (U) { (::Integer, U) -> untyped } -> U
16
- | [U] (U) -> ::Enumerator[[::Integer, U], U]
17
- code: Ruby::UnresolvedOverloading
13
+ Unsatisfiable constraint `::String <: U(1) <: ::Hash[::Symbol, ::String]` is generated through (U(1)) { (::Integer, U(1)) -> untyped } -> U(1)
14
+ ::String <: ::Hash[::Symbol, ::String]
15
+ ::Object <: ::Hash[::Symbol, ::String]
16
+ ::BasicObject <: ::Hash[::Symbol, ::String]
17
+ code: Ruby::UnsatisfiableConstraint
18
18
  - file: b.rb
19
19
  diagnostics:
20
20
  - range:
@@ -40,8 +40,8 @@
40
40
  character: 3
41
41
  severity: ERROR
42
42
  message: |-
43
- Cannot find compatible overloading of method `with_object` of type `::Enumerator[::Integer, ::Array[::Integer]]`
44
- Method types:
45
- def with_object: [U] (U) { (::Integer, U) -> untyped } -> U
46
- | [U] (U) -> ::Enumerator[[::Integer, U], U]
47
- code: Ruby::UnresolvedOverloading
43
+ Unsatisfiable constraint `::Array[untyped] <: U(3) <: ::String` is generated through (U(3)) { (::Integer, U(3)) -> untyped } -> U(3)
44
+ ::Array[untyped] <: ::String
45
+ ::Object <: ::String
46
+ ::BasicObject <: ::String
47
+ code: Ruby::UnsatisfiableConstraint
@@ -102,20 +102,9 @@
102
102
  message: |-
103
103
  Cannot find compatible overloading of method `Integer` of type `::Object`
104
104
  Method types:
105
- def Integer: ((::Numeric | ::String), ?exception: bool) -> ::Integer
106
- | (::String, ?::Integer, ?exception: bool) -> ::Integer
107
- code: Ruby::UnresolvedOverloading
108
- - range:
109
- start:
110
- line: 26
111
- character: 0
112
- end:
113
- line: 26
114
- character: 12
115
- severity: ERROR
116
- message: |-
117
- Cannot find compatible overloading of method `Integer` of type `::Object`
118
- Method types:
119
- def Integer: ((::Numeric | ::String), ?exception: bool) -> ::Integer
120
- | (::String, ?::Integer, ?exception: bool) -> ::Integer
105
+ def Integer: ((::_ToInt | ::_ToI), ?exception: true) -> ::Integer
106
+ | ((::_ToInt | ::_ToI), exception: bool) -> (::Integer | nil)
107
+ | (::string, ?::int, ?exception: true) -> ::Integer
108
+ | (::string, ?::int, exception: bool) -> (::Integer | nil)
109
+ | (untyped, ?untyped, exception: false) -> nil
121
110
  code: Ruby::UnresolvedOverloading
@@ -0,0 +1 @@
1
+ 1.foo()
@@ -35,6 +35,18 @@
35
35
  severity: ERROR
36
36
  message: 'Cannot find the declaration of class: `Foo`'
37
37
  code: Ruby::UnknownConstant
38
+ - file: hello world.rb
39
+ diagnostics:
40
+ - range:
41
+ start:
42
+ line: 1
43
+ character: 2
44
+ end:
45
+ line: 1
46
+ character: 5
47
+ severity: ERROR
48
+ message: Type `::Integer` does not have method `foo`
49
+ code: Ruby::NoMethod
38
50
  - file: issue_332.rb
39
51
  diagnostics:
40
52
  - range:
data/steep.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
28
 
29
- spec.required_ruby_version = '>= 2.7.0'
29
+ spec.required_ruby_version = '>= 3.0.0'
30
30
 
31
31
  spec.add_runtime_dependency "parser", ">= 3.1"
32
32
  spec.add_runtime_dependency "activesupport", ">= 5.1"
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: 1.5.2
4
+ version: 1.6.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-27 00:00:00.000000000 Z
11
+ date: 2023-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -332,6 +332,7 @@ files:
332
332
  - lib/steep/range_extension.rb
333
333
  - lib/steep/server/base_worker.rb
334
334
  - lib/steep/server/change_buffer.rb
335
+ - lib/steep/server/delay_queue.rb
335
336
  - lib/steep/server/interaction_worker.rb
336
337
  - lib/steep/server/lsp_formatter.rb
337
338
  - lib/steep/server/master.rb
@@ -350,8 +351,6 @@ files:
350
351
  - lib/steep/services/stats_calculator.rb
351
352
  - lib/steep/services/type_check_service.rb
352
353
  - lib/steep/services/type_name_completion.rb
353
- - lib/steep/shims/filter_map.rb
354
- - lib/steep/shims/symbol_start_with.rb
355
354
  - lib/steep/signature/validator.rb
356
355
  - lib/steep/source.rb
357
356
  - lib/steep/subtyping/cache.rb
@@ -467,6 +466,7 @@ files:
467
466
  - sig/steep/range_extension.rbs
468
467
  - sig/steep/server/base_worker.rbs
469
468
  - sig/steep/server/change_buffer.rbs
469
+ - sig/steep/server/delay_queue.rbs
470
470
  - sig/steep/server/interaction_worker.rbs
471
471
  - sig/steep/server/lsp_formatter.rbs
472
472
  - sig/steep/server/master.rbs
@@ -712,6 +712,7 @@ files:
712
712
  - smoke/regression/fun.rb
713
713
  - smoke/regression/fun.rbs
714
714
  - smoke/regression/hash.rb
715
+ - smoke/regression/hello world.rb
715
716
  - smoke/regression/issue_328.rb
716
717
  - smoke/regression/issue_328.rbs
717
718
  - smoke/regression/issue_332.rb
@@ -777,12 +778,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
777
778
  requirements:
778
779
  - - ">="
779
780
  - !ruby/object:Gem::Version
780
- version: 2.7.0
781
+ version: 3.0.0
781
782
  required_rubygems_version: !ruby/object:Gem::Requirement
782
783
  requirements:
783
- - - ">="
784
+ - - ">"
784
785
  - !ruby/object:Gem::Version
785
- version: '0'
786
+ version: 1.3.1
786
787
  requirements: []
787
788
  rubygems_version: 3.4.10
788
789
  signing_key:
@@ -1,30 +0,0 @@
1
- # Steep runs on Ruby 2.6 and it needs a shim of `filter_map`
2
-
3
- module Shims
4
- module EnumerableFilterMap
5
- def filter_map(&block)
6
- if block
7
- result = []
8
-
9
- each do |element|
10
- if value = yield(element)
11
- result << value
12
- end
13
- end
14
-
15
- result
16
- else
17
- enum_for :filter_map
18
- end
19
- end
20
- end
21
-
22
- unless Enumerable.method_defined?(:filter_map)
23
- Enumerable.include EnumerableFilterMap
24
-
25
- module ::Enumerable
26
- alias filter_map filter_map
27
- end
28
- end
29
- end
30
-
@@ -1,18 +0,0 @@
1
- # Steep runs on Ruby 2.6 and it needs a shim of `Symbol#start_with?`
2
-
3
- module Shims
4
- module SymbolStartWith
5
- def start_with?(*args)
6
- to_s.start_with?(*args)
7
- end
8
-
9
- def end_with?(*args)
10
- to_s.end_with?(*args)
11
- end
12
- end
13
-
14
- unless Symbol.method_defined?(:start_with?)
15
- Symbol.include(SymbolStartWith)
16
- end
17
- end
18
-