steep 0.40.0 → 0.44.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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +1 -0
  4. data/bin/output_rebaseline.rb +15 -30
  5. data/bin/output_test.rb +23 -57
  6. data/lib/steep.rb +89 -15
  7. data/lib/steep/annotation_parser.rb +10 -2
  8. data/lib/steep/ast/types/class.rb +4 -0
  9. data/lib/steep/cli.rb +31 -6
  10. data/lib/steep/diagnostic/ruby.rb +13 -8
  11. data/lib/steep/diagnostic/signature.rb +152 -2
  12. data/lib/steep/drivers/annotations.rb +18 -36
  13. data/lib/steep/drivers/check.rb +140 -31
  14. data/lib/steep/drivers/diagnostic_printer.rb +20 -11
  15. data/lib/steep/drivers/langserver.rb +4 -8
  16. data/lib/steep/drivers/print_project.rb +10 -9
  17. data/lib/steep/drivers/stats.rb +135 -119
  18. data/lib/steep/drivers/utils/driver_helper.rb +35 -0
  19. data/lib/steep/drivers/utils/jobs_count.rb +9 -0
  20. data/lib/steep/drivers/validate.rb +29 -18
  21. data/lib/steep/drivers/watch.rb +55 -49
  22. data/lib/steep/drivers/worker.rb +11 -8
  23. data/lib/steep/expectations.rb +159 -0
  24. data/lib/steep/index/signature_symbol_provider.rb +23 -1
  25. data/lib/steep/index/source_index.rb +55 -5
  26. data/lib/steep/interface/block.rb +4 -0
  27. data/lib/steep/project.rb +0 -30
  28. data/lib/steep/project/dsl.rb +5 -3
  29. data/lib/steep/project/pattern.rb +56 -0
  30. data/lib/steep/project/target.rb +11 -227
  31. data/lib/steep/server/base_worker.rb +1 -3
  32. data/lib/steep/server/change_buffer.rb +63 -0
  33. data/lib/steep/server/interaction_worker.rb +72 -57
  34. data/lib/steep/server/master.rb +652 -234
  35. data/lib/steep/server/type_check_worker.rb +304 -0
  36. data/lib/steep/server/worker_process.rb +16 -11
  37. data/lib/steep/{project → services}/completion_provider.rb +5 -5
  38. data/lib/steep/services/content_change.rb +61 -0
  39. data/lib/steep/services/file_loader.rb +48 -0
  40. data/lib/steep/services/goto_service.rb +321 -0
  41. data/lib/steep/{project → services}/hover_content.rb +19 -20
  42. data/lib/steep/services/path_assignment.rb +27 -0
  43. data/lib/steep/services/signature_service.rb +403 -0
  44. data/lib/steep/services/stats_calculator.rb +69 -0
  45. data/lib/steep/services/type_check_service.rb +413 -0
  46. data/lib/steep/signature/validator.rb +187 -85
  47. data/lib/steep/source.rb +21 -18
  48. data/lib/steep/subtyping/check.rb +246 -45
  49. data/lib/steep/subtyping/constraints.rb +4 -4
  50. data/lib/steep/type_construction.rb +428 -193
  51. data/lib/steep/type_inference/block_params.rb +1 -1
  52. data/lib/steep/type_inference/context.rb +22 -0
  53. data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
  54. data/lib/steep/type_inference/logic.rb +1 -1
  55. data/lib/steep/type_inference/logic_type_interpreter.rb +4 -4
  56. data/lib/steep/type_inference/type_env.rb +43 -17
  57. data/lib/steep/version.rb +1 -1
  58. data/smoke/alias/test_expectations.yml +96 -0
  59. data/smoke/and/test_expectations.yml +31 -0
  60. data/smoke/array/test_expectations.yml +103 -0
  61. data/smoke/block/test_expectations.yml +125 -0
  62. data/smoke/case/test_expectations.yml +47 -0
  63. data/smoke/class/test_expectations.yml +120 -0
  64. data/smoke/const/test_expectations.yml +129 -0
  65. data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
  66. data/smoke/diagnostics-rbs/Steepfile +7 -4
  67. data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
  68. data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
  69. data/smoke/{broken → diagnostics-ruby-unsat}/Steepfile +0 -0
  70. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  71. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  72. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  73. data/smoke/diagnostics/a.rbs +0 -4
  74. data/smoke/diagnostics/test_expectations.yml +451 -0
  75. data/smoke/dstr/test_expectations.yml +13 -0
  76. data/smoke/ensure/test_expectations.yml +62 -0
  77. data/smoke/enumerator/test_expectations.yml +135 -0
  78. data/smoke/extension/f.rb +2 -0
  79. data/smoke/extension/f.rbs +3 -0
  80. data/smoke/extension/test_expectations.yml +73 -0
  81. data/smoke/hash/test_expectations.yml +81 -0
  82. data/smoke/hello/test_expectations.yml +25 -0
  83. data/smoke/if/test_expectations.yml +34 -0
  84. data/smoke/implements/b.rb +13 -0
  85. data/smoke/implements/b.rbs +12 -0
  86. data/smoke/implements/test_expectations.yml +23 -0
  87. data/smoke/initialize/test_expectations.yml +1 -0
  88. data/smoke/integer/test_expectations.yml +101 -0
  89. data/smoke/interface/test_expectations.yml +23 -0
  90. data/smoke/kwbegin/test_expectations.yml +17 -0
  91. data/smoke/lambda/test_expectations.yml +39 -0
  92. data/smoke/literal/test_expectations.yml +106 -0
  93. data/smoke/map/test_expectations.yml +1 -0
  94. data/smoke/method/test_expectations.yml +90 -0
  95. data/smoke/module/test_expectations.yml +75 -0
  96. data/smoke/regexp/test_expectations.yml +615 -0
  97. data/smoke/regression/issue_328.rb +1 -0
  98. data/smoke/regression/issue_328.rbs +0 -0
  99. data/smoke/regression/issue_332.rb +11 -0
  100. data/smoke/regression/issue_332.rbs +19 -0
  101. data/smoke/regression/issue_372.rb +8 -0
  102. data/smoke/regression/issue_372.rbs +4 -0
  103. data/smoke/regression/masgn.rb +4 -0
  104. data/smoke/regression/test_expectations.yml +60 -0
  105. data/smoke/regression/thread.rb +7 -0
  106. data/smoke/rescue/test_expectations.yml +79 -0
  107. data/smoke/self/test_expectations.yml +23 -0
  108. data/smoke/skip/test_expectations.yml +23 -0
  109. data/smoke/stdout/test_expectations.yml +1 -0
  110. data/smoke/super/test_expectations.yml +69 -0
  111. data/smoke/toplevel/test_expectations.yml +15 -0
  112. data/smoke/tsort/Steepfile +2 -0
  113. data/smoke/tsort/test_expectations.yml +63 -0
  114. data/smoke/type_case/test_expectations.yml +48 -0
  115. data/smoke/unexpected/Steepfile +5 -0
  116. data/smoke/unexpected/test_expectations.yml +25 -0
  117. data/smoke/unexpected/unexpected.rb +1 -0
  118. data/smoke/unexpected/unexpected.rbs +3 -0
  119. data/smoke/yield/test_expectations.yml +68 -0
  120. data/steep.gemspec +4 -3
  121. metadata +127 -80
  122. data/lib/steep/project/file_loader.rb +0 -68
  123. data/lib/steep/project/signature_file.rb +0 -39
  124. data/lib/steep/project/source_file.rb +0 -129
  125. data/lib/steep/project/stats_calculator.rb +0 -80
  126. data/lib/steep/server/code_worker.rb +0 -150
  127. data/lib/steep/server/signature_worker.rb +0 -157
  128. data/lib/steep/server/utils.rb +0 -69
  129. data/smoke/alias/test.yaml +0 -73
  130. data/smoke/and/test.yaml +0 -24
  131. data/smoke/array/test.yaml +0 -80
  132. data/smoke/block/test.yaml +0 -96
  133. data/smoke/broken/broken.rb +0 -0
  134. data/smoke/broken/broken.rbs +0 -0
  135. data/smoke/broken/test.yaml +0 -6
  136. data/smoke/case/test.yaml +0 -36
  137. data/smoke/class/test.yaml +0 -89
  138. data/smoke/const/test.yaml +0 -96
  139. data/smoke/diagnostics-rbs-duplicated/test.yaml +0 -10
  140. data/smoke/diagnostics-rbs/test.yaml +0 -142
  141. data/smoke/diagnostics/test.yaml +0 -333
  142. data/smoke/dstr/test.yaml +0 -10
  143. data/smoke/ensure/test.yaml +0 -47
  144. data/smoke/enumerator/test.yaml +0 -100
  145. data/smoke/extension/test.yaml +0 -50
  146. data/smoke/hash/test.yaml +0 -62
  147. data/smoke/hello/test.yaml +0 -18
  148. data/smoke/if/test.yaml +0 -27
  149. data/smoke/implements/test.yaml +0 -16
  150. data/smoke/initialize/test.yaml +0 -4
  151. data/smoke/integer/test.yaml +0 -66
  152. data/smoke/interface/test.yaml +0 -16
  153. data/smoke/kwbegin/test.yaml +0 -14
  154. data/smoke/lambda/test.yaml +0 -28
  155. data/smoke/literal/test.yaml +0 -79
  156. data/smoke/map/test.yaml +0 -4
  157. data/smoke/method/test.yaml +0 -71
  158. data/smoke/module/test.yaml +0 -51
  159. data/smoke/regexp/test.yaml +0 -372
  160. data/smoke/regression/test.yaml +0 -38
  161. data/smoke/rescue/test.yaml +0 -60
  162. data/smoke/self/test.yaml +0 -16
  163. data/smoke/skip/test.yaml +0 -16
  164. data/smoke/stdout/test.yaml +0 -4
  165. data/smoke/super/test.yaml +0 -52
  166. data/smoke/toplevel/test.yaml +0 -12
  167. data/smoke/tsort/test.yaml +0 -32
  168. data/smoke/type_case/test.yaml +0 -33
  169. data/smoke/yield/test.yaml +0 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 725a6432404ca94fa643ba89ed2028d7b3923ece4031512ebea88ebbdc4fd01e
4
- data.tar.gz: 957a95acbda38474f1a796f829f8cf098b69484a8ddf42bd39e2c2be935a961e
3
+ metadata.gz: 9f5bbaa95e53fda280f5b1c239c0c72093d51cbb6ca0699dbc5c580bcd857989
4
+ data.tar.gz: c9d4c6e70696e7f85d17b872ca6cec7088f9ee44d9768e9341564fc48e0b8f65
5
5
  SHA512:
6
- metadata.gz: 363a04610a81d4652541c9e5856705f7317a8b4e92a2074dc460b5f34e19f8eb5bfd080826c3a61a41414668d22d0352e4b300d1ce09c659243ef8c06492fc22
7
- data.tar.gz: 33b8d47d5290acea68f1f07ee74a6129ad0a2568fff2ddc783b7910f2ed55ae2d6d6b6f0b1b90b8dea773bfab0c9cc7ccc70723ab5aee75db3e3a0f997b93fe9
6
+ metadata.gz: 21fb7999c14382b1e6f3d2ad6dba6ec1db2c9169c4620ee66c76ecff8bee8d198b4f972e2afc181405ba8f8f378ae16d07c070a3886135e92e3d788257c93d94
7
+ data.tar.gz: e06a0f4d2d5e726a749c79c8828d86f0de2c5494126d208ddaddc320fa7911b89eb5e051a231db0c97078d0f844b35a04552d47cbd3c8fe001c7213bea90f0ac
data/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.44.0 (2021-04-22)
6
+
7
+ * Implement LSP go to definition/implementation ([#371](https://github.com/soutaro/steep/pull/371), [#375](https://github.com/soutaro/steep/pull/375))
8
+ * Fix typing on passing optional block ([#373](https://github.com/soutaro/steep/pull/373))
9
+ * Do not crash when completion request `context` is missing ([#370](https://github.com/soutaro/steep/pull/370))
10
+ * Update RBS ([#376](https://github.com/soutaro/steep/pull/376))
11
+
12
+ ## 0.43.1 (2021-04-01)
13
+
14
+ * Fix LSP `textDocument/didSave` notification handling ([#368](https://github.com/soutaro/steep/issues/368))
15
+
16
+ ## 0.43.0 (2021-03-30)
17
+
18
+ * LSP responsiveness improvements ([\#352](https://github.com/soutaro/steep/issues/352))
19
+ * `@implements` annotation in blocks ([#338](https://github.com/soutaro/steep/issues/338))
20
+ * Better `steep stats` table formatting ([\#300](https://github.com/soutaro/steep/issues/300))
21
+ * Fix retry type checking ([\#293](https://github.com/soutaro/steep/issues/293))
22
+ * Better tuple type checking ([\#328](https://github.com/soutaro/steep/issues/328))
23
+ * Fix unexpected `add_call` error ([\#358](https://github.com/soutaro/steep/pull/358))
24
+ * Ignore passing nil as a block `&nil` ([\#356](https://github.com/soutaro/steep/pull/356))
25
+ * Better type checking for non-trivial block parameters ([\#354](https://github.com/soutaro/steep/pull/354))
26
+ * Avoid unexpected error on splat assignments ([\#330](https://github.com/soutaro/steep/pull/330))
27
+ * Fix constraint solver ([\#343](https://github.com/soutaro/steep/pull/343))
28
+ * Ruby 2.7 compatible private method call typing ([\#344](https://github.com/soutaro/steep/pull/344))
29
+
30
+ ## 0.42.0 (2021-03-08)
31
+
32
+ * Type checking performance improvement ([\#309](https://github.com/soutaro/steep/pull/309), [\#311](https://github.com/soutaro/steep/pull/311), [\#312](https://github.com/soutaro/steep/pull/312), [\#313](https://github.com/soutaro/steep/pull/313), [\#314](https://github.com/soutaro/steep/pull/314), [\#315](https://github.com/soutaro/steep/pull/315), [\#316](https://github.com/soutaro/steep/pull/316), [\#320](https://github.com/soutaro/steep/pull/320), [\#322](https://github.com/soutaro/steep/pull/322))
33
+ * Let `watch` command support files ([\#323](https://github.com/soutaro/steep/pull/323))
34
+ * Validate _module-self-type_ constraints ([\#308](https://github.com/soutaro/steep/pull/308))
35
+ * Add `-j` option to specify number of worker processes ([\#318](https://github.com/soutaro/steep/pull/318), [\#325](https://github.com/soutaro/steep/pull/325))
36
+ * Fix `code` of RBS diagnostics ([\#306](https://github.com/soutaro/steep/pull/306))
37
+ * Skip printing source code from out of date _expectations_ file ([\#305](https://github.com/soutaro/steep/pull/305))
38
+
39
+ ## 0.41.0 (2021-02-07)
40
+
41
+ * Add `--with-expectations` and `--save-expectations` option ([#303](https://github.com/soutaro/steep/pull/303))
42
+
5
43
  ## 0.40.0 (2021-01-31)
6
44
 
7
45
  * Report progress with dots ([#287](https://github.com/soutaro/steep/pull/287))
data/Gemfile CHANGED
@@ -12,3 +12,4 @@ gem "racc", "~> 1.4"
12
12
  gem "minitest-reporters"
13
13
  gem "minitest-hooks"
14
14
  gem "stackprof"
15
+ gem "rbs", git: "https://github.com/ruby/rbs.git"
@@ -9,41 +9,26 @@ else
9
9
  test_dirs = ARGV.map {|p| Pathname.pwd + p }
10
10
  end
11
11
 
12
- test_dirs.each do |dir|
13
- test = dir + "test.yaml"
14
-
15
- if test.file?
16
- content = YAML.load_file(test)
17
- else
18
- content = { "test" => {} }
19
- end
12
+ failed_tests = []
20
13
 
14
+ test_dirs.each do |dir|
21
15
  puts "Rebaselining #{dir}..."
22
16
 
23
- command = content["command"] || "steep check"
24
- puts " command: #{command}"
25
-
26
- output, _ = Open3.capture2(command, chdir: dir.to_s)
17
+ command = %w(steep check --save-expectations=test_expectations.yml)
18
+ puts " command: #{command.join(" ")}"
27
19
 
28
- diagnostics = output.split(/\n\n/).each.with_object({}) do |message, hash|
29
- if message =~ /\A([^:]+):\d+:\d+:/
30
- path = $1
31
- hash[path] ||= { "diagnostics" => [] }
32
- hash[path]["diagnostics"] << message.chomp + "\n"
33
- end
34
- end
20
+ output, status = Open3.capture2(*command, chdir: dir.to_s)
35
21
 
36
- content["test"].each_key do |path|
37
- unless diagnostics.key?(path)
38
- diagnostics[path] = { "diagnostics" => [] }
39
- end
40
- end
41
-
42
- content["test"] = diagnostics.keys.sort.each.with_object({}) do |key, hash|
43
- hash[key] = diagnostics[key]
22
+ unless status.success?
23
+ puts "Error!!! 👺"
24
+ failed_tests << dir.basename
44
25
  end
26
+ end
45
27
 
46
- test.open("w") do |io|
47
- YAML.dump(content, io, header: false)
48
- end
28
+ if failed_tests.empty?
29
+ puts "Successfully updated output expectations! 🤡"
30
+ else
31
+ puts "Failed to update the following tests! 💀"
32
+ puts " #{failed_tests.join(", ")}"
33
+ exit 1
49
34
  end
data/bin/output_test.rb CHANGED
@@ -14,21 +14,33 @@ else
14
14
  test_dirs = ARGV.map {|p| Pathname.pwd + p }
15
15
  end
16
16
 
17
- success = true
17
+ failed_tests = []
18
18
 
19
- test_dirs.each do |dir|
20
- test = dir + "test.yaml"
21
-
22
- next unless test.file?
19
+ ALLOW_FAILURE = ["diagnostics-ruby-unsat"]
23
20
 
21
+ test_dirs.each do |dir|
24
22
  puts "Running test #{dir}..."
25
23
 
26
- content = YAML.load_file(test)
24
+ unless (dir + "test_expectations.yml").file?
25
+ puts "Skipped ⛹️‍♀️"
26
+ next
27
+ end
28
+
29
+ command = %w(steep check --with-expectations=test_expectations.yml)
30
+ puts " command: #{command.join(" ")}"
27
31
 
28
- command = content["command"] || "steep check"
29
- puts " command: #{command}"
32
+ output, status = Open3.capture2(*command, chdir: dir.to_s)
30
33
 
31
- output, _ = Open3.capture2(command, chdir: dir.to_s)
34
+ unless status.success?
35
+ unless ALLOW_FAILURE.include?(dir.basename.to_s)
36
+ failed_tests << dir.basename
37
+ puts " Failed! 🤕"
38
+ else
39
+ puts " Failed! 🤕 (ALLOW_FAILURE)"
40
+ end
41
+ else
42
+ puts " Succeed! 👍"
43
+ end
32
44
 
33
45
  if @verbose
34
46
  puts " Raw output:"
@@ -36,58 +48,12 @@ test_dirs.each do |dir|
36
48
  puts " > #{line.chomp}"
37
49
  end
38
50
  end
39
-
40
- diagnostics = output.split(/\n\n/).each.with_object({}) do |d, hash|
41
- if d =~ /\A([^:]+):\d+:\d+:/
42
- path = $1
43
- hash[path] ||= []
44
- hash[path] << (d.chomp + "\n")
45
- end
46
- end
47
-
48
- content["test"].each do |path, test|
49
- puts " Checking: #{path}..."
50
-
51
- fail_expected = test["fail"] || false
52
-
53
- expected_diagnostics = test["diagnostics"]
54
- reported_diagnostics = (diagnostics[path] || [])
55
-
56
- puts " # of expected: #{expected_diagnostics.size}, # of reported: #{reported_diagnostics.size}"
57
-
58
- unexpected_diagnostics = reported_diagnostics.reject {|d| expected_diagnostics.include?(d) }
59
- missing_diagnostics = expected_diagnostics.reject {|d| reported_diagnostics.include?(d) }
60
-
61
- unexpected_diagnostics.each do |d|
62
- puts " Unexpected diagnostics:"
63
- d.split(/\n/).each do |line|
64
- puts " + #{line.chomp}"
65
- end
66
- end
67
-
68
- missing_diagnostics.each do |d|
69
- puts " Missing diagnostics:"
70
- d.split(/\n/).each do |line|
71
- puts " - #{line.chomp}"
72
- end
73
- end
74
-
75
- if unexpected_diagnostics.empty? && missing_diagnostics.empty?
76
- puts " 👍"
77
- else
78
- if fail_expected
79
- puts " 🚨 (expected failure)"
80
- else
81
- puts " 🚨"
82
- success = false
83
- end
84
- end
85
- end
86
51
  end
87
52
 
88
- if success
53
+ if failed_tests.empty?
89
54
  puts "All tests ok! 👏"
90
55
  else
91
56
  puts "Errors detected! 🤮"
57
+ puts " #{failed_tests.join(", ")}"
92
58
  exit 1
93
59
  end
data/lib/steep.rb CHANGED
@@ -2,8 +2,8 @@ require "steep/version"
2
2
 
3
3
  require "pathname"
4
4
  require "parser/ruby27"
5
- require "ast_utils"
6
5
  require "active_support/core_ext/object/try"
6
+ require "active_support/core_ext/string/inflections"
7
7
  require "logger"
8
8
  require "active_support/tagged_logging"
9
9
  require "rainbow"
@@ -13,6 +13,11 @@ require "etc"
13
13
  require "open3"
14
14
  require "stringio"
15
15
  require 'uri'
16
+ require "yaml"
17
+ require "securerandom"
18
+
19
+ require "parallel/processor_count"
20
+ require "terminal-table"
16
21
 
17
22
  require "rbs"
18
23
 
@@ -84,25 +89,32 @@ require "steep/index/rbs_index"
84
89
  require "steep/index/signature_symbol_provider"
85
90
  require "steep/index/source_index"
86
91
 
87
- require "steep/server/utils"
92
+ require "steep/server/change_buffer"
88
93
  require "steep/server/base_worker"
89
- require "steep/server/code_worker"
90
- require "steep/server/signature_worker"
91
94
  require "steep/server/worker_process"
92
95
  require "steep/server/interaction_worker"
96
+ require "steep/server/type_check_worker"
93
97
  require "steep/server/master"
94
98
 
99
+ require "steep/services/content_change"
100
+ require "steep/services/path_assignment"
101
+ require "steep/services/signature_service"
102
+ require "steep/services/type_check_service"
103
+ require "steep/services/hover_content"
104
+ require "steep/services/completion_provider"
105
+ require "steep/services/stats_calculator"
106
+ require "steep/services/file_loader"
107
+ require "steep/services/goto_service"
108
+
95
109
  require "steep/project"
96
- require "steep/project/signature_file"
97
- require "steep/project/source_file"
110
+ require "steep/project/pattern"
98
111
  require "steep/project/options"
99
112
  require "steep/project/target"
100
113
  require "steep/project/dsl"
101
- require "steep/project/file_loader"
102
- require "steep/project/hover_content"
103
- require "steep/project/completion_provider"
104
- require "steep/project/stats_calculator"
114
+
115
+ require "steep/expectations"
105
116
  require "steep/drivers/utils/driver_helper"
117
+ require "steep/drivers/utils/jobs_count"
106
118
  require "steep/drivers/check"
107
119
  require "steep/drivers/stats"
108
120
  require "steep/drivers/validate"
@@ -130,7 +142,7 @@ module Steep
130
142
  def self.new_logger(output, prev_level)
131
143
  ActiveSupport::TaggedLogging.new(Logger.new(output)).tap do |logger|
132
144
  logger.push_tags "Steep #{VERSION}"
133
- logger.level = prev_level || Logger::WARN
145
+ logger.level = prev_level || Logger::ERROR
134
146
  end
135
147
  end
136
148
 
@@ -147,18 +159,80 @@ module Steep
147
159
  @logger = nil
148
160
  self.log_output = STDERR
149
161
 
150
- def self.measure(message)
162
+ def self.measure(message, level: :warn)
151
163
  start = Time.now
152
164
  yield.tap do
153
165
  time = Time.now - start
154
- self.logger.info "#{message} took #{time} seconds"
166
+ if level.is_a?(Symbol)
167
+ level = Logger.const_get(level.to_s.upcase)
168
+ end
169
+ self.logger.log(level) { "#{message} took #{time} seconds" }
155
170
  end
156
171
  end
157
172
 
158
173
  def self.log_error(exn, message: "Unexpected error: #{exn.inspect}")
159
- Steep.logger.error message
174
+ Steep.logger.fatal message
160
175
  exn.backtrace.each do |loc|
161
- Steep.logger.warn " #{loc}"
176
+ Steep.logger.error " #{loc}"
177
+ end
178
+ end
179
+
180
+ class Sampler
181
+ def initialize()
182
+ @samples = []
183
+ end
184
+
185
+ def sample(message)
186
+ start = Time.now
187
+ yield.tap do
188
+ time = Time.now - start
189
+ @samples << [message, time]
190
+ end
191
+ end
192
+
193
+ def count
194
+ @samples.count
195
+ end
196
+
197
+ def total
198
+ @samples.sum(&:last)
162
199
  end
200
+
201
+ def slowests(num)
202
+ @samples.sort_by(&:last).reverse.take(num)
203
+ end
204
+
205
+ def average
206
+ if count > 0
207
+ total/count
208
+ else
209
+ 0
210
+ end
211
+ end
212
+
213
+ def percentile(p)
214
+ slowests(count - count * p / 100r).last&.last || 0
215
+ end
216
+ end
217
+
218
+ def self.measure2(message, level: :warn)
219
+ sampler = Sampler.new
220
+ result = yield(sampler)
221
+
222
+ if level.is_a?(Symbol)
223
+ level = Logger.const_get(level.to_s.upcase)
224
+ end
225
+ logger.log(level) { "#{sampler.total}secs for \"#{message}\"" }
226
+ logger.log(level) { " Average: #{sampler.average}secs"}
227
+ logger.log(level) { " Median: #{sampler.percentile(50)}secs"}
228
+ logger.log(level) { " Samples: #{sampler.count}"}
229
+ logger.log(level) { " 99 percentile: #{sampler.percentile(99)}secs"}
230
+ logger.log(level) { " 90 percentile: #{sampler.percentile(90)}secs"}
231
+ logger.log(level) { " 10 Slowests:"}
232
+ sampler.slowests(10).each do |message, time|
233
+ logger.log(level) { " #{message} (#{time}secs)"}
234
+ end
235
+
236
+ result
163
237
  end
164
238
  end
@@ -23,7 +23,15 @@ module Steep
23
23
  def initialize(source:, location:, exn: nil)
24
24
  @source = source
25
25
  @location = location
26
- super "Syntax error on annotation: `#{source}`, cause=#{exn.inspect}"
26
+
27
+ message = case exn
28
+ when RBS::Parser::SyntaxError
29
+ Diagnostic::Signature::SyntaxError.parser_syntax_error_message(exn)
30
+ else
31
+ exn.message
32
+ end
33
+
34
+ super message
27
35
  end
28
36
  end
29
37
 
@@ -158,7 +166,7 @@ module Steep
158
166
  end
159
167
  end
160
168
 
161
- rescue RBS::Parser::SyntaxError, RBS::Parser::SemanticsError => exn
169
+ rescue RBS::ParsingError => exn
162
170
  raise SyntaxError.new(source: src, location: location, exn: exn)
163
171
  end
164
172
  end
@@ -8,6 +8,10 @@ module Steep
8
8
  @location = location
9
9
  end
10
10
 
11
+ def to_s
12
+ "class"
13
+ end
14
+
11
15
  def ==(other)
12
16
  other.is_a?(Class)
13
17
  end
data/lib/steep/cli.rb CHANGED
@@ -8,6 +8,8 @@ module Steep
8
8
  attr_reader :stderr
9
9
  attr_reader :command
10
10
 
11
+ include Parallel::ProcessorCount
12
+
11
13
  def initialize(stdout:, stdin:, stderr:, argv:)
12
14
  @stdout = stdout
13
15
  @stdin = stdin
@@ -51,19 +53,27 @@ module Steep
51
53
  end
52
54
 
53
55
  def handle_logging_options(opts)
54
- opts.on("--log-level=[debug,info,warn,error,fatal]") do |level|
56
+ opts.on("--log-level=LEVEL", "Specify log level: debug, info, warn, error, fatal") do |level|
55
57
  Steep.logger.level = level
56
58
  end
57
59
 
58
- opts.on("--log-output=[PATH]") do |file|
60
+ opts.on("--log-output=PATH", "Print logs to given path") do |file|
59
61
  Steep.log_output = file
60
62
  end
61
63
 
62
- opts.on("--verbose") do
64
+ opts.on("--verbose", "Set log level to debug") do
63
65
  Steep.logger.level = Logger::DEBUG
64
66
  end
65
67
  end
66
68
 
69
+ def handle_jobs_option(command, opts, modifier = 0)
70
+ default = physical_processor_count + modifier
71
+ command.jobs_count = default
72
+ opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
73
+ command.jobs_count = Integer(count)
74
+ end
75
+ end
76
+
67
77
  def process_init
68
78
  Drivers::Init.new(stdout: stdout, stderr: stderr).tap do |command|
69
79
  OptionParser.new do |opts|
@@ -83,6 +93,13 @@ module Steep
83
93
  opts.banner = "Usage: steep check [options] [sources]"
84
94
 
85
95
  opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
96
+ opts.on("--with-expectations[=PATH]", "Type check with expectations saved in PATH (or steep_expectations.yml)") do |path|
97
+ check.with_expectations_path = Pathname(path || "steep_expectations.yml")
98
+ end
99
+ opts.on("--save-expectations[=PATH]", "Save expectations with current type check result to PATH (or steep_expectations.yml)") do |path|
100
+ check.save_expectations_path = Pathname(path || "steep_expectations.yml")
101
+ end
102
+ handle_jobs_option check, opts
86
103
  handle_logging_options opts
87
104
  end.parse!(argv)
88
105
 
@@ -96,6 +113,8 @@ module Steep
96
113
  opts.banner = "Usage: steep stats [options] [sources]"
97
114
 
98
115
  opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
116
+ opts.on("--format=FORMAT", "Specify output format: csv, table") {|format| check.format = format }
117
+ handle_jobs_option check, opts
99
118
  handle_logging_options opts
100
119
  end.parse!(argv)
101
120
 
@@ -136,10 +155,12 @@ module Steep
136
155
  Drivers::Watch.new(stdout: stdout, stderr: stderr).tap do |command|
137
156
  OptionParser.new do |opts|
138
157
  opts.banner = "Usage: steep watch [options] [dirs]"
158
+ handle_jobs_option command, opts
139
159
  handle_logging_options opts
140
160
  end.parse!(argv)
141
161
 
142
- command.dirs.push *argv
162
+ dirs = argv.map {|dir| Pathname(dir) }
163
+ command.dirs.push(*dirs)
143
164
  end.run
144
165
  end
145
166
 
@@ -147,6 +168,7 @@ module Steep
147
168
  Drivers::Langserver.new(stdout: stdout, stderr: stderr, stdin: stdin).tap do |command|
148
169
  OptionParser.new do |opts|
149
170
  opts.on("--steepfile=PATH") {|path| command.steepfile = Pathname(path) }
171
+ handle_jobs_option command, opts, -1
150
172
  handle_logging_options opts
151
173
  end.parse!(argv)
152
174
  end.run
@@ -179,12 +201,15 @@ module Steep
179
201
  handle_logging_options opts
180
202
 
181
203
  opts.on("--interaction") { command.worker_type = :interaction }
182
- opts.on("--code") { command.worker_type = :code }
183
- opts.on("--signature") { command.worker_type = :signature }
204
+ opts.on("--typecheck") { command.worker_type = :typecheck }
184
205
  opts.on("--steepfile=PATH") {|path| command.steepfile = Pathname(path) }
185
206
  opts.on("--name=NAME") {|name| command.worker_name = name }
186
207
  opts.on("--delay-shutdown") { command.delay_shutdown = true }
208
+ opts.on("--max-index=COUNT") {|count| command.max_index = Integer(count) }
209
+ opts.on("--index=INDEX") {|index| command.index = Integer(index) }
187
210
  end.parse!(argv)
211
+
212
+ command.commandline_args.push(*argv)
188
213
  end.run
189
214
  end
190
215
  end