steep 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -17,6 +17,20 @@ module Steep
17
17
  new(dictionary: {}, instance_type: AST::Types::Instance.new, module_type: AST::Types::Class.new, self_type: AST::Types::Self.new)
18
18
  end
19
19
 
20
+ def to_s
21
+ a = []
22
+
23
+ dictionary.each do |x, ty|
24
+ a << "#{x} -> #{ty}"
25
+ end
26
+
27
+ a << "[instance_type] -> #{instance_type}"
28
+ a << "[module_type] -> #{module_type}"
29
+ a << "[self_type] -> #{self_type}"
30
+
31
+ "{ #{a.join(", ")} }"
32
+ end
33
+
20
34
  def [](key)
21
35
  dictionary[key] or raise "Unknown variable: #{key}"
22
36
  end
@@ -55,6 +69,14 @@ module Steep
55
69
  raise "Duplicated key on merge!: #{key}, #{a}, #{b}"
56
70
  end
57
71
  end
72
+ self
73
+ end
74
+
75
+ def merge(s)
76
+ Substitution.new(dictionary: dictionary.dup,
77
+ instance_type: instance_type,
78
+ module_type: module_type,
79
+ self_type: self_type).merge!(s)
58
80
  end
59
81
 
60
82
  def add!(v, ty)
data/lib/steep/project.rb CHANGED
@@ -1,251 +1,43 @@
1
1
  module Steep
2
2
  class Project
3
- class SignatureLoaded
4
- attr_reader :check
5
- attr_reader :loaded_at
6
- attr_reader :file_paths
3
+ attr_reader :targets
4
+ attr_reader :base_dir
7
5
 
8
- def initialize(check:, loaded_at:, file_paths:)
9
- @check = check
10
- @loaded_at = loaded_at
11
- @file_paths = file_paths
12
- end
13
- end
14
-
15
- class SignatureHasSyntaxError
16
- attr_reader :errors
17
-
18
- def initialize(errors:)
19
- @errors = errors
20
- end
21
- end
22
-
23
- class SignatureHasError
24
- attr_reader :errors
25
-
26
- def initialize(errors:)
27
- @errors = errors
28
- end
29
- end
30
-
31
- attr_reader :source_files
32
- attr_reader :signature_files
33
- attr_reader :listener
34
-
35
- attr_reader :signature
36
-
37
- def initialize(listener = nil)
38
- @listener = listener || NullListener.new
39
- @source_files = {}
40
- @signature_files = {}
41
- end
42
-
43
- def clear
44
- listener.clear_project project: self do
45
- @signature = nil
46
- source_files.each_value do |file|
47
- file.invalidate
48
- end
49
- end
50
- end
6
+ def initialize(base_dir:)
7
+ @targets = []
8
+ @base_dir = base_dir
51
9
 
52
- def type_check(force_signatures: false, force_sources: false)
53
- listener.check(project: self) do
54
- should_reload_signature = force_signatures || signature_updated?
55
- reload_signature if should_reload_signature
56
-
57
- case sig = signature
58
- when SignatureLoaded
59
- each_updated_source(force: force_sources || should_reload_signature) do |file|
60
- file.invalidate
61
-
62
- listener.parse_source(project: self, file: file) do
63
- file.parse()
64
- end
65
-
66
- listener.type_check_source(project: self, file: file) do
67
- file.type_check(sig.check)
68
- end
69
- end
70
- end
71
- end
72
- end
73
-
74
- def success?
75
- signature.is_a?(SignatureLoaded) &&
76
- source_files.all? {|_, file| file.source.is_a?(Source) && file.typing }
77
- end
78
-
79
- def has_type_error?
80
- source_files.any? do |_, file|
81
- file.errors&.any?
82
- end
83
- end
84
-
85
- def errors
86
- source_files.flat_map do |_, file|
87
- file.errors || []
88
- end
89
- end
90
-
91
- # @type method each_updated_source: (?force: bool) ?{ (SourceFile) -> any } -> any
92
- def each_updated_source(force: false)
93
- if block_given?
94
- source_files.each_value do |file|
95
- if force || file.requires_type_check?
96
- yield file
97
- end
98
- end
99
- else
100
- enum_for :each_updated_source, force: force
10
+ unless base_dir.absolute?
11
+ raise "Project#initialize(base_dir:): base_dir should be absolute path"
101
12
  end
102
13
  end
103
14
 
104
- def signature_updated?
105
- case sig = signature
106
- when SignatureLoaded
107
- signature_files.keys != sig.file_paths ||
108
- signature_files.any? {|_, file| file.content_updated_at >= sig.loaded_at }
109
- else
110
- true
111
- end
15
+ def relative_path(path)
16
+ path.relative_path_from(base_dir)
112
17
  end
113
18
 
114
- def reload_signature
115
- @signature = nil
116
-
117
- env = AST::Signature::Env.new
118
- builder = Interface::Builder.new(signatures: env)
119
- check = Subtyping::Check.new(builder: builder)
120
-
121
- # @type var syntax_errors: Hash<Pathname, any>
122
- syntax_errors = {}
123
-
124
- listener.load_signature(project: self) do
125
- signature_files.each_value do |file|
126
- sigs = listener.parse_signature(project: self, file: file) do
127
- file.parse
128
- end
129
-
130
- sigs.each do |sig|
131
- env.add sig
132
- end
133
- rescue Racc::ParseError => exn
134
- Steep.logger.warn { "Syntax error on #{file.path}: #{exn.inspect}" }
135
- syntax_errors[file.path] = exn
136
- end
137
-
138
- if syntax_errors.empty?
139
- listener.validate_signature(project: self) do
140
- errors = validate_signature(check)
141
- @signature = if errors.empty?
142
- SignatureLoaded.new(check: check, loaded_at: Time.now, file_paths: signature_files.keys)
143
- else
144
- SignatureHasError.new(errors: errors)
145
- end
146
- end
147
- else
148
- @signature = SignatureHasSyntaxError.new(errors: syntax_errors)
149
- end
150
- end
19
+ def absolute_path(path)
20
+ (base_dir + path).cleanpath
151
21
  end
152
22
 
153
- def validate_signature(check)
154
- errors = []
155
-
156
- builder = check.builder
23
+ def type_of_node(path:, line:, column:)
24
+ source_file = targets.map {|target| target.source_files[path] }.compact[0]
157
25
 
158
- check.builder.signatures.each do |sig|
159
- Steep.logger.debug { "Validating signature: #{sig.inspect}" }
26
+ if source_file
27
+ case (status = source_file.status)
28
+ when SourceFile::TypeCheckStatus
29
+ node = status.source.find_node(line: line, column: column)
160
30
 
161
- case sig
162
- when AST::Signature::Interface
163
- yield_self do
164
- instance_interface = builder.build_interface(sig.name)
165
-
166
- args = instance_interface.params.map {|var| AST::Types::Var.fresh(var) }
167
- instance_type = AST::Types::Name::Interface.new(name: sig.name, args: args)
168
-
169
- instance_interface.instantiate(type: instance_type,
170
- args: args,
171
- instance_type: instance_type,
172
- module_type: nil).validate(check)
31
+ type = begin
32
+ status.typing.type_of(node: node)
33
+ rescue RuntimeError
34
+ AST::Builtin.any_type
173
35
  end
174
36
 
175
- when AST::Signature::Module
176
- yield_self do
177
- instance_interface = builder.build_instance(sig.name)
178
- instance_args = instance_interface.params.map {|var| AST::Types::Var.fresh(var) }
179
-
180
- module_interface = builder.build_module(sig.name)
181
- module_args = module_interface.params.map {|var| AST::Types::Var.fresh(var) }
182
-
183
- instance_type = AST::Types::Name::Instance.new(name: sig.name, args: instance_args)
184
- module_type = AST::Types::Name::Module.new(name: sig.name)
185
-
186
- Steep.logger.debug { "Validating instance methods..." }
187
- instance_interface.instantiate(type: instance_type,
188
- args: instance_args,
189
- instance_type: instance_type,
190
- module_type: module_type).validate(check)
191
-
192
- Steep.logger.debug { "Validating class methods..." }
193
- module_interface.instantiate(type: module_type,
194
- args: module_args,
195
- instance_type: instance_type,
196
- module_type: module_type).validate(check)
197
- end
198
-
199
- when AST::Signature::Class
200
- yield_self do
201
- instance_interface = builder.build_instance(sig.name)
202
- instance_args = instance_interface.params.map {|var| AST::Types::Var.fresh(var) }
203
-
204
- module_interface = builder.build_class(sig.name, constructor: true)
205
- module_args = module_interface.params.map {|var| AST::Types::Var.fresh(var) }
206
-
207
- instance_type = AST::Types::Name::Instance.new(name: sig.name, args: instance_args)
208
- module_type = AST::Types::Name::Class.new(name: sig.name, constructor: true)
209
-
210
- Steep.logger.debug { "Validating instance methods..." }
211
- instance_interface.instantiate(type: instance_type,
212
- args: instance_args,
213
- instance_type: instance_type,
214
- module_type: module_type).validate(check)
215
-
216
- Steep.logger.debug { "Validating class methods..." }
217
- module_interface.instantiate(type: module_type,
218
- args: module_args,
219
- instance_type: instance_type,
220
- module_type: module_type).validate(check)
221
- end
222
- end
223
-
224
- rescue => exn
225
- errors << exn
226
- end
227
-
228
- errors
229
- end
230
-
231
- def type_of(path:, line:, column:)
232
- if source_file = source_files[path]
233
- case source = source_file.source
234
- when Source
235
- if typing = source_file.typing
236
- node = source.find_node(line: line, column: column)
237
-
238
- type = begin
239
- typing.type_of(node: node)
240
- rescue RuntimeError
241
- AST::Builtin.any_type
242
- end
243
-
244
- if block_given?
245
- yield type, node
246
- else
247
- type
248
- end
37
+ if block_given?
38
+ yield type, node
39
+ else
40
+ type
249
41
  end
250
42
  end
251
43
  end
@@ -0,0 +1,132 @@
1
+ module Steep
2
+ class Project
3
+ class DSL
4
+ class TargetDSL
5
+ attr_reader :name
6
+ attr_reader :sources
7
+ attr_reader :libraries
8
+ attr_reader :signatures
9
+ attr_reader :ignored_sources
10
+ attr_reader :no_builtin
11
+ attr_reader :vendor_dir
12
+
13
+ def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [])
14
+ @name = name
15
+ @sources = sources
16
+ @libraries = libraries
17
+ @signatures = signatures
18
+ @ignored_sources = ignored_sources
19
+ @vendor_dir = nil
20
+ end
21
+
22
+ def initialize_copy(other)
23
+ @name = other.name
24
+ @sources = other.sources.dup
25
+ @libraries = other.libraries.dup
26
+ @signatures = other.signatures.dup
27
+ @ignored_sources = other.ignored_sources.dup
28
+ @vendor_dir = other.vendor_dir
29
+ end
30
+
31
+ def check(*args)
32
+ sources.push(*args)
33
+ end
34
+
35
+ def ignore(*args)
36
+ ignored_sources.push(*args)
37
+ end
38
+
39
+ def library(*args)
40
+ libraries.push(*args)
41
+ end
42
+
43
+ def signature(*args)
44
+ signatures.push(*args)
45
+ end
46
+
47
+ def update(name: self.name, sources: self.sources, libraries: self.libraries, ignored_sources: self.ignored_sources, signatures: self.signatures)
48
+ self.class.new(
49
+ name,
50
+ sources: sources,
51
+ libraries: libraries,
52
+ signatures: signatures,
53
+ ignored_sources: ignored_sources
54
+ )
55
+ end
56
+
57
+ def no_builtin!(value = true)
58
+ Steep.logger.error "`no_builtin!` in Steepfile is deprecated and ignored. Use `vendor` instead."
59
+ end
60
+
61
+ def vendor(dir = "vendor/sigs", stdlib: nil, gems: nil)
62
+ if stdlib || gems
63
+ @vendor_dir = [
64
+ stdlib&.yield_self {|x| Pathname(x) },
65
+ gems&.yield_self {|x| Pathname(x) }
66
+ ]
67
+ else
68
+ @vendor_dir = Pathname(dir)
69
+ end
70
+ end
71
+ end
72
+
73
+ attr_reader :project
74
+
75
+ @@templates = {
76
+ gemfile: TargetDSL.new(:gemfile).tap do |target|
77
+ target.check "Gemfile"
78
+ target.library "gemfile"
79
+ end
80
+ }
81
+
82
+ def self.templates
83
+ @@templates
84
+ end
85
+
86
+ def initialize(project:)
87
+ @project = project
88
+ @global_signatures = []
89
+ end
90
+
91
+ def self.register_template(name, target)
92
+ templates[name] = target
93
+ end
94
+
95
+ def self.parse(project, code, filename: "Steepfile")
96
+ self.new(project: project).instance_eval(code, filename)
97
+ end
98
+
99
+ def target(name, template: nil, &block)
100
+ target = if template
101
+ self.class.templates[template]&.dup&.update(name: name) or
102
+ raise "Unknown template: #{template}, available templates: #{@@templates.keys.join(", ")}"
103
+ else
104
+ TargetDSL.new(name)
105
+ end
106
+
107
+ target.instance_eval(&block) if block_given?
108
+
109
+ Project::Target.new(
110
+ name: target.name,
111
+ source_patterns: target.sources,
112
+ ignore_patterns: target.ignored_sources,
113
+ signature_patterns: target.signatures,
114
+ options: Options.new.tap do |options|
115
+ options.libraries.push(*target.libraries)
116
+
117
+ case target.vendor_dir
118
+ when Array
119
+ options.vendored_stdlib_path = target.vendor_dir[0]
120
+ options.vendored_gems_path = target.vendor_dir[1]
121
+ when Pathname
122
+ options.vendored_stdlib_path = target.vendor_dir + "stdlib"
123
+ options.vendored_gems_path = target.vendor_dir + "gems"
124
+ end
125
+ end
126
+ ).tap do |target|
127
+ project.targets << target
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -1,101 +1,108 @@
1
1
  module Steep
2
2
  class Project
3
3
  class SourceFile
4
- attr_reader :options
5
4
  attr_reader :path
6
5
  attr_reader :content
7
6
  attr_reader :content_updated_at
7
+ attr_reader :factory
8
8
 
9
- attr_reader :source
10
- attr_reader :typing
11
- attr_reader :last_type_checked_at
9
+ attr_accessor :status
12
10
 
13
- def initialize(path:, options:)
11
+ ParseErrorStatus = Struct.new(:error, keyword_init: true)
12
+ AnnotationSyntaxErrorStatus = Struct.new(:error, :location, keyword_init: true)
13
+ TypeCheckStatus = Struct.new(:typing, :source, :timestamp, keyword_init: true)
14
+
15
+ def initialize(path:)
14
16
  @path = path
15
- @options = options
17
+ @content = false
16
18
  self.content = ""
17
19
  end
18
20
 
19
21
  def content=(content)
20
- @content_updated_at = Time.now
21
- @content = content
22
- end
23
-
24
- def requires_type_check?
25
- if last = last_type_checked_at
26
- last < content_updated_at
27
- else
28
- true
22
+ if @content != content
23
+ @content_updated_at = Time.now
24
+ @content = content
25
+ @status = nil
29
26
  end
30
27
  end
31
28
 
32
- def invalidate
33
- @source = nil
34
- @typing = nil
35
- @last_type_checked_at = nil
36
- end
37
-
38
- def parse
39
- _ = @source =
40
- begin
41
- Source.parse(content, path: path.to_s, labeling: ASTUtils::Labeling.new)
42
- rescue ::Parser::SyntaxError => exn
43
- Steep.logger.warn { "Syntax error on #{path}: #{exn.inspect}" }
44
- exn
45
- rescue EncodingError => exn
46
- Steep.logger.warn { "Encoding error on #{path}: #{exn.inspect}" }
47
- exn
48
- end
49
- end
50
-
51
29
  def errors
52
- typing&.errors&.reject do |error|
53
- case
54
- when error.is_a?(Errors::FallbackAny)
55
- !options.fallback_any_is_error
56
- when error.is_a?(Errors::MethodDefinitionMissing)
57
- options.allow_missing_definitions
58
- end
30
+ case status
31
+ when TypeCheckStatus
32
+ status.typing.errors
33
+ # errors.reject do |error|
34
+ # case
35
+ # when error.is_a?(Errors::FallbackAny)
36
+ # !options.fallback_any_is_error
37
+ # when error.is_a?(Errors::MethodDefinitionMissing)
38
+ # options.allow_missing_definitions
39
+ # end
40
+ # end
41
+ else
42
+ []
59
43
  end
60
44
  end
61
45
 
62
- def type_check(check)
63
- case source = self.source
64
- when Source
65
- @typing = Typing.new
66
-
67
- annotations = source.annotations(block: source.node, builder: check.builder, current_module: AST::Namespace.root)
68
-
69
- const_env = TypeInference::ConstantEnv.new(builder: check.builder, context: nil)
70
- type_env = TypeInference::TypeEnv.build(annotations: annotations,
71
- subtyping: check,
72
- const_env: const_env,
73
- signatures: check.builder.signatures)
46
+ def type_check(subtyping, env_updated_at)
47
+ # skip type check
48
+ return false if status.is_a?(TypeCheckStatus) && env_updated_at <= status.timestamp
49
+
50
+ parse(subtyping.factory) do |source|
51
+ typing = Typing.new
52
+
53
+ if source
54
+ annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: AST::Namespace.root)
55
+ const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: nil)
56
+ type_env = TypeInference::TypeEnv.build(annotations: annotations,
57
+ subtyping: subtyping,
58
+ const_env: const_env,
59
+ signatures: subtyping.factory.env)
60
+
61
+ construction = TypeConstruction.new(
62
+ checker: subtyping,
63
+ annotations: annotations,
64
+ source: source,
65
+ self_type: AST::Builtin::Object.instance_type,
66
+ block_context: nil,
67
+ module_context: TypeConstruction::ModuleContext.new(
68
+ instance_type: nil,
69
+ module_type: nil,
70
+ implement_name: nil,
71
+ current_namespace: AST::Namespace.root,
72
+ const_env: const_env,
73
+ class_name: nil
74
+ ),
75
+ method_context: nil,
76
+ typing: typing,
77
+ break_context: nil,
78
+ type_env: type_env
79
+ )
80
+
81
+ construction.synthesize(source.node)
82
+ end
74
83
 
75
- construction = TypeConstruction.new(
76
- checker: check,
77
- annotations: annotations,
78
- source: source,
79
- self_type: AST::Builtin::Object.instance_type,
80
- block_context: nil,
81
- module_context: TypeConstruction::ModuleContext.new(
82
- instance_type: nil,
83
- module_type: nil,
84
- implement_name: nil,
85
- current_namespace: AST::Namespace.root,
86
- const_env: const_env,
87
- class_name: nil
88
- ),
89
- method_context: nil,
84
+ @status = TypeCheckStatus.new(
90
85
  typing: typing,
91
- break_context: nil,
92
- type_env: type_env
86
+ source: source,
87
+ timestamp: Time.now
93
88
  )
89
+ end
94
90
 
95
- construction.synthesize(source.node)
91
+ true
92
+ end
96
93
 
97
- @last_type_checked_at = Time.now
94
+ def parse(factory)
95
+ if status.is_a?(TypeCheckStatus)
96
+ yield status.source
97
+ else
98
+ yield Source.parse(content, path: path.to_s, factory: factory, labeling: ASTUtils::Labeling.new)
98
99
  end
100
+ rescue AnnotationParser::SyntaxError => exn
101
+ Steep.logger.warn { "Annotation syntax error on #{path}: #{exn.inspect}" }
102
+ @status = AnnotationSyntaxErrorStatus.new(error: exn, location: exn.location)
103
+ rescue ::Parser::SyntaxError, EncodingError => exn
104
+ Steep.logger.warn { "Source parsing error on #{path}: #{exn.inspect}" }
105
+ @status = ParseErrorStatus.new(error: exn)
99
106
  end
100
107
  end
101
108
 
@@ -104,18 +111,28 @@ module Steep
104
111
  attr_reader :content
105
112
  attr_reader :content_updated_at
106
113
 
114
+ attr_reader :status
115
+
116
+ ParseErrorStatus = Struct.new(:error, keyword_init: true)
117
+ DeclarationsStatus = Struct.new(:declarations, keyword_init: true)
118
+
107
119
  def initialize(path:)
108
120
  @path = path
109
121
  self.content = ""
110
122
  end
111
123
 
112
- def parse
113
- Parser.parse_signature(content, name: path)
114
- end
115
-
116
124
  def content=(content)
117
125
  @content_updated_at = Time.now
118
126
  @content = content
127
+ @status = nil
128
+ end
129
+
130
+ def load!
131
+ buffer = Ruby::Signature::Buffer.new(name: path, content: content)
132
+ decls = Ruby::Signature::Parser.parse_signature(buffer)
133
+ @status = DeclarationsStatus.new(declarations: decls)
134
+ rescue Ruby::Signature::Parser::SyntaxError, Ruby::Signature::Parser::SemanticsError => exn
135
+ @status = ParseErrorStatus.new(error: exn)
119
136
  end
120
137
  end
121
138
  end