steep 1.5.2 → 1.6.0.pre.1

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