steep 1.7.0.dev.3 → 1.7.0.dev.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +12 -12
  3. data/doc/narrowing.md +1 -1
  4. data/doc/shape.md +176 -0
  5. data/gemfile_steep/Gemfile.lock +5 -5
  6. data/lib/steep/ast/types/factory.rb +27 -18
  7. data/lib/steep/ast/types/proc.rb +14 -9
  8. data/lib/steep/interface/block.rb +1 -1
  9. data/lib/steep/interface/builder.rb +1 -0
  10. data/lib/steep/interface/function.rb +14 -6
  11. data/lib/steep/interface/method_type.rb +15 -7
  12. data/lib/steep/project/pattern.rb +1 -2
  13. data/lib/steep/server/interaction_worker.rb +6 -0
  14. data/lib/steep/server/lsp_formatter.rb +2 -0
  15. data/lib/steep/services/completion_provider.rb +1 -1
  16. data/lib/steep/services/file_loader.rb +15 -20
  17. data/lib/steep/services/signature_help_provider.rb +11 -9
  18. data/lib/steep/signature/validator.rb +1 -1
  19. data/lib/steep/subtyping/check.rb +15 -6
  20. data/lib/steep/subtyping/variable_variance.rb +3 -3
  21. data/lib/steep/type_construction.rb +185 -149
  22. data/lib/steep/type_inference/block_params.rb +1 -1
  23. data/lib/steep/type_inference/logic_type_interpreter.rb +2 -1
  24. data/lib/steep/type_inference/method_params.rb +16 -0
  25. data/lib/steep/type_inference/send_args.rb +5 -2
  26. data/lib/steep/version.rb +1 -1
  27. data/sig/steep/ast/types/factory.rbs +2 -2
  28. data/sig/steep/interface/builder.rbs +12 -53
  29. data/sig/steep/interface/function.rbs +5 -4
  30. data/sig/steep/services/signature_help_provider.rbs +1 -1
  31. data/sig/steep/subtyping/variable_variance.rbs +1 -1
  32. data/sig/steep/type_inference/block_params.rbs +1 -1
  33. data/sig/steep/type_inference/method_params.rbs +3 -3
  34. data/steep.gemspec +1 -1
  35. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c30f769d118a31c069ae146f976dc3df96b71acfa50659e6f03b00bdc1624da7
4
- data.tar.gz: '064953d68e749654f069f2ea215746366a58506406ec5977826f5cf73552f779'
3
+ metadata.gz: 17795ed14e183d6e8858e6ea8f57f71dbd3cdced0e4d9cf7e43c646188e486cd
4
+ data.tar.gz: 7005e9d96f44f23a47f1844597b86fd3d774f000b1de5cf100d235e68c56a0b5
5
5
  SHA512:
6
- metadata.gz: 4ce31d8368b84b72284eb331606a6f1c15b3843a2c13a01770bcac35c4f9fa35ab5a62617a4d13c913c482b1775fc043265a8fbdb5a58e7598e9ad92a2246fda
7
- data.tar.gz: 206491dcd015533b092afe61277f48e28e288693c9ffadaa85aa855b0616ab9f64ba7001b297a7387432fec3492aed55f16ac5ebba3b379cb7bf79575249700c
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.3)
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,23 +33,23 @@ GEM
33
33
  tzinfo (~> 2.0)
34
34
  ast (2.4.2)
35
35
  base64 (0.2.0)
36
- bigdecimal (3.1.7)
36
+ bigdecimal (3.1.8)
37
37
  concurrent-ruby (1.2.3)
38
38
  connection_pool (2.4.1)
39
39
  csv (3.3.0)
40
- debug (1.9.1)
40
+ debug (1.9.2)
41
41
  irb (~> 1.10)
42
42
  reline (>= 0.3.8)
43
43
  drb (2.2.1)
44
44
  ffi (1.16.3)
45
45
  fileutils (1.7.2)
46
- i18n (1.14.4)
46
+ i18n (1.14.5)
47
47
  concurrent-ruby (~> 1.0)
48
48
  io-console (0.7.2)
49
- irb (1.12.0)
50
- rdoc
49
+ irb (1.13.1)
50
+ rdoc (>= 4.0.0)
51
51
  reline (>= 0.4.2)
52
- json (2.7.1)
52
+ json (2.7.2)
53
53
  language_server-protocol (3.17.0.3)
54
54
  listen (3.9.0)
55
55
  rb-fsevent (~> 0.10, >= 0.10.3)
@@ -61,22 +61,22 @@ GEM
61
61
  minitest-slow_test (0.2.0)
62
62
  minitest (>= 5.0)
63
63
  mutex_m (0.2.0)
64
- parser (3.3.0.5)
64
+ parser (3.3.1.0)
65
65
  ast (~> 2.4.1)
66
66
  racc
67
67
  psych (5.1.2)
68
68
  stringio
69
69
  racc (1.7.3)
70
70
  rainbow (3.1.1)
71
- rake (13.1.0)
71
+ rake (13.2.1)
72
72
  rb-fsevent (0.11.2)
73
73
  rb-inotify (0.10.1)
74
74
  ffi (~> 1.0)
75
- rbs (3.4.4)
75
+ rbs (3.5.0.pre.2)
76
76
  abbrev
77
77
  rdoc (6.6.3.1)
78
78
  psych (>= 4.0.0)
79
- reline (0.4.3)
79
+ reline (0.5.6)
80
80
  io-console (~> 0.5)
81
81
  securerandom (0.3.1)
82
82
  stackprof (0.2.26)
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.
@@ -14,16 +14,16 @@ GEM
14
14
  tzinfo (~> 2.0)
15
15
  ast (2.4.2)
16
16
  base64 (0.2.0)
17
- bigdecimal (3.1.7)
17
+ bigdecimal (3.1.8)
18
18
  concurrent-ruby (1.2.3)
19
19
  connection_pool (2.4.1)
20
20
  csv (3.3.0)
21
21
  drb (2.2.1)
22
22
  ffi (1.16.3)
23
23
  fileutils (1.7.2)
24
- i18n (1.14.4)
24
+ i18n (1.14.5)
25
25
  concurrent-ruby (~> 1.0)
26
- json (2.7.1)
26
+ json (2.7.2)
27
27
  language_server-protocol (3.17.0.3)
28
28
  listen (3.9.0)
29
29
  rb-fsevent (~> 0.10, >= 0.10.3)
@@ -31,7 +31,7 @@ GEM
31
31
  logger (1.6.0)
32
32
  minitest (5.22.3)
33
33
  mutex_m (0.2.0)
34
- parser (3.3.0.5)
34
+ parser (3.3.1.0)
35
35
  ast (~> 2.4.1)
36
36
  racc
37
37
  racc (1.7.3)
@@ -42,7 +42,7 @@ GEM
42
42
  rbs (3.4.4)
43
43
  abbrev
44
44
  securerandom (0.3.1)
45
- steep (1.7.0.dev.2)
45
+ steep (1.7.0.dev.3)
46
46
  activesupport (>= 5.1)
47
47
  concurrent-ruby (>= 1.1.10)
48
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)
@@ -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
@@ -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
  )
@@ -62,6 +62,7 @@ module Steep
62
62
  def shape(type, config)
63
63
  Steep.logger.tagged "shape(#{type})" do
64
64
  if shape = raw_shape(type, config)
65
+ # Optimization that skips unnecesary substittuion
65
66
  if type.free_variables.include?(AST::Types::Self.instance)
66
67
  shape
67
68
  else
@@ -1008,7 +1008,7 @@ module Steep
1008
1008
  def free_variables
1009
1009
  @fvs ||= Set[].tap do |fvs|
1010
1010
  # @type var fvs: Set[AST::Types::variable]
1011
- fvs.merge(params.free_variables)
1011
+ fvs.merge(params.free_variables) if params
1012
1012
  fvs.merge(return_type.free_variables)
1013
1013
  end
1014
1014
  end
@@ -1016,7 +1016,7 @@ module Steep
1016
1016
  def subst(s)
1017
1017
  return self if s.empty?
1018
1018
 
1019
- ps = params.subst(s)
1019
+ ps = params.subst(s) if params
1020
1020
  ret = return_type.subst(s)
1021
1021
 
1022
1022
  if ps == params && ret == return_type
@@ -1032,7 +1032,7 @@ module Steep
1032
1032
 
1033
1033
  def each_type(&block)
1034
1034
  if block
1035
- params.each_type(&block)
1035
+ params&.each_type(&block)
1036
1036
  yield return_type
1037
1037
  else
1038
1038
  enum_for :each_type
@@ -1043,7 +1043,7 @@ module Steep
1043
1043
 
1044
1044
  def map_type(&block)
1045
1045
  Function.new(
1046
- params: params.map_type(&block),
1046
+ params: params&.map_type(&block),
1047
1047
  return_type: yield(return_type),
1048
1048
  location: location
1049
1049
  )
@@ -1058,11 +1058,19 @@ module Steep
1058
1058
  end
1059
1059
 
1060
1060
  def to_s
1061
- "#{params} -> #{return_type}"
1061
+ if params
1062
+ "#{params} -> #{return_type}"
1063
+ else
1064
+ "(?) -> #{return_type}"
1065
+ end
1062
1066
  end
1063
1067
 
1064
1068
  def closed?
1065
- params.closed? && return_type.free_variables.empty?
1069
+ if params
1070
+ params.closed? && return_type.free_variables.empty?
1071
+ else
1072
+ return_type.free_variables.empty?
1073
+ end
1066
1074
  end
1067
1075
  end
1068
1076
  end
@@ -61,7 +61,7 @@ module Steep
61
61
  type.each_type(&block)
62
62
  if block()
63
63
  yield(block().self_type) if block().self_type
64
- block().type.params.each_type(&block)
64
+ block().type.params&.each_type(&block)
65
65
  yield(block().type.return_type)
66
66
  end
67
67
  else
@@ -119,7 +119,7 @@ module Steep
119
119
  self.class.new(
120
120
  type_params: type_params,
121
121
  type: Function.new(
122
- params: type.params.subst(s1) + other.type.params.subst(s2),
122
+ params: type.params && other.type.params ? type.params.subst(s1) + other.type.params.subst(s2) : nil,
123
123
  return_type: AST::Types::Union.build(
124
124
  types: [type.return_type.subst(s1), other.type.return_type.subst(s2)]
125
125
  ),
@@ -250,10 +250,13 @@ module Steep
250
250
  nil
251
251
  end
252
252
 
253
- # Return when the two block parameters are imcompatible.
254
- return unless b.type.params & ob.type.params
255
-
256
- block_params = b.type.params | ob.type.params or return
253
+ if b.type.params && ob.type.params
254
+ # Return when the two block parameters are imcompatible.
255
+ return unless b.type.params & ob.type.params
256
+ block_params = b.type.params | ob.type.params or return
257
+ else
258
+ block_params = b.type.params || ob.type.params
259
+ end
257
260
 
258
261
  block_return_type = AST::Types::Intersection.build(types: [b.type.return_type, ob.type.return_type])
259
262
  block_type = Function.new(params: block_params, return_type: block_return_type, location: nil)
@@ -285,7 +288,12 @@ module Steep
285
288
  def &(other)
286
289
  return self if self == other
287
290
 
288
- params = self.type.params | other.type.params or return
291
+ if self.type.params && other.type.params
292
+ params = self.type.params | other.type.params or return
293
+ else
294
+ params = self.type.params || other.type.params
295
+ end
296
+
289
297
  block =
290
298
  case
291
299
  when (b = self.block) && (ob = other.block)
@@ -46,10 +46,9 @@ module Steep
46
46
 
47
47
  def test_string(path, patterns, prefixes)
48
48
  string = path.to_s
49
- extension = path.extname
50
49
 
51
50
  patterns.any? {|pat| File.fnmatch(pat, string, File::FNM_PATHNAME) } ||
52
- prefixes.any? {|prefix| string.start_with?(prefix) && extension == ext }
51
+ prefixes.any? {|prefix| File.fnmatch("#{prefix}**/*#{ext}", string, File::FNM_PATHNAME) }
53
52
  end
54
53
  end
55
54
  end
@@ -90,6 +90,12 @@ module Steep
90
90
  collect_changes(request)
91
91
  queue_job ApplyChangeJob.new
92
92
 
93
+ when "$/file/reset"
94
+ uri = request[:params][:uri]
95
+ text = request[:params][:content]
96
+ reset_change(uri: uri, text: text)
97
+ queue_job ApplyChangeJob.new
98
+
93
99
  when "textDocument/hover"
94
100
  id = request[:id]
95
101
 
@@ -263,6 +263,8 @@ module Steep
263
263
  <<~MD
264
264
  **Keyword argument**: `#{item.identifier}`
265
265
  MD
266
+ else
267
+ raise
266
268
  end
267
269
  end
268
270
 
@@ -740,7 +740,7 @@ module Steep
740
740
  if method = shape.methods[call.method_name]
741
741
  method.method_types.each.with_index do |method_type, i|
742
742
  defn = method_type.method_decls.to_a[0]&.method_def
743
- if defn
743
+ if defn && defn.type.type
744
744
  range = range_for(position, prefix: prefix)
745
745
  kwargs = argument_nodes.find { |arg| arg.type == :kwargs }&.children || []
746
746
  used_kwargs = kwargs.filter_map { |arg| arg.type == :pair && arg.children.first.children.first }
@@ -12,30 +12,25 @@ module Steep
12
12
  pats = commandline_patterns.empty? ? pattern.patterns : commandline_patterns
13
13
 
14
14
  pats.each do |path|
15
- absolute_path = base_dir + path
16
-
17
- if absolute_path.file?
18
- relative_path = absolute_path.relative_path_from(base_dir)
19
- if pattern =~ relative_path
20
- yield relative_path
21
- end
22
- else
23
- files = if absolute_path.directory?
24
- Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
25
- else
26
- Pathname.glob(absolute_path.to_s)
27
- end
28
-
29
- files.sort.each do |source_path|
30
- if source_path.file?
31
- relative_path = source_path.relative_path_from(base_dir)
32
- unless pattern.ignore?(relative_path)
33
- yield relative_path
15
+ Pathname.glob((base_dir + path).to_s).each do |absolute_path|
16
+ if absolute_path.file?
17
+ relative_path = absolute_path.relative_path_from(base_dir)
18
+ if pattern =~ relative_path
19
+ yield relative_path
20
+ end
21
+ else
22
+ files = Pathname.glob("#{absolute_path}/**/*#{pattern.ext}")
23
+
24
+ files.sort.each do |source_path|
25
+ if source_path.file?
26
+ relative_path = source_path.relative_path_from(base_dir)
27
+ unless pattern.ignore?(relative_path)
28
+ yield relative_path
29
+ end
34
30
  end
35
31
  end
36
32
  end
37
33
  end
38
-
39
34
  end
40
35
  else
41
36
  enum_for :each_path_in_patterns, pattern, commandline_patterns
@@ -7,15 +7,17 @@ module Steep
7
7
  # @implements Item
8
8
 
9
9
  def parameters
10
- arguments = [] #: Array[String]
11
- arguments.push(*method_type.type.required_positionals.map(&:to_s))
12
- arguments.push(*method_type.type.optional_positionals.map {|p| "?#{p}"})
13
- arguments.push("*#{self.method_type.type.rest_positionals}") if method_type.type.rest_positionals
14
- arguments.push(*method_type.type.trailing_positionals.map(&:to_s))
15
- arguments.push(*method_type.type.required_keywords.map {|name, param| "#{name}: #{param}" })
16
- arguments.push(*method_type.type.optional_keywords.map {|name, param| "?#{name}: #{param}" })
17
- arguments.push("**#{method_type.type.rest_keywords}") if method_type.type.rest_keywords
18
- arguments
10
+ if method_type.type.is_a?(RBS::Types::Function)
11
+ arguments = [] #: Array[String]
12
+ arguments.push(*method_type.type.required_positionals.map(&:to_s))
13
+ arguments.push(*method_type.type.optional_positionals.map {|p| "?#{p}"})
14
+ arguments.push("*#{self.method_type.type.rest_positionals}") if method_type.type.rest_positionals
15
+ arguments.push(*method_type.type.trailing_positionals.map(&:to_s))
16
+ arguments.push(*method_type.type.required_keywords.map {|name, param| "#{name}: #{param}" })
17
+ arguments.push(*method_type.type.optional_keywords.map {|name, param| "?#{name}: #{param}" })
18
+ arguments.push("**#{method_type.type.rest_keywords}") if method_type.type.rest_keywords
19
+ arguments
20
+ end
19
21
  end
20
22
  end
21
23
 
@@ -134,7 +134,7 @@ module Steep
134
134
  end
135
135
 
136
136
  def validate_type(type)
137
- Steep.logger.debug "#{Location.to_string type.location}: Validating #{type}..."
137
+ Steep.logger.debug { "#{Location.to_string type.location}: Validating #{type}..." }
138
138
 
139
139
  validator.validate_type(type, context: nil)
140
140
  validate_type_application(type)