steep 0.1.0.pre2 → 0.1.0

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