steep 0.1.0.pre2 → 0.1.0

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 (119) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/README.md +146 -33
  4. data/bin/smoke_runner.rb +43 -10
  5. data/lib/steep/ast/annotation/collection.rb +93 -0
  6. data/lib/steep/ast/annotation.rb +131 -0
  7. data/lib/steep/ast/buffer.rb +47 -0
  8. data/lib/steep/ast/location.rb +82 -0
  9. data/lib/steep/ast/method_type.rb +116 -0
  10. data/lib/steep/ast/signature/class.rb +33 -0
  11. data/lib/steep/ast/signature/const.rb +17 -0
  12. data/lib/steep/ast/signature/env.rb +123 -0
  13. data/lib/steep/ast/signature/extension.rb +21 -0
  14. data/lib/steep/ast/signature/gvar.rb +17 -0
  15. data/lib/steep/ast/signature/interface.rb +31 -0
  16. data/lib/steep/ast/signature/members.rb +71 -0
  17. data/lib/steep/ast/signature/module.rb +21 -0
  18. data/lib/steep/ast/type_params.rb +13 -0
  19. data/lib/steep/ast/types/any.rb +39 -0
  20. data/lib/steep/ast/types/bot.rb +39 -0
  21. data/lib/steep/ast/types/class.rb +35 -0
  22. data/lib/steep/ast/types/helper.rb +21 -0
  23. data/lib/steep/ast/types/instance.rb +39 -0
  24. data/lib/steep/ast/types/intersection.rb +74 -0
  25. data/lib/steep/ast/types/name.rb +124 -0
  26. data/lib/steep/ast/types/self.rb +39 -0
  27. data/lib/steep/ast/types/top.rb +39 -0
  28. data/lib/steep/ast/types/union.rb +74 -0
  29. data/lib/steep/ast/types/var.rb +57 -0
  30. data/lib/steep/ast/types/void.rb +35 -0
  31. data/lib/steep/cli.rb +28 -1
  32. data/lib/steep/drivers/annotations.rb +32 -0
  33. data/lib/steep/drivers/check.rb +53 -77
  34. data/lib/steep/drivers/scaffold.rb +303 -0
  35. data/lib/steep/drivers/utils/each_signature.rb +66 -0
  36. data/lib/steep/drivers/utils/validator.rb +115 -0
  37. data/lib/steep/drivers/validate.rb +39 -0
  38. data/lib/steep/errors.rb +291 -19
  39. data/lib/steep/interface/abstract.rb +44 -0
  40. data/lib/steep/interface/builder.rb +470 -0
  41. data/lib/steep/interface/instantiated.rb +126 -0
  42. data/lib/steep/interface/ivar_chain.rb +26 -0
  43. data/lib/steep/interface/method.rb +60 -0
  44. data/lib/steep/{interface.rb → interface/method_type.rb} +111 -100
  45. data/lib/steep/interface/substitution.rb +65 -0
  46. data/lib/steep/module_name.rb +116 -0
  47. data/lib/steep/parser.rb +1314 -814
  48. data/lib/steep/parser.y +536 -175
  49. data/lib/steep/source.rb +220 -25
  50. data/lib/steep/subtyping/check.rb +673 -0
  51. data/lib/steep/subtyping/constraints.rb +275 -0
  52. data/lib/steep/subtyping/relation.rb +41 -0
  53. data/lib/steep/subtyping/result.rb +126 -0
  54. data/lib/steep/subtyping/trace.rb +48 -0
  55. data/lib/steep/subtyping/variable_occurrence.rb +49 -0
  56. data/lib/steep/subtyping/variable_variance.rb +69 -0
  57. data/lib/steep/type_construction.rb +1630 -524
  58. data/lib/steep/type_inference/block_params.rb +100 -0
  59. data/lib/steep/type_inference/constant_env.rb +55 -0
  60. data/lib/steep/type_inference/send_args.rb +222 -0
  61. data/lib/steep/type_inference/type_env.rb +226 -0
  62. data/lib/steep/type_name.rb +27 -7
  63. data/lib/steep/typing.rb +4 -0
  64. data/lib/steep/version.rb +1 -1
  65. data/lib/steep.rb +71 -16
  66. data/smoke/and/a.rb +4 -2
  67. data/smoke/array/a.rb +4 -5
  68. data/smoke/array/b.rb +4 -4
  69. data/smoke/block/a.rb +2 -2
  70. data/smoke/block/a.rbi +2 -0
  71. data/smoke/block/b.rb +15 -0
  72. data/smoke/case/a.rb +3 -3
  73. data/smoke/class/a.rb +3 -3
  74. data/smoke/class/b.rb +0 -2
  75. data/smoke/class/d.rb +2 -2
  76. data/smoke/class/e.rb +1 -1
  77. data/smoke/class/f.rb +2 -2
  78. data/smoke/class/g.rb +8 -0
  79. data/smoke/const/a.rb +3 -3
  80. data/smoke/dstr/a.rb +1 -1
  81. data/smoke/ensure/a.rb +22 -0
  82. data/smoke/enumerator/a.rb +6 -6
  83. data/smoke/enumerator/b.rb +22 -0
  84. data/smoke/extension/a.rb +2 -2
  85. data/smoke/extension/b.rb +3 -3
  86. data/smoke/extension/c.rb +1 -1
  87. data/smoke/hello/hello.rb +2 -2
  88. data/smoke/if/a.rb +4 -2
  89. data/smoke/kwbegin/a.rb +8 -0
  90. data/smoke/literal/a.rb +5 -5
  91. data/smoke/method/a.rb +5 -5
  92. data/smoke/method/a.rbi +4 -0
  93. data/smoke/method/b.rb +29 -0
  94. data/smoke/module/a.rb +3 -3
  95. data/smoke/module/a.rbi +9 -0
  96. data/smoke/module/b.rb +2 -2
  97. data/smoke/module/c.rb +1 -1
  98. data/smoke/module/d.rb +5 -0
  99. data/smoke/module/e.rb +13 -0
  100. data/smoke/module/f.rb +13 -0
  101. data/smoke/rescue/a.rb +62 -0
  102. data/smoke/super/a.rb +2 -2
  103. data/smoke/type_case/a.rb +35 -0
  104. data/smoke/yield/a.rb +2 -2
  105. data/stdlib/builtin.rbi +463 -24
  106. data/steep.gemspec +3 -2
  107. metadata +91 -29
  108. data/lib/steep/annotation.rb +0 -223
  109. data/lib/steep/signature/class.rb +0 -450
  110. data/lib/steep/signature/extension.rb +0 -51
  111. data/lib/steep/signature/interface.rb +0 -49
  112. data/lib/steep/types/any.rb +0 -31
  113. data/lib/steep/types/class.rb +0 -27
  114. data/lib/steep/types/instance.rb +0 -27
  115. data/lib/steep/types/merge.rb +0 -32
  116. data/lib/steep/types/name.rb +0 -57
  117. data/lib/steep/types/union.rb +0 -42
  118. data/lib/steep/types/var.rb +0 -38
  119. data/lib/steep/types.rb +0 -4
data/lib/steep/source.rb CHANGED
@@ -28,19 +28,51 @@ module Steep
28
28
  @mapping = mapping
29
29
  end
30
30
 
31
+ class Builder < ::Parser::Builders::Default
32
+ def string_value(token)
33
+ value(token)
34
+ end
35
+
36
+ def emit_lambda
37
+ true
38
+ end
39
+ end
40
+
41
+ def self.parser
42
+ ::Parser::CurrentRuby.new(Builder.new).tap do |parser|
43
+ parser.diagnostics.all_errors_are_fatal = true
44
+ parser.diagnostics.ignore_warnings = true
45
+ end
46
+ end
47
+
31
48
  def self.parse(source_code, path:, labeling: ASTUtils::Labeling.new)
32
- node = labeling.translate(::Parser::CurrentRuby.parse(source_code, path.to_s), {})
49
+ buffer = ::Parser::Source::Buffer.new(path.to_s, 1)
50
+ buffer.source = source_code
51
+ node = parser.parse(buffer).yield_self do |n|
52
+ if n
53
+ labeling.translate(n, {})
54
+ else
55
+ return
56
+ end
57
+ end
33
58
 
34
59
  annotations = []
35
60
 
36
- buffer = ::Parser::Source::Buffer.new(path.to_s)
37
- buffer.source = source_code
38
- parser = ::Parser::CurrentRuby.new
61
+ _, comments, _ = yield_self do
62
+ buffer = ::Parser::Source::Buffer.new(path.to_s)
63
+ buffer.source = source_code
64
+ parser = ::Parser::CurrentRuby.new
65
+
66
+ parser.tokenize(buffer)
67
+ end
68
+
69
+ buffer = AST::Buffer.new(name: path, content: source_code)
39
70
 
40
- _, comments, _ = parser.tokenize(buffer)
41
71
  comments.each do |comment|
42
- src = comment.text.gsub(/\A#\s*/, '')
43
- annotation = Steep::Parser.parse_annotation_opt(src)
72
+ src = comment.text.gsub(/\A#/, '')
73
+ annotation = Steep::Parser.parse_annotation_opt(src,
74
+ buffer: buffer,
75
+ offset: comment.location.expression.begin_pos+1)
44
76
  if annotation
45
77
  annotations << LocatedAnnotation.new(line: comment.location.line, source: src, annotation: annotation)
46
78
  end
@@ -57,42 +89,205 @@ module Steep
57
89
  new(path: path, node: node, mapping: mapping)
58
90
  end
59
91
 
60
- def self.construct_mapping(node:, annotations:, mapping:)
61
- each_child_node(node) do |child|
62
- construct_mapping(node: child, annotations: annotations, mapping: mapping)
63
- end
64
-
92
+ def self.construct_mapping(node:, annotations:, mapping:, line_range: nil)
65
93
  case node.type
66
- when :def, :block, :module, :class
67
- start_line = node.loc.line
68
- end_line = node.loc.last_line
94
+ when :if
95
+ if node.loc.is_a?(::Parser::Source::Map::Ternary)
96
+ # Skip ternary operator
97
+ each_child_node node do |child|
98
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
99
+ end
100
+ else
101
+ if node.loc.expression.begin_pos == node.loc.keyword.begin_pos
102
+ construct_mapping(node: node.children[0],
103
+ annotations: annotations,
104
+ mapping: mapping,
105
+ line_range: nil)
106
+
107
+ if node.children[1]
108
+ if node.loc.keyword.source == "if" || node.loc.keyword.source == "elsif"
109
+ then_start = node.loc.begin&.loc&.last_line || node.children[0].loc.last_line
110
+ then_end = node.children[2] ? node.loc.else.line : node.loc.last_line
111
+ else
112
+ then_start = node.loc.else.last_line
113
+ then_end = node.loc.last_line
114
+ end
115
+ construct_mapping(node: node.children[1],
116
+ annotations: annotations,
117
+ mapping: mapping,
118
+ line_range: then_start...then_end)
119
+ end
120
+
121
+ if node.children[2]
122
+ if node.loc.keyword.source == "if" || node.loc.keyword.source == "elsif"
123
+ else_start = node.loc.else.last_line
124
+ else_end = node.loc.last_line
125
+ else
126
+ else_start = node.loc.begin&.last_line || node.children[0].loc.last_line
127
+ else_end = node.children[1] ? node.loc.else.line : node.loc.last_line
128
+ end
129
+ construct_mapping(node: node.children[2],
130
+ annotations: annotations,
131
+ mapping: mapping,
132
+ line_range: else_start...else_end)
133
+ end
134
+
135
+ else
136
+ # postfix if/unless
137
+ each_child_node(node) do |child|
138
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
139
+ end
140
+ end
141
+ end
142
+
143
+ when :while, :until
144
+ if node.loc.expression.begin_pos == node.loc.keyword.begin_pos
145
+ construct_mapping(node: node.children[0],
146
+ annotations: annotations,
147
+ mapping: mapping,
148
+ line_range: nil)
149
+
150
+ if node.children[1]
151
+ body_start = node.children[0].loc.last_line
152
+ body_end = node.loc.end.line
153
+
154
+ construct_mapping(node: node.children[1],
155
+ annotations: annotations,
156
+ mapping: mapping,
157
+ line_range: body_start...body_end)
158
+ end
159
+
160
+ else
161
+ # postfix while
162
+ each_child_node(node) do |child|
163
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
164
+ end
165
+ end
166
+
167
+ when :while_post, :until_post
168
+ construct_mapping(node: node.children[0],
169
+ annotations: annotations,
170
+ mapping: mapping,
171
+ line_range: nil)
69
172
 
70
- consumed = []
173
+ if node.children[1]
174
+ body_start = node.loc.expression.line
175
+ body_end = node.loc.keyword.line
71
176
 
72
- annotations.each do |annot|
73
- if start_line <= annot.line && annot.line < end_line
74
- consumed << annot
75
- mapping[node.__id__] = [] unless mapping.key?(node.__id__)
76
- mapping[node.__id__] << annot.annotation
177
+ construct_mapping(node: node.children[1],
178
+ annotations: annotations,
179
+ mapping: mapping,
180
+ line_range: body_start...body_end)
181
+ end
182
+
183
+ when :case
184
+ if node.children[0]
185
+ construct_mapping(node: node.children[0], annotations: annotations, mapping: mapping, line_range: nil)
186
+ end
187
+
188
+ if node.loc.else
189
+ else_node = node.children.last
190
+ else_start = node.loc.else.last_line
191
+ else_end = node.loc.end.line
192
+
193
+ construct_mapping(node: else_node,
194
+ annotations: annotations,
195
+ mapping: mapping,
196
+ line_range: else_start...else_end)
197
+ end
198
+
199
+ node.children.drop(1).each do |child|
200
+ if child&.type == :when
201
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
77
202
  end
78
203
  end
79
204
 
80
- consumed.each do |annot|
81
- annotations.delete annot
205
+ when :when
206
+ last_cond = node.children[-2]
207
+ body = node.children.last
208
+
209
+ node.children.take(node.children.size-1) do |child|
210
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
211
+ end
212
+
213
+ if body
214
+ cond_end = last_cond.loc.last_line+1
215
+ body_end = body.loc.last_line
216
+ construct_mapping(node: body,
217
+ annotations: annotations,
218
+ mapping: mapping,
219
+ line_range: cond_end...body_end)
220
+ end
221
+
222
+ when :rescue
223
+ if node.children.last
224
+ else_node = node.children.last
225
+ else_start = node.loc.else.last_line
226
+ else_end = node.loc.last_line
227
+
228
+ construct_mapping(node: else_node,
229
+ annotations: annotations,
230
+ mapping: mapping,
231
+ line_range: else_start...else_end)
232
+ end
233
+
234
+ each_child_node(node) do |child|
235
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
236
+ end
237
+
238
+ else
239
+ each_child_node(node) do |child|
240
+ construct_mapping(node: child, annotations: annotations, mapping: mapping, line_range: nil)
241
+ end
242
+ end
243
+
244
+ associated_annotations = annotations.select do |annot|
245
+ case node.type
246
+ when :def, :module, :class, :block, :ensure
247
+ loc = node.loc
248
+ loc.line <= annot.line && annot.line < loc.last_line
249
+
250
+ when :resbody
251
+ if node.loc.keyword.begin_pos == node.loc.expression.begin_pos
252
+ # skip postfix rescue
253
+ loc = node.loc
254
+ loc.line <= annot.line && annot.line < loc.last_line
255
+ end
256
+ else
257
+ if line_range
258
+ line_range.begin <= annot.line && annot.line < line_range.end
259
+ end
82
260
  end
83
261
  end
262
+
263
+ associated_annotations.each do |annot|
264
+ mapping[node.__id__] = [] unless mapping.key?(node.__id__)
265
+ mapping[node.__id__] << annot.annotation
266
+ annotations.delete annot
267
+ end
84
268
  end
85
269
 
86
270
  def self.each_child_node(node)
87
271
  node.children.each do |child|
88
- if child.is_a?(AST::Node)
272
+ if child.is_a?(::AST::Node)
89
273
  yield child
90
274
  end
91
275
  end
92
276
  end
93
277
 
94
278
  def annotations(block:)
95
- Annotation::Collection.new(annotations: mapping[block.__id__] || [])
279
+ AST::Annotation::Collection.new(annotations: mapping[block.__id__] || [])
280
+ end
281
+
282
+ def each_annotation
283
+ if block_given?
284
+ mapping.each_key do |id|
285
+ node = ObjectSpace._id2ref(id)
286
+ yield node, mapping[id]
287
+ end
288
+ else
289
+ enum_for :each_annotation
290
+ end
96
291
  end
97
292
  end
98
293
  end