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
@@ -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