steep 0.11.1 → 0.12.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 (299) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +27 -0
  3. data/.gitmodules +3 -0
  4. data/CHANGELOG.md +5 -0
  5. data/README.md +48 -90
  6. data/Rakefile +10 -6
  7. data/Steepfile +1 -0
  8. data/bin/setup +1 -0
  9. data/bin/smoke_runner.rb +9 -14
  10. data/exe/rbs +3 -0
  11. data/exe/ruby-signature +3 -0
  12. data/exe/steep +1 -0
  13. data/lib/steep.rb +32 -26
  14. data/lib/steep/annotation_parser.rb +167 -0
  15. data/lib/steep/ast/annotation/collection.rb +7 -7
  16. data/lib/steep/ast/types.rb +60 -0
  17. data/lib/steep/ast/types/any.rb +1 -1
  18. data/lib/steep/ast/types/factory.rb +535 -0
  19. data/lib/steep/ast/types/name.rb +3 -3
  20. data/lib/steep/ast/types/var.rb +1 -1
  21. data/lib/steep/cli.rb +56 -240
  22. data/lib/steep/drivers/annotations.rb +36 -19
  23. data/lib/steep/drivers/check.rb +55 -91
  24. data/lib/steep/drivers/init.rb +54 -0
  25. data/lib/steep/drivers/langserver.rb +241 -150
  26. data/lib/steep/drivers/print_project.rb +56 -0
  27. data/lib/steep/drivers/signature_error_printer.rb +25 -0
  28. data/lib/steep/drivers/trace_printer.rb +25 -0
  29. data/lib/steep/drivers/utils/driver_helper.rb +26 -0
  30. data/lib/steep/drivers/validate.rb +18 -38
  31. data/lib/steep/drivers/vendor.rb +46 -0
  32. data/lib/steep/drivers/watch.rb +78 -140
  33. data/lib/steep/errors.rb +22 -13
  34. data/lib/steep/interface/interface.rb +91 -0
  35. data/lib/steep/interface/method.rb +0 -4
  36. data/lib/steep/interface/method_type.rb +362 -2
  37. data/lib/steep/interface/substitution.rb +22 -0
  38. data/lib/steep/project.rb +25 -233
  39. data/lib/steep/project/dsl.rb +132 -0
  40. data/lib/steep/project/file.rb +93 -76
  41. data/lib/steep/project/file_loader.rb +63 -0
  42. data/lib/steep/project/options.rb +7 -0
  43. data/lib/steep/project/target.rb +190 -0
  44. data/lib/steep/signature/errors.rb +25 -77
  45. data/lib/steep/signature/validator.rb +122 -0
  46. data/lib/steep/source.rb +12 -7
  47. data/lib/steep/subtyping/check.rb +357 -633
  48. data/lib/steep/subtyping/constraints.rb +2 -2
  49. data/lib/steep/subtyping/trace.rb +23 -0
  50. data/lib/steep/type_construction.rb +509 -455
  51. data/lib/steep/type_inference/constant_env.rb +16 -24
  52. data/lib/steep/type_inference/type_env.rb +26 -18
  53. data/lib/steep/version.rb +1 -1
  54. data/sample/Steepfile +6 -0
  55. data/sample/lib/conference.rb +12 -0
  56. data/sample/sig/conference.rbs +6 -0
  57. data/smoke/alias/Steepfile +4 -0
  58. data/smoke/alias/a.rb +2 -2
  59. data/smoke/alias/{a.rbi → a.rbs} +1 -1
  60. data/smoke/and/Steepfile +4 -0
  61. data/smoke/array/Steepfile +4 -0
  62. data/smoke/array/a.rb +2 -2
  63. data/smoke/array/b.rb +4 -4
  64. data/smoke/array/c.rb +2 -2
  65. data/smoke/block/Steepfile +5 -0
  66. data/smoke/block/{a.rbi → a.rbs} +1 -1
  67. data/smoke/block/{c.rbi → c.rbs} +0 -0
  68. data/smoke/block/d.rb +6 -6
  69. data/smoke/case/Steepfile +4 -0
  70. data/smoke/case/a.rb +4 -3
  71. data/smoke/class/Steepfile +4 -0
  72. data/smoke/class/a.rb +1 -4
  73. data/smoke/class/a.rbs +24 -0
  74. data/smoke/class/h.rb +6 -2
  75. data/smoke/class/{h.rbi → h.rbs} +1 -2
  76. data/smoke/class/i.rb +1 -2
  77. data/smoke/class/i.rbs +9 -0
  78. data/smoke/const/Steepfile +4 -0
  79. data/smoke/dstr/Steepfile +4 -0
  80. data/smoke/ensure/Steepfile +4 -0
  81. data/smoke/ensure/a.rb +1 -1
  82. data/smoke/enumerator/Steepfile +4 -0
  83. data/smoke/enumerator/a.rb +7 -7
  84. data/smoke/enumerator/b.rb +6 -6
  85. data/smoke/extension/Steepfile +4 -0
  86. data/smoke/extension/{a.rbi → a.rbs} +2 -2
  87. data/smoke/extension/{e.rbi → e.rbs} +2 -2
  88. data/smoke/hash/Steepfile +4 -0
  89. data/smoke/hash/{a.rbi → a.rbs} +0 -0
  90. data/smoke/hash/b.rb +2 -2
  91. data/smoke/hash/c.rb +1 -1
  92. data/smoke/hash/e.rbs +3 -0
  93. data/smoke/hash/f.rb +1 -1
  94. data/smoke/hello/Steepfile +4 -0
  95. data/smoke/hello/hello.rbs +7 -0
  96. data/smoke/if/Steepfile +4 -0
  97. data/smoke/implements/Steepfile +4 -0
  98. data/smoke/implements/a.rbs +6 -0
  99. data/smoke/initialize/Steepfile +4 -0
  100. data/smoke/initialize/a.rbs +3 -0
  101. data/smoke/integer/Steepfile +4 -0
  102. data/smoke/integer/a.rb +5 -3
  103. data/smoke/interface/Steepfile +4 -0
  104. data/smoke/interface/{a.rbi → a.rbs} +0 -0
  105. data/smoke/kwbegin/Steepfile +4 -0
  106. data/smoke/lambda/Steepfile +4 -0
  107. data/smoke/lambda/a.rb +9 -2
  108. data/smoke/literal/Steepfile +4 -0
  109. data/smoke/literal/{literal_methods.rbi → literal_methods.rbs} +0 -0
  110. data/smoke/map/Steepfile +4 -0
  111. data/smoke/map/a.rb +1 -1
  112. data/smoke/method/Steepfile +4 -0
  113. data/smoke/method/{a.rbi → a.rbs} +0 -0
  114. data/smoke/method/b.rb +1 -4
  115. data/smoke/method/d.rb +1 -0
  116. data/smoke/method/d.rbs +3 -0
  117. data/smoke/module/Steepfile +4 -0
  118. data/smoke/module/a.rb +1 -1
  119. data/smoke/module/a.rbs +16 -0
  120. data/smoke/module/c.rb +1 -1
  121. data/smoke/regexp/Steepfile +4 -0
  122. data/smoke/regexp/a.rb +2 -2
  123. data/smoke/regexp/b.rb +16 -16
  124. data/smoke/regression/Steepfile +5 -0
  125. data/smoke/regression/array.rb +2 -2
  126. data/smoke/regression/hash.rb +2 -2
  127. data/smoke/regression/poly_new.rb +2 -0
  128. data/smoke/regression/poly_new.rbs +4 -0
  129. data/smoke/regression/set_divide.rb +2 -2
  130. data/smoke/rescue/Steepfile +4 -0
  131. data/smoke/rescue/a.rb +1 -1
  132. data/smoke/self/Steepfile +4 -0
  133. data/smoke/self/a.rbs +4 -0
  134. data/smoke/skip/Steepfile +4 -0
  135. data/smoke/stdout/Steepfile +4 -0
  136. data/smoke/stdout/{a.rbi → a.rbs} +1 -1
  137. data/smoke/super/Steepfile +4 -0
  138. data/smoke/super/a.rbs +10 -0
  139. data/smoke/type_case/Steepfile +4 -0
  140. data/smoke/type_case/a.rb +1 -1
  141. data/smoke/yield/Steepfile +4 -0
  142. data/smoke/yield/a.rb +2 -2
  143. data/steep.gemspec +14 -7
  144. data/vendor/ruby-signature/.github/workflows/ruby.yml +27 -0
  145. data/vendor/ruby-signature/.gitignore +12 -0
  146. data/vendor/ruby-signature/.rubocop.yml +15 -0
  147. data/vendor/ruby-signature/BSDL +22 -0
  148. data/vendor/ruby-signature/COPYING +56 -0
  149. data/vendor/ruby-signature/Gemfile +6 -0
  150. data/vendor/ruby-signature/README.md +93 -0
  151. data/vendor/ruby-signature/Rakefile +66 -0
  152. data/vendor/ruby-signature/bin/annotate-with-rdoc +156 -0
  153. data/vendor/ruby-signature/bin/console +14 -0
  154. data/vendor/ruby-signature/bin/query-rdoc +103 -0
  155. data/vendor/ruby-signature/bin/setup +10 -0
  156. data/vendor/ruby-signature/bin/sort +88 -0
  157. data/vendor/ruby-signature/bin/test_runner.rb +17 -0
  158. data/vendor/ruby-signature/docs/CONTRIBUTING.md +97 -0
  159. data/vendor/ruby-signature/docs/sigs.md +148 -0
  160. data/vendor/ruby-signature/docs/stdlib.md +152 -0
  161. data/vendor/ruby-signature/docs/syntax.md +528 -0
  162. data/vendor/ruby-signature/exe/rbs +3 -0
  163. data/vendor/ruby-signature/exe/ruby-signature +7 -0
  164. data/vendor/ruby-signature/lib/ruby/signature.rb +64 -0
  165. data/vendor/ruby-signature/lib/ruby/signature/ast/annotation.rb +29 -0
  166. data/vendor/ruby-signature/lib/ruby/signature/ast/comment.rb +29 -0
  167. data/vendor/ruby-signature/lib/ruby/signature/ast/declarations.rb +391 -0
  168. data/vendor/ruby-signature/lib/ruby/signature/ast/members.rb +364 -0
  169. data/vendor/ruby-signature/lib/ruby/signature/buffer.rb +52 -0
  170. data/vendor/ruby-signature/lib/ruby/signature/builtin_names.rb +54 -0
  171. data/vendor/ruby-signature/lib/ruby/signature/cli.rb +534 -0
  172. data/vendor/ruby-signature/lib/ruby/signature/constant.rb +28 -0
  173. data/vendor/ruby-signature/lib/ruby/signature/constant_table.rb +152 -0
  174. data/vendor/ruby-signature/lib/ruby/signature/definition.rb +172 -0
  175. data/vendor/ruby-signature/lib/ruby/signature/definition_builder.rb +921 -0
  176. data/vendor/ruby-signature/lib/ruby/signature/environment.rb +283 -0
  177. data/vendor/ruby-signature/lib/ruby/signature/environment_loader.rb +138 -0
  178. data/vendor/ruby-signature/lib/ruby/signature/environment_walker.rb +126 -0
  179. data/vendor/ruby-signature/lib/ruby/signature/errors.rb +189 -0
  180. data/vendor/ruby-signature/lib/ruby/signature/location.rb +104 -0
  181. data/vendor/ruby-signature/lib/ruby/signature/method_type.rb +125 -0
  182. data/vendor/ruby-signature/lib/ruby/signature/namespace.rb +93 -0
  183. data/vendor/ruby-signature/lib/ruby/signature/parser.y +1343 -0
  184. data/vendor/ruby-signature/lib/ruby/signature/prototype/rb.rb +441 -0
  185. data/vendor/ruby-signature/lib/ruby/signature/prototype/rbi.rb +579 -0
  186. data/vendor/ruby-signature/lib/ruby/signature/prototype/runtime.rb +383 -0
  187. data/vendor/ruby-signature/lib/ruby/signature/substitution.rb +48 -0
  188. data/vendor/ruby-signature/lib/ruby/signature/test.rb +28 -0
  189. data/vendor/ruby-signature/lib/ruby/signature/test/errors.rb +63 -0
  190. data/vendor/ruby-signature/lib/ruby/signature/test/hook.rb +290 -0
  191. data/vendor/ruby-signature/lib/ruby/signature/test/setup.rb +58 -0
  192. data/vendor/ruby-signature/lib/ruby/signature/test/spy.rb +324 -0
  193. data/vendor/ruby-signature/lib/ruby/signature/test/test_helper.rb +185 -0
  194. data/vendor/ruby-signature/lib/ruby/signature/test/type_check.rb +256 -0
  195. data/vendor/ruby-signature/lib/ruby/signature/type_name.rb +72 -0
  196. data/vendor/ruby-signature/lib/ruby/signature/types.rb +932 -0
  197. data/vendor/ruby-signature/lib/ruby/signature/variance_calculator.rb +140 -0
  198. data/vendor/ruby-signature/lib/ruby/signature/vendorer.rb +49 -0
  199. data/vendor/ruby-signature/lib/ruby/signature/version.rb +5 -0
  200. data/vendor/ruby-signature/lib/ruby/signature/writer.rb +271 -0
  201. data/vendor/ruby-signature/ruby-signature.gemspec +45 -0
  202. data/vendor/ruby-signature/stdlib/abbrev/abbrev.rbs +3 -0
  203. data/vendor/ruby-signature/stdlib/base64/base64.rbs +15 -0
  204. data/vendor/ruby-signature/stdlib/builtin/array.rbs +1997 -0
  205. data/vendor/ruby-signature/stdlib/builtin/basic_object.rbs +280 -0
  206. data/vendor/ruby-signature/stdlib/builtin/binding.rbs +177 -0
  207. data/vendor/ruby-signature/stdlib/builtin/builtin.rbs +35 -0
  208. data/vendor/ruby-signature/stdlib/builtin/class.rbs +145 -0
  209. data/vendor/ruby-signature/stdlib/builtin/comparable.rbs +116 -0
  210. data/vendor/ruby-signature/stdlib/builtin/complex.rbs +400 -0
  211. data/vendor/ruby-signature/stdlib/builtin/constants.rbs +37 -0
  212. data/vendor/ruby-signature/stdlib/builtin/data.rbs +5 -0
  213. data/vendor/ruby-signature/stdlib/builtin/deprecated.rbs +2 -0
  214. data/vendor/ruby-signature/stdlib/builtin/dir.rbs +419 -0
  215. data/vendor/ruby-signature/stdlib/builtin/encoding.rbs +606 -0
  216. data/vendor/ruby-signature/stdlib/builtin/enumerable.rbs +404 -0
  217. data/vendor/ruby-signature/stdlib/builtin/enumerator.rbs +260 -0
  218. data/vendor/ruby-signature/stdlib/builtin/errno.rbs +781 -0
  219. data/vendor/ruby-signature/stdlib/builtin/errors.rbs +582 -0
  220. data/vendor/ruby-signature/stdlib/builtin/exception.rbs +193 -0
  221. data/vendor/ruby-signature/stdlib/builtin/false_class.rbs +40 -0
  222. data/vendor/ruby-signature/stdlib/builtin/fiber.rbs +68 -0
  223. data/vendor/ruby-signature/stdlib/builtin/fiber_error.rbs +12 -0
  224. data/vendor/ruby-signature/stdlib/builtin/file.rbs +476 -0
  225. data/vendor/ruby-signature/stdlib/builtin/file_test.rbs +59 -0
  226. data/vendor/ruby-signature/stdlib/builtin/float.rbs +696 -0
  227. data/vendor/ruby-signature/stdlib/builtin/gc.rbs +121 -0
  228. data/vendor/ruby-signature/stdlib/builtin/hash.rbs +1029 -0
  229. data/vendor/ruby-signature/stdlib/builtin/integer.rbs +710 -0
  230. data/vendor/ruby-signature/stdlib/builtin/io.rbs +683 -0
  231. data/vendor/ruby-signature/stdlib/builtin/kernel.rbs +574 -0
  232. data/vendor/ruby-signature/stdlib/builtin/marshal.rbs +135 -0
  233. data/vendor/ruby-signature/stdlib/builtin/match_data.rbs +141 -0
  234. data/vendor/ruby-signature/stdlib/builtin/math.rbs +66 -0
  235. data/vendor/ruby-signature/stdlib/builtin/method.rbs +182 -0
  236. data/vendor/ruby-signature/stdlib/builtin/module.rbs +248 -0
  237. data/vendor/ruby-signature/stdlib/builtin/nil_class.rbs +82 -0
  238. data/vendor/ruby-signature/stdlib/builtin/numeric.rbs +409 -0
  239. data/vendor/ruby-signature/stdlib/builtin/object.rbs +824 -0
  240. data/vendor/ruby-signature/stdlib/builtin/proc.rbs +426 -0
  241. data/vendor/ruby-signature/stdlib/builtin/process.rbs +354 -0
  242. data/vendor/ruby-signature/stdlib/builtin/random.rbs +93 -0
  243. data/vendor/ruby-signature/stdlib/builtin/range.rbs +226 -0
  244. data/vendor/ruby-signature/stdlib/builtin/rational.rbs +424 -0
  245. data/vendor/ruby-signature/stdlib/builtin/rb_config.rbs +10 -0
  246. data/vendor/ruby-signature/stdlib/builtin/regexp.rbs +131 -0
  247. data/vendor/ruby-signature/stdlib/builtin/ruby_vm.rbs +14 -0
  248. data/vendor/ruby-signature/stdlib/builtin/signal.rbs +55 -0
  249. data/vendor/ruby-signature/stdlib/builtin/string.rbs +770 -0
  250. data/vendor/ruby-signature/stdlib/builtin/string_io.rbs +13 -0
  251. data/vendor/ruby-signature/stdlib/builtin/struct.rbs +40 -0
  252. data/vendor/ruby-signature/stdlib/builtin/symbol.rbs +230 -0
  253. data/vendor/ruby-signature/stdlib/builtin/thread.rbs +1112 -0
  254. data/vendor/ruby-signature/stdlib/builtin/thread_group.rbs +23 -0
  255. data/vendor/ruby-signature/stdlib/builtin/time.rbs +739 -0
  256. data/vendor/ruby-signature/stdlib/builtin/trace_point.rbs +91 -0
  257. data/vendor/ruby-signature/stdlib/builtin/true_class.rbs +46 -0
  258. data/vendor/ruby-signature/stdlib/builtin/unbound_method.rbs +159 -0
  259. data/vendor/ruby-signature/stdlib/builtin/warning.rbs +17 -0
  260. data/vendor/ruby-signature/stdlib/erb/erb.rbs +18 -0
  261. data/vendor/ruby-signature/stdlib/find/find.rbs +44 -0
  262. data/vendor/ruby-signature/stdlib/pathname/pathname.rbs +21 -0
  263. data/vendor/ruby-signature/stdlib/prime/integer-extension.rbs +23 -0
  264. data/vendor/ruby-signature/stdlib/prime/prime.rbs +188 -0
  265. data/vendor/ruby-signature/stdlib/securerandom/securerandom.rbs +9 -0
  266. data/vendor/ruby-signature/stdlib/set/set.rbs +77 -0
  267. data/vendor/ruby-signature/stdlib/tmpdir/tmpdir.rbs +53 -0
  268. metadata +244 -54
  269. data/.travis.yml +0 -7
  270. data/lib/steep/ast/signature/alias.rb +0 -19
  271. data/lib/steep/ast/signature/class.rb +0 -33
  272. data/lib/steep/ast/signature/const.rb +0 -17
  273. data/lib/steep/ast/signature/env.rb +0 -138
  274. data/lib/steep/ast/signature/extension.rb +0 -21
  275. data/lib/steep/ast/signature/gvar.rb +0 -17
  276. data/lib/steep/ast/signature/interface.rb +0 -31
  277. data/lib/steep/ast/signature/members.rb +0 -115
  278. data/lib/steep/ast/signature/module.rb +0 -21
  279. data/lib/steep/drivers/print_interface.rb +0 -94
  280. data/lib/steep/drivers/scaffold.rb +0 -321
  281. data/lib/steep/drivers/utils/each_signature.rb +0 -31
  282. data/lib/steep/interface/abstract.rb +0 -68
  283. data/lib/steep/interface/builder.rb +0 -637
  284. data/lib/steep/interface/instantiated.rb +0 -163
  285. data/lib/steep/interface/ivar_chain.rb +0 -26
  286. data/lib/steep/parser.y +0 -1278
  287. data/lib/steep/project/listener.rb +0 -53
  288. data/smoke/class/a.rbi +0 -24
  289. data/smoke/class/d.rb +0 -9
  290. data/smoke/class/e.rb +0 -12
  291. data/smoke/class/i.rbi +0 -9
  292. data/smoke/hash/e.rbi +0 -3
  293. data/smoke/hello/hello.rbi +0 -7
  294. data/smoke/implements/a.rbi +0 -6
  295. data/smoke/initialize/a.rbi +0 -3
  296. data/smoke/module/a.rbi +0 -16
  297. data/smoke/self/a.rbi +0 -4
  298. data/smoke/super/a.rbi +0 -10
  299. data/stdlib/builtin.rbi +0 -787
@@ -0,0 +1,185 @@
1
+ module Ruby
2
+ module Signature
3
+ module Test
4
+ module TypeAssertions
5
+ module ClassMethods
6
+ attr_reader :target
7
+
8
+ def library(*libs)
9
+ @libs = libs
10
+ @env = nil
11
+ @target = nil
12
+ end
13
+
14
+ def env
15
+ @env ||= begin
16
+ loader = Ruby::Signature::EnvironmentLoader.new
17
+ (@libs || []).each do |lib|
18
+ loader.add library: lib
19
+ end
20
+
21
+ Ruby::Signature::Environment.new.tap do |env|
22
+ loader.load(env: env)
23
+ end
24
+ end
25
+ end
26
+
27
+ def builder
28
+ @builder ||= DefinitionBuilder.new(env: env)
29
+ end
30
+
31
+ def testing(type_or_string)
32
+ type = case type_or_string
33
+ when String
34
+ Ruby::Signature::Parser.parse_type(type_or_string, variables: [])
35
+ else
36
+ type_or_string
37
+ end
38
+
39
+ definition = case type
40
+ when Types::ClassInstance
41
+ builder.build_instance(type.name)
42
+ when Types::ClassSingleton
43
+ builder.build_singleton(type.name)
44
+ else
45
+ raise "Test target should be class instance or class singleton: #{type}"
46
+ end
47
+
48
+ @target = [type, definition]
49
+ end
50
+ end
51
+
52
+ def self.included(base)
53
+ base.extend ClassMethods
54
+ end
55
+
56
+ def env
57
+ self.class.env
58
+ end
59
+
60
+ def builder
61
+ self.class.builder
62
+ end
63
+
64
+ def targets
65
+ @targets ||= []
66
+ end
67
+
68
+ def target
69
+ targets.last || self.class.target
70
+ end
71
+
72
+ def testing(type_or_string)
73
+ type = case type_or_string
74
+ when String
75
+ Ruby::Signature::Parser.parse_type(type_or_string, variables: [])
76
+ else
77
+ type_or_string
78
+ end
79
+
80
+ definition = case type
81
+ when Types::ClassInstance
82
+ builder.build_instance(type.name)
83
+ when Types::ClassSingleton
84
+ builder.build_singleton(type.name)
85
+ else
86
+ raise "Test target should be class instance or class singleton: #{type}"
87
+ end
88
+
89
+ targets.push [type, definition]
90
+
91
+ if block_given?
92
+ begin
93
+ yield
94
+ ensure
95
+ targets.pop
96
+ end
97
+ else
98
+ [type, definition]
99
+ end
100
+ end
101
+
102
+ ruby2_keywords def assert_send_type(method_type, receiver, method, *args, &block)
103
+ trace = []
104
+ spy = Spy.wrap(receiver, method)
105
+ spy.callback = -> (result) { trace << result }
106
+
107
+ exception = nil
108
+
109
+ begin
110
+ spy.wrapped_object.__send__(method, *args, &block)
111
+ rescue => exn
112
+ exception = exn
113
+ end
114
+
115
+ mt = case method_type
116
+ when String
117
+ Ruby::Signature::Parser.parse_method_type(method_type, variables: [])
118
+ when Ruby::Signature::MethodType
119
+ method_type
120
+ end
121
+
122
+ typecheck = TypeCheck.new(self_class: receiver.class, builder: builder)
123
+ errors = typecheck.method_call(method, mt, trace.last, errors: [])
124
+
125
+ assert_empty errors.map {|x| Ruby::Signature::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.last.inspect}"
126
+
127
+ type, definition = target
128
+ method_types = case
129
+ when definition.instance_type?
130
+ subst = Substitution.build(definition.declaration.type_params.each.map(&:name),
131
+ type.args)
132
+ definition.methods[method].method_types.map do |method_type|
133
+ method_type.sub(subst)
134
+ end
135
+ when definition.class_type?
136
+ definition.methods[method].method_types
137
+ end
138
+
139
+ all_errors = method_types.map {|t| typecheck.method_call(method, t, trace.last, errors: []) }
140
+ assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.last.inspect}\n #{method_types.join(" | ")}"
141
+
142
+ if exception
143
+ raise exception
144
+ end
145
+ end
146
+
147
+ ruby2_keywords def refute_send_type(method_type, receiver, method, *args, &block)
148
+ trace = []
149
+ spy = Spy.wrap(receiver, method)
150
+ spy.callback = -> (result) { trace << result }
151
+
152
+ exception = nil
153
+ begin
154
+ spy.wrapped_object.__send__(method, *args, &block)
155
+ rescue Exception => exn
156
+ exception = exn
157
+ end
158
+
159
+ mt = case method_type
160
+ when String
161
+ Ruby::Signature::Parser.parse_method_type(method_type, variables: [])
162
+ when Ruby::Signature::MethodType
163
+ method_type
164
+ end
165
+
166
+ mt = mt.update(block: if mt.block
167
+ MethodType::Block.new(
168
+ type: mt.block.type.with_return_type(Types::Bases::Any.new(location: nil)),
169
+ required: mt.block.required
170
+ )
171
+ end,
172
+ type: mt.type.with_return_type(Types::Bases::Any.new(location: nil)))
173
+
174
+ typecheck = TypeCheck.new(self_class: receiver.class, builder: builder)
175
+ errors = typecheck.method_call(method, mt, trace.last, errors: [])
176
+
177
+ assert_operator exception, :is_a?, ::Exception
178
+ assert_empty errors.map {|x| Ruby::Signature::Test::Errors.to_string(x) }
179
+
180
+ exception
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,256 @@
1
+ module Ruby
2
+ module Signature
3
+ module Test
4
+ class TypeCheck
5
+ attr_reader :self_class
6
+ attr_reader :builder
7
+
8
+ def initialize(self_class:, builder:)
9
+ @self_class = self_class
10
+ @builder = builder
11
+ end
12
+
13
+ def method_call(method_name, method_type, call, errors:)
14
+ args(method_name, method_type, method_type.type, call.method_call, errors, type_error: Errors::ArgumentTypeError, argument_error: Errors::ArgumentError)
15
+ self.return(method_name, method_type, method_type.type, call.method_call, errors, return_error: Errors::ReturnTypeError)
16
+
17
+ if method_type.block
18
+ case
19
+ when !call.block_calls.empty?
20
+ call.block_calls.each do |block_call|
21
+ args(method_name, method_type, method_type.block.type, block_call, errors, type_error: Errors::BlockArgumentTypeError, argument_error: Errors::BlockArgumentError)
22
+ self.return(method_name, method_type, method_type.block.type, block_call, errors, return_error: Errors::BlockReturnTypeError)
23
+ end
24
+ when !call.block_given
25
+ # Block is not given
26
+ if method_type.block.required
27
+ errors << Errors::MissingBlockError.new(klass: self_class, method_name: method_name, method_type: method_type)
28
+ end
29
+ else
30
+ # Block is given, but not yielded
31
+ end
32
+ else
33
+ if call.block_given
34
+ errors << Errors::UnexpectedBlockError.new(klass: self_class, method_name: method_name, method_type: method_type)
35
+ end
36
+ end
37
+
38
+ errors
39
+ end
40
+
41
+ def args(method_name, method_type, fun, call, errors, type_error:, argument_error:)
42
+ test = zip_args(call.arguments, fun) do |val, param|
43
+ unless self.value(val, param.type)
44
+ errors << type_error.new(klass: self_class,
45
+ method_name: method_name,
46
+ method_type: method_type,
47
+ param: param,
48
+ value: val)
49
+ end
50
+ end
51
+
52
+ unless test
53
+ errors << argument_error.new(klass: self_class,
54
+ method_name: method_name,
55
+ method_type: method_type)
56
+ end
57
+ end
58
+
59
+ def return(method_name, method_type, fun, call, errors, return_error:)
60
+ unless call.exception
61
+ unless value(call.return_value, fun.return_type)
62
+ errors << return_error.new(klass: self_class,
63
+ method_name: method_name,
64
+ method_type: method_type,
65
+ type: fun.return_type,
66
+ value: call.return_value)
67
+ end
68
+ end
69
+ end
70
+
71
+ def zip_keyword_args(hash, fun)
72
+ fun.required_keywords.each do |name, param|
73
+ if hash.key?(name)
74
+ yield(hash[name], param)
75
+ else
76
+ return false
77
+ end
78
+ end
79
+
80
+ fun.optional_keywords.each do |name, param|
81
+ if hash.key?(name)
82
+ yield(hash[name], param)
83
+ end
84
+ end
85
+
86
+ hash.each do |name, value|
87
+ next if fun.required_keywords.key?(name)
88
+ next if fun.optional_keywords.key?(name)
89
+
90
+ if fun.rest_keywords
91
+ yield value, fun.rest_keywords
92
+ else
93
+ return false
94
+ end
95
+ end
96
+
97
+ true
98
+ end
99
+
100
+ def keyword?(value)
101
+ value.is_a?(Hash) && value.keys.all? {|key| key.is_a?(Symbol) }
102
+ end
103
+
104
+ def zip_args(args, fun, &block)
105
+ case
106
+ when args.empty?
107
+ if fun.required_positionals.empty? && fun.trailing_positionals.empty? && fun.required_keywords.empty?
108
+ true
109
+ else
110
+ false
111
+ end
112
+ when !fun.required_positionals.empty?
113
+ yield_self do
114
+ param, fun_ = fun.drop_head
115
+ yield(args.first, param)
116
+ zip_args(args.drop(1), fun_, &block)
117
+ end
118
+ when fun.has_keyword?
119
+ yield_self do
120
+ hash = args.last
121
+ if keyword?(hash)
122
+ zip_keyword_args(hash, fun, &block) &&
123
+ zip_args(args.take(args.size - 1),
124
+ fun.update(required_keywords: {}, optional_keywords: {}, rest_keywords: nil),
125
+ &block)
126
+ else
127
+ fun.required_keywords.empty? &&
128
+ zip_args(args,
129
+ fun.update(required_keywords: {}, optional_keywords: {}, rest_keywords: nil),
130
+ &block)
131
+ end
132
+ end
133
+ when !fun.trailing_positionals.empty?
134
+ yield_self do
135
+ param, fun_ = fun.drop_tail
136
+ yield(args.last, param)
137
+ zip_args(args.take(args.size - 1), fun_, &block)
138
+ end
139
+ when !fun.optional_positionals.empty?
140
+ yield_self do
141
+ param, fun_ = fun.drop_head
142
+ yield(args.first, param)
143
+ zip_args(args.drop(1), fun_, &block)
144
+ end
145
+ when fun.rest_positionals
146
+ yield_self do
147
+ yield(args.first, fun.rest_positionals)
148
+ zip_args(args.drop(1), fun, &block)
149
+ end
150
+ else
151
+ false
152
+ end
153
+ end
154
+
155
+ def value(val, type)
156
+ case type
157
+ when Types::Bases::Any
158
+ true
159
+ when Types::Bases::Bool
160
+ true
161
+ when Types::Bases::Top
162
+ true
163
+ when Types::Bases::Bottom
164
+ false
165
+ when Types::Bases::Void
166
+ true
167
+ when Types::Bases::Self
168
+ Test.call(val, IS_AP, self_class)
169
+ when Types::Bases::Nil
170
+ Test.call(val, IS_AP, ::NilClass)
171
+ when Types::Bases::Class
172
+ Test.call(val, IS_AP, Class)
173
+ when Types::Bases::Instance
174
+ Test.call(val, IS_AP, self_class)
175
+ when Types::ClassInstance
176
+ klass = Object.const_get(type.name.to_s)
177
+ case
178
+ when klass == ::Array
179
+ Test.call(val, IS_AP, klass) && val.all? {|v| value(v, type.args[0]) }
180
+ when klass == ::Hash
181
+ Test.call(val, IS_AP, klass) && val.all? {|k, v| value(k, type.args[0]) && value(v, type.args[1]) }
182
+ when klass == ::Range
183
+ Test.call(val, IS_AP, klass) && value(val.begin, type.args[0]) && value(val.end, type.args[0])
184
+ when klass == ::Enumerator
185
+ if Test.call(val, IS_AP, klass)
186
+ case val.size
187
+ when Float::INFINITY
188
+ values = []
189
+ ret = self
190
+ val.lazy.take(10).each do |*args|
191
+ values << args
192
+ nil
193
+ end
194
+ else
195
+ values = []
196
+ ret = val.each do |*args|
197
+ values << args
198
+ nil
199
+ end
200
+ end
201
+
202
+ values.all? do |v|
203
+ if v.size == 1
204
+ # Only one block argument.
205
+ value(v[0], type.args[0]) || value(v, type.args[0])
206
+ else
207
+ value(v, type.args[0])
208
+ end
209
+ end &&
210
+ if ret.equal?(self)
211
+ type.args[1].is_a?(Types::Bases::Bottom)
212
+ else
213
+ value(ret, type.args[1])
214
+ end
215
+ end
216
+ else
217
+ Test.call(val, IS_AP, klass)
218
+ end
219
+ when Types::ClassSingleton
220
+ klass = Object.const_get(type.name.to_s)
221
+ val == klass
222
+ when Types::Interface
223
+ methods = Set.new(Test.call(val, METHODS))
224
+ decl = builder.env.find_class(type.name)
225
+ if (definition = builder.build_interface(type.name, decl))
226
+ definition.methods.each_key.all? do |method_name|
227
+ methods.member?(method_name)
228
+ end
229
+ end
230
+ when Types::Variable
231
+ true
232
+ when Types::Literal
233
+ val == type.literal
234
+ when Types::Union
235
+ type.types.any? {|type| value(val, type) }
236
+ when Types::Intersection
237
+ type.types.all? {|type| value(val, type) }
238
+ when Types::Optional
239
+ Test.call(val, IS_AP, ::NilClass) || value(val, type.type)
240
+ when Types::Alias
241
+ value(val, builder.expand_alias(type.name))
242
+ when Types::Tuple
243
+ Test.call(val, IS_AP, ::Array) &&
244
+ type.types.map.with_index {|ty, index| value(val[index], ty) }.all?
245
+ when Types::Record
246
+ Test::call(val, IS_AP, ::Hash)
247
+ when Types::Proc
248
+ Test::call(val, IS_AP, ::Proc)
249
+ else
250
+ false
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,72 @@
1
+ module Ruby
2
+ module Signature
3
+ class TypeName
4
+ attr_reader :namespace
5
+ attr_reader :name
6
+ attr_reader :kind
7
+
8
+ def initialize(namespace:, name:)
9
+ @namespace = namespace
10
+ @name = name
11
+ @kind = case name.to_s[0,1]
12
+ when /[A-Z]/
13
+ :class
14
+ when /[a-z]/
15
+ :alias
16
+ when "_"
17
+ :interface
18
+ end
19
+ end
20
+
21
+ def ==(other)
22
+ other.is_a?(self.class) && other.namespace == namespace && other.name == name
23
+ end
24
+
25
+ alias eql? ==
26
+
27
+ def hash
28
+ self.class.hash ^ namespace.hash ^ name.hash
29
+ end
30
+
31
+ def to_s
32
+ "#{namespace.to_s}#{name}"
33
+ end
34
+
35
+ def to_json(*a)
36
+ to_s.to_json(*a)
37
+ end
38
+
39
+ def to_namespace
40
+ namespace.append(self.name)
41
+ end
42
+
43
+ def class?
44
+ kind == :class
45
+ end
46
+
47
+ def alias?
48
+ kind == :alias
49
+ end
50
+
51
+ def absolute!
52
+ self.class.new(namespace: namespace.absolute!, name: name)
53
+ end
54
+
55
+ def absolute?
56
+ namespace.absolute?
57
+ end
58
+
59
+ def relative!
60
+ self.class.new(namespace: namespace.relative!, name: name)
61
+ end
62
+
63
+ def interface?
64
+ kind == :interface
65
+ end
66
+
67
+ def with_prefix(namespace)
68
+ self.class.new(namespace: namespace + self.namespace, name: name)
69
+ end
70
+ end
71
+ end
72
+ end