steep 1.7.0.dev.2 → 1.7.0.dev.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +17 -19
  3. data/doc/narrowing.md +1 -1
  4. data/doc/shape.md +176 -0
  5. data/gemfile_steep/Gemfile.lock +10 -12
  6. data/lib/steep/ast/types/factory.rb +27 -18
  7. data/lib/steep/ast/types/helper.rb +4 -0
  8. data/lib/steep/ast/types/intersection.rb +7 -0
  9. data/lib/steep/ast/types/proc.rb +14 -9
  10. data/lib/steep/ast/types/record.rb +7 -0
  11. data/lib/steep/ast/types/tuple.rb +7 -0
  12. data/lib/steep/ast/types/union.rb +7 -0
  13. data/lib/steep/drivers/stats.rb +2 -2
  14. data/lib/steep/drivers/validate.rb +4 -2
  15. data/lib/steep/expectations.rb +2 -2
  16. data/lib/steep/interface/block.rb +1 -1
  17. data/lib/steep/interface/builder.rb +337 -360
  18. data/lib/steep/interface/function.rb +82 -11
  19. data/lib/steep/interface/method_type.rb +18 -10
  20. data/lib/steep/interface/shape.rb +69 -18
  21. data/lib/steep/interface/substitution.rb +4 -0
  22. data/lib/steep/node_helper.rb +18 -1
  23. data/lib/steep/project/pattern.rb +1 -2
  24. data/lib/steep/server/interaction_worker.rb +6 -0
  25. data/lib/steep/server/lsp_formatter.rb +2 -0
  26. data/lib/steep/services/completion_provider.rb +20 -18
  27. data/lib/steep/services/file_loader.rb +15 -20
  28. data/lib/steep/services/signature_help_provider.rb +17 -18
  29. data/lib/steep/signature/validator.rb +1 -1
  30. data/lib/steep/subtyping/check.rb +19 -22
  31. data/lib/steep/subtyping/variable_variance.rb +3 -3
  32. data/lib/steep/test.rb +9 -0
  33. data/lib/steep/type_construction.rb +198 -158
  34. data/lib/steep/type_inference/block_params.rb +12 -4
  35. data/lib/steep/type_inference/context.rb +1 -1
  36. data/lib/steep/type_inference/logic_type_interpreter.rb +3 -2
  37. data/lib/steep/type_inference/method_params.rb +16 -0
  38. data/lib/steep/type_inference/send_args.rb +5 -2
  39. data/lib/steep/version.rb +1 -1
  40. data/lib/steep.rb +11 -7
  41. data/sig/steep/ast/types/factory.rbs +2 -2
  42. data/sig/steep/ast/types/helper.rbs +2 -0
  43. data/sig/steep/ast/types/intersection.rbs +2 -0
  44. data/sig/steep/ast/types/name.rbs +4 -0
  45. data/sig/steep/ast/types/record.rbs +2 -0
  46. data/sig/steep/ast/types/tuple.rbs +2 -0
  47. data/sig/steep/ast/types/union.rbs +2 -0
  48. data/sig/steep/expectations.rbs +1 -1
  49. data/sig/steep/interface/block.rbs +2 -2
  50. data/sig/steep/interface/builder.rbs +54 -109
  51. data/sig/steep/interface/function.rbs +38 -32
  52. data/sig/steep/interface/shape.rbs +23 -4
  53. data/sig/steep/interface/substitution.rbs +2 -0
  54. data/sig/steep/node_helper.rbs +11 -0
  55. data/sig/steep/services/signature_help_provider.rbs +3 -1
  56. data/sig/steep/subtyping/constraints.rbs +2 -2
  57. data/sig/steep/subtyping/variable_variance.rbs +1 -1
  58. data/sig/steep/type_construction.rbs +1 -1
  59. data/sig/steep/type_inference/block_params.rbs +3 -3
  60. data/sig/steep/type_inference/context.rbs +2 -0
  61. data/sig/steep/type_inference/method_params.rbs +3 -3
  62. data/sig/steep.rbs +1 -1
  63. data/steep.gemspec +1 -1
  64. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0646b6c1cb596e684bc62461ee2dac160e134bc7e126f447df8f6e46a535c8b6
4
- data.tar.gz: fda1f8d1903253537fec79679dd88f3579404372d4fc611a0d4b9d085e5b3502
3
+ metadata.gz: 17795ed14e183d6e8858e6ea8f57f71dbd3cdced0e4d9cf7e43c646188e486cd
4
+ data.tar.gz: 7005e9d96f44f23a47f1844597b86fd3d774f000b1de5cf100d235e68c56a0b5
5
5
  SHA512:
6
- metadata.gz: 46fe48e86a4fe74482765debeb255e1b806298fb797603ebf292443432506e80ac7ffb7aa964b6331e4f71d2f4e607379340834a6f66866d75bc8c0ca4b73633
7
- data.tar.gz: c822e0bf8a0484914423ece12d3d38bebf4102d6f63b1eb79f779cc3bf8aa9b909d34b189a594cf5d0a4f607ed0474d7b9bb2ed6a6c6d400212e329f4d5a8e96
6
+ metadata.gz: e178baa7a185edaafb359032266bfa7f29d082c9da30ca418e5ef4030b5723423f3f36ba4165a640d996e252bb91883dcfe55b1f750f51c3153452b368e5a9ee
7
+ data.tar.gz: 8919d4c047097e7e7fd63ecba71ae96f412a56588c7b6ff1d381838d2d935d2ba7dc382ca83fe5b679f35ebbe298460e80e87047c88b6ebcc5e3e6ef258e2535
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (1.7.0.dev.2)
4
+ steep (1.7.0.dev.4)
5
5
  activesupport (>= 5.1)
6
6
  concurrent-ruby (>= 1.1.10)
7
7
  csv (>= 3.0.9)
@@ -12,7 +12,7 @@ PATH
12
12
  logger (>= 1.3.0)
13
13
  parser (>= 3.1)
14
14
  rainbow (>= 2.2.2, < 4.0)
15
- rbs (>= 3.1.0)
15
+ rbs (>= 3.5.0.pre)
16
16
  securerandom (>= 0.1)
17
17
  strscan (>= 1.0.0)
18
18
  terminal-table (>= 2, < 4)
@@ -33,53 +33,51 @@ GEM
33
33
  tzinfo (~> 2.0)
34
34
  ast (2.4.2)
35
35
  base64 (0.2.0)
36
- bigdecimal (3.1.6)
36
+ bigdecimal (3.1.8)
37
37
  concurrent-ruby (1.2.3)
38
38
  connection_pool (2.4.1)
39
- csv (3.2.8)
40
- debug (1.9.1)
39
+ csv (3.3.0)
40
+ debug (1.9.2)
41
41
  irb (~> 1.10)
42
42
  reline (>= 0.3.8)
43
- drb (2.2.0)
44
- ruby2_keywords
43
+ drb (2.2.1)
45
44
  ffi (1.16.3)
46
45
  fileutils (1.7.2)
47
- i18n (1.14.1)
46
+ i18n (1.14.5)
48
47
  concurrent-ruby (~> 1.0)
49
48
  io-console (0.7.2)
50
- irb (1.11.1)
51
- rdoc
49
+ irb (1.13.1)
50
+ rdoc (>= 4.0.0)
52
51
  reline (>= 0.4.2)
53
- json (2.7.1)
52
+ json (2.7.2)
54
53
  language_server-protocol (3.17.0.3)
55
- listen (3.8.0)
54
+ listen (3.9.0)
56
55
  rb-fsevent (~> 0.10, >= 0.10.3)
57
56
  rb-inotify (~> 0.9, >= 0.9.10)
58
57
  logger (1.6.0)
59
- minitest (5.22.2)
58
+ minitest (5.22.3)
60
59
  minitest-hooks (1.5.1)
61
60
  minitest (> 5.3)
62
61
  minitest-slow_test (0.2.0)
63
62
  minitest (>= 5.0)
64
63
  mutex_m (0.2.0)
65
- parser (3.3.0.5)
64
+ parser (3.3.1.0)
66
65
  ast (~> 2.4.1)
67
66
  racc
68
67
  psych (5.1.2)
69
68
  stringio
70
69
  racc (1.7.3)
71
70
  rainbow (3.1.1)
72
- rake (13.1.0)
71
+ rake (13.2.1)
73
72
  rb-fsevent (0.11.2)
74
73
  rb-inotify (0.10.1)
75
74
  ffi (~> 1.0)
76
- rbs (3.4.4)
75
+ rbs (3.5.0.pre.2)
77
76
  abbrev
78
- rdoc (6.6.2)
77
+ rdoc (6.6.3.1)
79
78
  psych (>= 4.0.0)
80
- reline (0.4.2)
79
+ reline (0.5.6)
81
80
  io-console (~> 0.5)
82
- ruby2_keywords (0.0.5)
83
81
  securerandom (0.3.1)
84
82
  stackprof (0.2.26)
85
83
  stringio (3.1.0)
data/doc/narrowing.md CHANGED
@@ -65,7 +65,7 @@ It immediately type checks the left hand side, but with *conditional mode*. Cond
65
65
  x && y
66
66
  ```
67
67
 
68
- Going down again, it gets a typing `x: String?` and `y: String?. It runs a type narrowing, to obtain a result both of `x` and `y` are `String` for truthy result, both of `x` and `y` are `String?` for falsy result. The two environments should be propagated to the upper node, because the parent node is also `&&` which is a subject of type narrowing. So, it returns an `ENV` type, `String?` for original type, `{ x: String, y: String }` for truthy result, and `{ x: String?, y: String? }` for falsy result.
68
+ Going down again, it gets a typing `x: String?` and `y: String?`. It runs a type narrowing, to obtain a result both of `x` and `y` are `String` for truthy result, both of `x` and `y` are `String?` for falsy result. The two environments should be propagated to the upper node, because the parent node is also `&&` which is a subject of type narrowing. So, it returns an `ENV` type, `String?` for original type, `{ x: String, y: String }` for truthy result, and `{ x: String?, y: String? }` for falsy result.
69
69
 
70
70
  Going up to the outer `&&` expression. The left hand side has `ENV` type, and then the right hand side is type checked based on the truthy environment (because of the semantics of `&&` expression.) Both `x` and `y` are `String` and it type checks. The type of the whole expression union of `String` and the falsy part of the original type -- `nil`.
71
71
  ## Union type partition
data/doc/shape.md ADDED
@@ -0,0 +1,176 @@
1
+ # Shapes
2
+
3
+ A *shape* is a data structure, which contains the set of available methods and their types, which is associated with a type. Steep uses shapes to type check method calls -- it calculates the shape of the type of the receiver, checks if the called method is defined on the shape and the arguments are compatible with the method, and calculates the return type.
4
+
5
+ Assume an interface `_Foo` is defined as follows:
6
+
7
+ ```rbs
8
+ interface _Foo
9
+ def foo: () -> String
10
+
11
+ def bar: () -> self
12
+ end
13
+ ```
14
+
15
+ The shape of `_Foo` will be the following:
16
+
17
+ ```
18
+ Shape (_Foo) {
19
+ foo: () -> String,
20
+ bar: () -> _Foo
21
+ }
22
+ ```
23
+
24
+ Note that the `self` type in the example is resolved to `_Foo` during shape calculation.
25
+
26
+ The shape calculation of an object is straightforward. Calculate a `RBS::Definition` of a class singleton/instance, or an interface, and translate the data structure to a `Shape` object. But there are a few things to consider.
27
+ ## Tuple, record, and proc types
28
+ The shape of tuple, record, or proc types are based on their base types -- Array, Hash, or Proc classes --, but with specialized method types.
29
+
30
+ ```
31
+ Shape ([Integer, String]) {
32
+ []: (0) -> Integer
33
+ | (1) -> String
34
+ | (Integer) -> (Integer | String)
35
+ ...
36
+ }
37
+ ```
38
+
39
+ The specialization is implemented as a part of shape calculation.
40
+ ## Special methods
41
+ Steep recognizes some special methods for type narrowing, including `#is_a?`, `#===`, `#nil?`, ... These methods are defined with normal RBS syntax, but the method types in shapes are transformed to types using logic types.
42
+
43
+ The shape calculation inserts the specialized methods with these special methods.
44
+ ## `self` types
45
+ There are two cases of `self` types to consider during shape calculation.
46
+
47
+ 1. `self` types included in the shape of a type
48
+ 2. `self` types included in given types
49
+ ### 1. `self` types included in the shape of a type
50
+ `self` types may be included in a class or interface definition.
51
+
52
+ ```rbs
53
+ interface _Foo
54
+ def itself: () -> self
55
+ end
56
+ ```
57
+
58
+ The `self` types included in the shape of `_Foo` type should be resolved to `_Foo` type.
59
+
60
+ ```
61
+ Shape (_Foo) {
62
+ itself: () -> _Foo
63
+ }
64
+ ```
65
+ ### 2. `self` types included in given types
66
+ Unlike `self` types included in definitions, `self` types in given types should be preserved.
67
+
68
+ ```rbs
69
+ interface _Foo[A]
70
+ def get: () -> A
71
+ end
72
+ ```
73
+
74
+ The shape of `_Foo[self]` has `self` type as its type argument, and we want the `self` type preserved after the shape calculation.
75
+
76
+ ```
77
+ Shape (_Foo[self]) {
78
+ get: () -> self
79
+ }
80
+ ```
81
+
82
+ We often use `self` types as the return type of a method.
83
+
84
+ ```rbs
85
+ class Foo
86
+ def foo: () -> self
87
+ end
88
+ ```
89
+
90
+ So, the implementation of `foo` might use `self` node to return `self` type.
91
+
92
+ ```rb
93
+ class Foo
94
+ def foo
95
+ # @type var foo: _Foo[self]
96
+ foo = ...
97
+ foo.get
98
+ end
99
+ end
100
+ ```
101
+
102
+ We want the type of `foo.get` to be `self`, not `Foo`, to avoid a type error being detected.
103
+ ## Shape of `self` types
104
+ We also want `self` type if `self` is the type of the shape.
105
+
106
+ ```rb
107
+ class Foo
108
+ def foo
109
+ self.itself
110
+ end
111
+ end
112
+ ```
113
+
114
+ This is a straightforward case, because the type of `self` is `self` itself. Calculate the shape of it, but keep the `self` types in the shape.
115
+
116
+ ```
117
+ Shape (self) {
118
+ itself: () -> self
119
+ }
120
+ ```
121
+
122
+ If `self` is a union type, or something built with a type constructor, the shape calculation gets complicated.
123
+
124
+ ```rbs
125
+ class Foo
126
+ def foo: () -> Integer
127
+ end
128
+
129
+ class Bar
130
+ def foo: () -> self
131
+ end
132
+ ```
133
+
134
+ What is the expected shape of `self` where the type of `self` is `Foo | Bar`?
135
+
136
+ The shape of a union type is straightforward. It calculates the shape of each type, and then it calculates a union of the shape.
137
+
138
+ We do the same for the case with `self` types, but it results in slightly incorrect shapes.
139
+
140
+ ```
141
+ Shape (Foo) {
142
+ foo: () -> Integer
143
+ }
144
+
145
+ Shape (Bar) {
146
+ foo: () -> self # self is preserved, because the shape of `self` is being calculated
147
+ }
148
+
149
+ Shape (Foo | Bar) {
150
+ foo: () -> (Integer | self)
151
+ }
152
+ ```
153
+
154
+ So, the resulting type of `self.foo` where the type of `self` is `Foo | Bar`, would be `Integer | Foo | Bar`. But, actually, it won't be `Foo` because the `self` comes from `Bar`.
155
+
156
+ This is an incorrect result, but Steep is doing this right now.
157
+ ## `class` and `instance` types
158
+ The shape calculation provides limited support for `class` and `instance` types.
159
+
160
+ 1. `class`/`instance` types from the definition are resolved
161
+ 2. `class`/`instance` types in generics type arguments of interfaces/instances are preserved
162
+ 3. Shape of `class`/`instance` types are resolved to configuration's `class_type` and `instance_type`, and the translated types are used to calculate the shape
163
+
164
+ It's different from `self` types except case #2. The relationship between `self`/`class`/`instance` is not trivial in Ruby. All of them might be resolved to any type, which means calculating one from another of them is simply impossible.
165
+ ## Public methods, private methods
166
+ `Shape` objects have a flag of if the shape is for *public* method calls or *private* method calls. Private method call is a form of `foo()` or `self.foo()` -- when the receiver is omitted or `self`. Public method calls are anything else.
167
+
168
+ The shape calculation starts with *private methods*, and the `Shape#public_shape` method returns another shape that only has *public* methods.
169
+
170
+ > Note that the private shape calculation is required even on public method calls. This means a possible chance of future optimizations.
171
+ ## Lazy method type calculation
172
+ We rarely need all of the methods available for an object. If we want to type check a method call, we only need the method type of that method. All other methods can be just ignored.
173
+
174
+ *Lazy method type calculation* is introduced for that case. Instead of calculating the types of all of the methods, it registers a block that computes the method type.
175
+
176
+ It is implemented in `Steep::Interface::Shape::Entry` and used to make the shape calculation of a union type faster.
@@ -2,7 +2,7 @@ GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
4
  abbrev (0.1.2)
5
- activesupport (7.1.3)
5
+ activesupport (7.1.3.2)
6
6
  base64
7
7
  bigdecimal
8
8
  concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -14,25 +14,24 @@ GEM
14
14
  tzinfo (~> 2.0)
15
15
  ast (2.4.2)
16
16
  base64 (0.2.0)
17
- bigdecimal (3.1.6)
17
+ bigdecimal (3.1.8)
18
18
  concurrent-ruby (1.2.3)
19
19
  connection_pool (2.4.1)
20
- csv (3.2.8)
21
- drb (2.2.0)
22
- ruby2_keywords
20
+ csv (3.3.0)
21
+ drb (2.2.1)
23
22
  ffi (1.16.3)
24
23
  fileutils (1.7.2)
25
- i18n (1.14.1)
24
+ i18n (1.14.5)
26
25
  concurrent-ruby (~> 1.0)
27
- json (2.7.1)
26
+ json (2.7.2)
28
27
  language_server-protocol (3.17.0.3)
29
- listen (3.8.0)
28
+ listen (3.9.0)
30
29
  rb-fsevent (~> 0.10, >= 0.10.3)
31
30
  rb-inotify (~> 0.9, >= 0.9.10)
32
31
  logger (1.6.0)
33
- minitest (5.22.2)
32
+ minitest (5.22.3)
34
33
  mutex_m (0.2.0)
35
- parser (3.3.0.5)
34
+ parser (3.3.1.0)
36
35
  ast (~> 2.4.1)
37
36
  racc
38
37
  racc (1.7.3)
@@ -42,9 +41,8 @@ GEM
42
41
  ffi (~> 1.0)
43
42
  rbs (3.4.4)
44
43
  abbrev
45
- ruby2_keywords (0.0.5)
46
44
  securerandom (0.3.1)
47
- steep (1.7.0.dev.1)
45
+ steep (1.7.0.dev.3)
48
46
  activesupport (>= 5.1)
49
47
  concurrent-ruby (>= 1.1.10)
50
48
  csv (>= 3.0.9)
@@ -212,27 +212,36 @@ module Steep
212
212
  params = func.params
213
213
  return_type = func.return_type
214
214
 
215
- RBS::Types::Function.new(
216
- required_positionals: params.required.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
217
- optional_positionals: params.optional.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
218
- rest_positionals: params.rest&.yield_self {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
219
- trailing_positionals: [],
220
- required_keywords: params.required_keywords.transform_values {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
221
- optional_keywords: params.optional_keywords.transform_values {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
222
- rest_keywords: params.rest_keywords&.yield_self {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
223
- return_type: type_1(return_type)
224
- )
215
+ if params
216
+ RBS::Types::Function.new(
217
+ required_positionals: params.required.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
218
+ optional_positionals: params.optional.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
219
+ rest_positionals: params.rest&.yield_self {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
220
+ trailing_positionals: [],
221
+ required_keywords: params.required_keywords.transform_values {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
222
+ optional_keywords: params.optional_keywords.transform_values {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
223
+ rest_keywords: params.rest_keywords&.yield_self {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
224
+ return_type: type_1(return_type)
225
+ )
226
+ else
227
+ RBS::Types::UntypedFunction.new(return_type: type_1(return_type))
228
+ end
225
229
  end
226
230
 
227
231
  def params(type)
228
- Interface::Function::Params.build(
229
- required: type.required_positionals.map {|param| type(param.type) },
230
- optional: type.optional_positionals.map {|param| type(param.type) },
231
- rest: type.rest_positionals&.yield_self {|param| type(param.type) },
232
- required_keywords: type.required_keywords.transform_values {|param| type(param.type) },
233
- optional_keywords: type.optional_keywords.transform_values {|param| type(param.type) },
234
- rest_keywords: type.rest_keywords&.yield_self {|param| type(param.type) }
235
- )
232
+ case type
233
+ when RBS::Types::Function
234
+ Interface::Function::Params.build(
235
+ required: type.required_positionals.map {|param| type(param.type) },
236
+ optional: type.optional_positionals.map {|param| type(param.type) },
237
+ rest: type.rest_positionals&.yield_self {|param| type(param.type) },
238
+ required_keywords: type.required_keywords.transform_values {|param| type(param.type) },
239
+ optional_keywords: type.optional_keywords.transform_values {|param| type(param.type) },
240
+ rest_keywords: type.rest_keywords&.yield_self {|param| type(param.type) }
241
+ )
242
+ when RBS::Types::UntypedFunction
243
+ nil
244
+ end
236
245
  end
237
246
 
238
247
  def type_param(type_param)
@@ -29,6 +29,10 @@ module Steep
29
29
  enum_for :each_child
30
30
  end
31
31
  end
32
+
33
+ def map_type
34
+ self
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -80,6 +80,13 @@ module Steep
80
80
  end
81
81
  end
82
82
 
83
+ def map_type(&block)
84
+ self.class.build(
85
+ types: each_child.map(&block),
86
+ location: location
87
+ )
88
+ end
89
+
83
90
  def level
84
91
  [0] + level_of_children(types)
85
92
  end
@@ -57,9 +57,11 @@ module Steep
57
57
  include Helper::ChildrenLevel
58
58
 
59
59
  def level
60
- children = type.params.each_type.to_a + [type.return_type]
60
+ children = type.params&.each_type.to_a + [type.return_type]
61
61
  if block
62
- children.push(*block.type.params.each_type.to_a)
62
+ if block.type.params
63
+ children.push(*block.type.params.each_type.to_a)
64
+ end
63
65
  children.push(block.type.return_type)
64
66
  end
65
67
  if self_type
@@ -83,13 +85,16 @@ module Steep
83
85
 
84
86
  def one_arg?
85
87
  params = type.params
86
-
87
- params.required.size == 1 &&
88
- params.optional.empty? &&
89
- !params.rest &&
90
- params.required_keywords.empty? &&
91
- params.optional_keywords.empty? &&
92
- !params.rest_keywords
88
+ if params
89
+ params.required.size == 1 &&
90
+ params.optional.empty? &&
91
+ !params.rest &&
92
+ params.required_keywords.empty? &&
93
+ params.optional_keywords.empty? &&
94
+ !params.rest_keywords
95
+ else
96
+ true
97
+ end
93
98
  end
94
99
 
95
100
  def back_type
@@ -50,6 +50,13 @@ module Steep
50
50
  end
51
51
  end
52
52
 
53
+ def map_type(&block)
54
+ self.class.new(
55
+ elements: elements.transform_values(&block),
56
+ location: location
57
+ )
58
+ end
59
+
53
60
  def level
54
61
  [0] + level_of_children(elements.values)
55
62
  end
@@ -46,6 +46,13 @@ module Steep
46
46
  end
47
47
  end
48
48
 
49
+ def map_type(&block)
50
+ Tuple.new(
51
+ types: types.map(&block),
52
+ location: location
53
+ )
54
+ end
55
+
49
56
  def level
50
57
  [0] + level_of_children(types)
51
58
  end
@@ -80,6 +80,13 @@ module Steep
80
80
  end
81
81
  end
82
82
 
83
+ def map_type(&block)
84
+ Union.build(
85
+ types: types.map(&block),
86
+ location: location
87
+ )
88
+ end
89
+
83
90
  include Helper::ChildrenLevel
84
91
 
85
92
  def level
@@ -83,7 +83,7 @@ module Steep
83
83
  end
84
84
  end
85
85
 
86
- table = Terminal::Table.new(
86
+ table = Terminal::Table.new( # steep:ignore UnknownConstant
87
87
  headings: ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"],
88
88
  rows: rows
89
89
  )
@@ -166,7 +166,7 @@ module Steep
166
166
  {
167
167
  id: stats_id,
168
168
  method: "workspace/executeCommand",
169
- params: { command: "steep/stats", arguments: [] }
169
+ params: { command: "steep/stats", arguments: _ = [] }
170
170
  })
171
171
 
172
172
  stats_response = wait_for_response_id(reader: client_reader, id: stats_id)
@@ -49,8 +49,10 @@ module Steep
49
49
  if buffer
50
50
  printer = DiagnosticPrinter.new(stdout: stdout, buffer: buffer)
51
51
  ds.each do |d|
52
- printer.print(d)
53
- stdout.puts
52
+ if d
53
+ printer.print(_ = d)
54
+ stdout.puts
55
+ end
54
56
  end
55
57
  end
56
58
  end
@@ -23,7 +23,7 @@ module Steep
23
23
  :information
24
24
  when "HINT"
25
25
  :hint
26
- end #: Diagnostic::LSPFormatter::severity
26
+ end #: Steep::Diagnostic::LSPFormatter::severity
27
27
 
28
28
  Diagnostic.new(
29
29
  start_position: start_position,
@@ -56,7 +56,7 @@ module Steep
56
56
  :hint
57
57
  else
58
58
  :error
59
- end #: Diagnostic::LSPFormatter::severity
59
+ end #: Steep::Diagnostic::LSPFormatter::severity
60
60
 
61
61
  Diagnostic.new(
62
62
  start_position: start_position,
@@ -82,7 +82,7 @@ module Steep
82
82
  def +(other)
83
83
  optional = self.optional? || other.optional?
84
84
  type = Function.new(
85
- params: self.type.params + other.type.params,
85
+ params: self.type.params && other.type.params ? self.type.params + other.type.params : nil,
86
86
  return_type: AST::Types::Union.build(types: [self.type.return_type, other.type.return_type]),
87
87
  location: nil
88
88
  )