steep 0.23.0 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/bin/smoke_runner.rb +3 -4
  4. data/lib/steep.rb +4 -3
  5. data/lib/steep/annotation_parser.rb +2 -4
  6. data/lib/steep/ast/builtin.rb +11 -21
  7. data/lib/steep/ast/types.rb +5 -3
  8. data/lib/steep/ast/types/any.rb +1 -3
  9. data/lib/steep/ast/types/boolean.rb +1 -3
  10. data/lib/steep/ast/types/bot.rb +1 -3
  11. data/lib/steep/ast/types/class.rb +2 -2
  12. data/lib/steep/ast/types/factory.rb +249 -89
  13. data/lib/steep/ast/types/helper.rb +6 -0
  14. data/lib/steep/ast/types/instance.rb +2 -2
  15. data/lib/steep/ast/types/intersection.rb +20 -13
  16. data/lib/steep/ast/types/literal.rb +1 -3
  17. data/lib/steep/ast/types/logic.rb +63 -0
  18. data/lib/steep/ast/types/name.rb +15 -67
  19. data/lib/steep/ast/types/nil.rb +1 -3
  20. data/lib/steep/ast/types/proc.rb +5 -2
  21. data/lib/steep/ast/types/record.rb +9 -4
  22. data/lib/steep/ast/types/self.rb +1 -1
  23. data/lib/steep/ast/types/top.rb +1 -3
  24. data/lib/steep/ast/types/tuple.rb +5 -3
  25. data/lib/steep/ast/types/union.rb +16 -9
  26. data/lib/steep/ast/types/var.rb +2 -2
  27. data/lib/steep/ast/types/void.rb +1 -3
  28. data/lib/steep/drivers/check.rb +4 -0
  29. data/lib/steep/errors.rb +14 -0
  30. data/lib/steep/interface/interface.rb +5 -62
  31. data/lib/steep/interface/method_type.rb +394 -93
  32. data/lib/steep/interface/substitution.rb +48 -6
  33. data/lib/steep/module_helper.rb +25 -0
  34. data/lib/steep/project/completion_provider.rb +48 -51
  35. data/lib/steep/project/file.rb +3 -3
  36. data/lib/steep/project/hover_content.rb +4 -6
  37. data/lib/steep/project/target.rb +5 -2
  38. data/lib/steep/server/base_worker.rb +5 -3
  39. data/lib/steep/server/code_worker.rb +2 -0
  40. data/lib/steep/server/master.rb +10 -1
  41. data/lib/steep/signature/validator.rb +3 -3
  42. data/lib/steep/source.rb +4 -3
  43. data/lib/steep/subtyping/check.rb +46 -59
  44. data/lib/steep/subtyping/constraints.rb +8 -0
  45. data/lib/steep/type_construction.rb +771 -513
  46. data/lib/steep/type_inference/block_params.rb +5 -0
  47. data/lib/steep/type_inference/constant_env.rb +3 -6
  48. data/lib/steep/type_inference/context.rb +8 -0
  49. data/lib/steep/type_inference/context_array.rb +4 -3
  50. data/lib/steep/type_inference/logic.rb +31 -0
  51. data/lib/steep/type_inference/logic_type_interpreter.rb +219 -0
  52. data/lib/steep/type_inference/type_env.rb +2 -2
  53. data/lib/steep/typing.rb +7 -0
  54. data/lib/steep/version.rb +1 -1
  55. data/smoke/alias/a.rb +1 -1
  56. data/smoke/case/a.rb +1 -1
  57. data/smoke/hash/d.rb +1 -1
  58. data/smoke/if/a.rb +1 -1
  59. data/smoke/module/a.rb +1 -1
  60. data/smoke/rescue/a.rb +4 -13
  61. data/smoke/type_case/a.rb +0 -7
  62. data/steep.gemspec +2 -2
  63. metadata +10 -10
  64. data/lib/steep/ast/method_type.rb +0 -126
  65. data/lib/steep/ast/namespace.rb +0 -80
  66. data/lib/steep/names.rb +0 -86
@@ -56,6 +56,11 @@ module Steep
56
56
 
57
57
  node.children.each do |arg|
58
58
  var = arg.children.first
59
+
60
+ if var.is_a?(::AST::Node)
61
+ return
62
+ end
63
+
59
64
  type = annotations.var_type(lvar: var.name)
60
65
 
61
66
  case arg.type
@@ -6,7 +6,7 @@ module Steep
6
6
  attr_reader :factory
7
7
  attr_reader :table
8
8
 
9
- # ConstantEnv receives an Names::Module as a context, not a Namespace, because this is a simulation of Ruby.
9
+ # ConstantEnv receives an TypeName as a context, not a Namespace, because this is a simulation of Ruby.
10
10
  # Any namespace is a module or class.
11
11
  def initialize(factory:, context:)
12
12
  @cache = {}
@@ -17,16 +17,13 @@ module Steep
17
17
 
18
18
  def lookup(name)
19
19
  cache[name] ||= begin
20
- constant = table.resolve_constant_reference(
21
- factory.type_name_1(name),
22
- context: context.map {|namespace| factory.namespace_1(namespace) }
23
- )
20
+ constant = table.resolve_constant_reference(name, context: context)
24
21
 
25
22
  if constant
26
23
  factory.type(constant.type)
27
24
  end
28
25
  rescue => exn
29
- Steep.logger.error "Looking up a constant failed: name=#{name}, context=[#{context.join(", ")}], error=#{exn.inspect}"
26
+ Steep.logger.debug "Looking up a constant failed: name=#{name}, context=[#{context.join(", ")}], error=#{exn.inspect}"
30
27
  nil
31
28
  end
32
29
  end
@@ -70,6 +70,14 @@ module Steep
70
70
  def const_context
71
71
  const_env.context
72
72
  end
73
+
74
+ def class_variables
75
+ if module_definition
76
+ @class_variables ||= module_definition.class_variables.transform_values do |var_def|
77
+ var_def.type
78
+ end
79
+ end
80
+ end
73
81
  end
74
82
 
75
83
  attr_reader :method_context
@@ -35,12 +35,13 @@ module Steep
35
35
 
36
36
  def insert_context(range, context:, entry: self.root)
37
37
  entry.sub_entries.each do |sub|
38
- next if sub.range.begin < range.begin && range.end <= sub.range.end
39
- next if range.begin < sub.range.begin && sub.range.end <= range.end
38
+ next if sub.range.begin <= range.begin && range.end <= sub.range.end
39
+ next if range.begin <= sub.range.begin && sub.range.end <= range.end
40
40
  next if range.end <= sub.range.begin
41
41
  next if sub.range.end <= range.begin
42
42
 
43
- raise "Range crossing: sub range=#{sub.range}, new range=#{range}"
43
+ Steep.logger.error { "Range crossing: sub range=#{sub.range}, new range=#{range}" }
44
+ raise
44
45
  end
45
46
 
46
47
  sup = entry.sub_entries.find do |sub|
@@ -47,6 +47,37 @@ module Steep
47
47
  f.merge([node])
48
48
  ]
49
49
 
50
+ when :masgn
51
+ lhs, rhs = node.children
52
+
53
+ lt, lf = nodes(node: lhs)
54
+ rt, rf = nodes(node: rhs)
55
+
56
+ [
57
+ (lt + rt).merge([node]),
58
+ (lf + rf).merge([node])
59
+ ]
60
+
61
+ when :mlhs
62
+ nodes = [node]
63
+
64
+ node.children.each do |child|
65
+ case child.type
66
+ when :lvasgn
67
+ nodes << child
68
+ when :splat
69
+ if node.children[0].type == :lvasgn
70
+ nodes << child
71
+ nodes << child.children[0]
72
+ end
73
+ end
74
+ end
75
+
76
+ [
77
+ Result.new(nodes),
78
+ Result.new(nodes)
79
+ ]
80
+
50
81
  when :and
51
82
  lhs, rhs = node.children
52
83
 
@@ -0,0 +1,219 @@
1
+ module Steep
2
+ module TypeInference
3
+ class LogicTypeInterpreter
4
+ attr_reader :subtyping
5
+ attr_reader :typing
6
+
7
+ def initialize(subtyping:, typing:)
8
+ @subtyping = subtyping
9
+ @typing = typing
10
+ end
11
+
12
+ def factory
13
+ subtyping.factory
14
+ end
15
+
16
+ def guess_type_from_method(node)
17
+ if node.type == :send
18
+ method = node.children[1]
19
+ case method
20
+ when :is_a?, :kind_of?, :instance_of?
21
+ AST::Types::Logic::ReceiverIsArg.new
22
+ when :nil?
23
+ AST::Types::Logic::ReceiverIsNil.new
24
+ when :!
25
+ AST::Types::Logic::Not.new
26
+ when :===
27
+ AST::Types::Logic::ArgIsReceiver.new
28
+ end
29
+ end
30
+ end
31
+
32
+ def eval(env:, type:, node:)
33
+ value_node, vars = decompose_value(node)
34
+
35
+ truthy_env = env
36
+ falsy_env = env
37
+
38
+ if type.is_a?(AST::Types::Any)
39
+ type = guess_type_from_method(node) || type
40
+ end
41
+
42
+ if type.is_a?(AST::Types::Logic::Base)
43
+ vars.each do |var_name|
44
+ truthy_env = truthy_env.assign!(var_name, node: node, type: AST::Builtin.true_type)
45
+ falsy_env = truthy_env.assign!(var_name, node: node, type: AST::Builtin.false_type)
46
+ end
47
+
48
+ case type
49
+ when AST::Types::Logic::ReceiverIsNil
50
+ case value_node.type
51
+ when :send
52
+ receiver = value_node.children[0]
53
+
54
+ if receiver
55
+ _, receiver_vars = decompose_value(receiver)
56
+
57
+ receiver_vars.each do |receiver_var|
58
+ var_type = env[receiver_var]
59
+ truthy_type, falsy_type = factory.unwrap_optional(var_type)
60
+
61
+ truthy_env = truthy_env.assign!(receiver_var, node: node, type: falsy_type || AST::Builtin.nil_type)
62
+ falsy_env = falsy_env.assign!(receiver_var, node: node, type: truthy_type)
63
+ end
64
+ end
65
+ end
66
+ when AST::Types::Logic::ReceiverIsArg
67
+ case value_node.type
68
+ when :send
69
+ receiver, _, arg = value_node.children
70
+
71
+ if receiver
72
+ _, receiver_vars = decompose_value(receiver)
73
+ arg_type = typing.type_of(node: arg)
74
+
75
+ if arg_type.is_a?(AST::Types::Name::Singleton)
76
+ receiver_vars.each do |var_name|
77
+ var_type = env[var_name]
78
+ truthy_type, falsy_type = type_case_select(var_type, arg_type.name)
79
+
80
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
81
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ when AST::Types::Logic::ArgIsReceiver
87
+ case value_node.type
88
+ when :send
89
+ receiver, _, arg = value_node.children
90
+
91
+ if receiver
92
+ _, arg_vars = decompose_value(arg)
93
+ receiver_type = typing.type_of(node: receiver)
94
+
95
+ if receiver_type.is_a?(AST::Types::Name::Singleton)
96
+ arg_vars.each do |var_name|
97
+ var_type = env[var_name]
98
+ truthy_type, falsy_type = type_case_select(var_type, receiver_type.name)
99
+
100
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
101
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ when AST::Types::Logic::Not
107
+ receiver, * = value_node.children
108
+ receiver_type = typing.type_of(node: receiver)
109
+ falsy_env, truthy_env = eval(env: env, type: receiver_type, node: receiver)
110
+ end
111
+ else
112
+ _, vars = decompose_value(node)
113
+
114
+ vars.each do |var_name|
115
+ var_type = env[var_name]
116
+ truthy_type, falsy_type = factory.unwrap_optional(var_type)
117
+
118
+ if falsy_type
119
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
120
+ falsy_env = falsy_env.assign!(var_name, node: node, type: falsy_type)
121
+ else
122
+ truthy_env = truthy_env.assign!(var_name, node: node, type: truthy_type)
123
+ falsy_env = falsy_env.assign!(var_name, node: node, type: truthy_type)
124
+ end
125
+ end
126
+ end
127
+
128
+ [truthy_env, falsy_env]
129
+ end
130
+
131
+ def decompose_value(node)
132
+ case node.type
133
+ when :lvar
134
+ [node, Set[node.children[0].name]]
135
+ when :masgn
136
+ lhs, rhs = node.children
137
+ lhs_vars = lhs.children.select {|m| m.type == :lvasgn }.map {|m| m.children[0].name }
138
+ val, vars = decompose_value(rhs)
139
+ [val, vars + lhs_vars]
140
+ when :lvasgn
141
+ var, rhs = node.children
142
+ val, vars = decompose_value(rhs)
143
+ [val, vars + [var.name]]
144
+ when :begin
145
+ decompose_value(node.children.last)
146
+ when :and
147
+ left, right = node.children
148
+ _, left_vars = decompose_value(left)
149
+ val, right_vars = decompose_value(right)
150
+ [val, left_vars + right_vars]
151
+ else
152
+ [node, Set[]]
153
+ end
154
+ end
155
+
156
+ def type_case_select(type, klass)
157
+ truth_types, false_types = type_case_select0(type, klass)
158
+
159
+ [
160
+ AST::Types::Union.build(types: truth_types),
161
+ AST::Types::Union.build(types: false_types)
162
+ ]
163
+ end
164
+
165
+ def type_case_select0(type, klass)
166
+ instance_type = factory.instance_type(klass)
167
+
168
+ case type
169
+ when AST::Types::Union
170
+ truthy_types = []
171
+ falsy_types = []
172
+
173
+ type.types.each do |ty|
174
+ truths, falses = type_case_select0(ty, klass)
175
+
176
+ if truths.empty?
177
+ falsy_types.push(ty)
178
+ else
179
+ truthy_types.push(*truths)
180
+ falsy_types.push(*falses)
181
+ end
182
+ end
183
+
184
+ [truthy_types, falsy_types]
185
+
186
+ when AST::Types::Name::Instance
187
+ relation = Subtyping::Relation.new(sub_type: type, super_type: instance_type)
188
+ if subtyping.check(relation, constraints: Subtyping::Constraints.empty, self_type: AST::Types::Self.new).success?
189
+ [
190
+ [type],
191
+ []
192
+ ]
193
+ else
194
+ [
195
+ [],
196
+ [type]
197
+ ]
198
+ end
199
+
200
+ when AST::Types::Name::Alias
201
+ ty = factory.expand_alias(type)
202
+ type_case_select0(ty, klass)
203
+
204
+ when AST::Types::Any, AST::Types::Top
205
+ [
206
+ [instance_type],
207
+ [type]
208
+ ]
209
+
210
+ else
211
+ [
212
+ [],
213
+ [type]
214
+ ]
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -57,7 +57,7 @@ module Steep
57
57
  end
58
58
  end
59
59
 
60
- # @type method assert: (const: Names::Module) { () -> void } -> AST::Type
60
+ # @type method assert: (const: TypeName) { () -> void } -> AST::Type
61
61
  # | (gvar: Symbol) { () -> void } -> AST::Type
62
62
  # | (ivar: Symbol) { () -> void } -> AST::Type
63
63
  def get(const: nil, gvar: nil, ivar: nil)
@@ -98,7 +98,7 @@ module Steep
98
98
  end
99
99
  end
100
100
 
101
- # @type method assign: (const: Names::Module, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
101
+ # @type method assign: (const: TypeName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
102
102
  # | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
103
103
  # | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
104
104
  def assign(const: nil, gvar: nil, ivar: nil, type:, self_type:, &block)
@@ -126,6 +126,13 @@ module Steep
126
126
  end_pos = node.loc.end.begin_pos
127
127
  add_context(begin_pos..end_pos, context: context)
128
128
 
129
+ when :for
130
+ _, collection, _ = node.children
131
+
132
+ begin_pos = collection.loc.expression.end_pos
133
+ end_pos = node.loc.end.begin_pos
134
+
135
+ add_context(begin_pos..end_pos, context: context)
129
136
  else
130
137
  raise "Unexpected node for insert_context: #{node.type}"
131
138
  end
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.23.0"
2
+ VERSION = "0.29.0"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  # @type var x: foo
2
2
  x = ""
3
3
 
4
- # !expects ArgumentTypeMismatch: receiver=(::Integer | ::String), expected=::string, actual=::Integer
4
+ # !expects* UnresolvedOverloading: receiver=(::String | ::Integer), method_name=+,
5
5
  x + 123
6
6
 
7
7
  # @type var y: bar
@@ -1,6 +1,6 @@
1
1
  # @type var a: Integer
2
2
 
3
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::String] | ::Integer | ::String | nil)
3
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::Array[::String] | nil | ::String)
4
4
  a = case 1
5
5
  when 2
6
6
  1
@@ -2,5 +2,5 @@
2
2
 
3
3
  params = { id: 30, name: "Matz" }
4
4
 
5
- # !expects IncompatibleAssignment: lhs_type={ :name => ::String, :id => ::Integer }, rhs_type={ :id => ::String, :name => ::String, :email => ::String }
5
+ # !expects IncompatibleAssignment: lhs_type={ :id => ::Integer, :name => ::String }, rhs_type={ :email => ::String, :id => ::String, :name => ::String }
6
6
  params = { id: "30", name: "foo", email: "matsumoto@soutaro.com" }
@@ -13,7 +13,7 @@ else
13
13
  "baz"
14
14
  end
15
15
 
16
- # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=(::Integer | ::String)
16
+ # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=(::String | ::Integer)
17
17
  a = if z
18
18
  "foofoo"
19
19
  else
@@ -13,7 +13,7 @@ module A
13
13
  # !expects IncompatibleAssignment: lhs_type=::String, rhs_type=::Integer
14
14
  s = n
15
15
 
16
- # !expects NoMethodError: type=(::A & ::Object & ::_Each2[::Integer, ::A]), method=foo
16
+ # !expects NoMethodError: type=(::Object & ::_Each2[::Integer, ::A] & ::A), method=foo
17
17
  foo()
18
18
 
19
19
  n
@@ -1,6 +1,6 @@
1
1
  # @type var a: Integer
2
2
 
3
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String)
3
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Integer)
4
4
  a = begin
5
5
  'foo'
6
6
  rescue
@@ -9,12 +9,12 @@ a = begin
9
9
 
10
10
  # @type var b: Integer
11
11
 
12
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String)
12
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Integer)
13
13
  b = 'foo' rescue 1
14
14
 
15
15
  # @type var c: Integer
16
16
 
17
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Integer | ::String | ::Symbol)
17
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::String | ::Symbol | ::Integer)
18
18
  c = begin
19
19
  'foo'
20
20
  rescue RuntimeError
@@ -23,18 +23,9 @@ c = begin
23
23
  1
24
24
  end
25
25
 
26
- # @type var d: Integer
27
-
28
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=::String
29
- d = begin
30
- 1
31
- else
32
- 'foo'
33
- end
34
-
35
26
  # @type var e: Integer
36
27
 
37
- # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::Integer] | ::Integer | ::Symbol)
28
+ # !expects IncompatibleAssignment: lhs_type=::Integer, rhs_type=(::Array[::Integer] | ::Symbol | ::Integer)
38
29
  e = begin
39
30
  'foo'
40
31
  rescue RuntimeError