steep 1.9.0.dev.1 → 1.9.0.dev.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37bf13501b4d8d6e4b6fa5b0702e0a978a6488e674832e36168070788c1b3367
4
- data.tar.gz: 6184ef95ab4f594841ee4d7ef775a68df571bb21b981beff18e0a7cddd53ae7e
3
+ metadata.gz: 89c207623c288c2142cdcf7d7de7f404da4d160b5bc40c84210116a721ec4029
4
+ data.tar.gz: dfd95e726115676f4d293d312bd1f06afa6ea89336911e9887c8e4b5ee1167ff
5
5
  SHA512:
6
- metadata.gz: b1d51f5e77be8d2ea4ddb45982e2e4515afcb16453784feef442ec618ea9584bf75a52f12654ef63283367dc1d5a3cd5e10be71cd3e02f9cde71566402f86ed0
7
- data.tar.gz: 92e5a0e27efbf0cfc629ed7fbce8576e8a8657c6abd5abc8b11f4e51c7087d2ca2d36c6ba7415ce9d1d53ea994e42068a857cbabb7a64940ec476321346a2829
6
+ metadata.gz: c9800ef17d4108ff391642510701e12a0ec4e63035c74765ed1203fa9b62d964be10441d60890ab3c643dc8d0295dd2a68be5285126307f3cb401f517eaa799f
7
+ data.tar.gz: 3ef2c5d7bac4dd2d492df8e5c60322de6c06d9c33cec21e2a97e4608f235e41729f0383e0817cfd324213853cad4c34308b14f5a582eedda71d36828545d6840
data/Steepfile CHANGED
@@ -1,28 +1,51 @@
1
1
  D = Steep::Diagnostic
2
2
 
3
+ FileUtils.mkpath("tmp")
4
+ tmp_rbs_dir = Pathname("tmp/rbs-sig")
5
+
6
+ definition = Bundler::Definition.build(Pathname("Gemfile"), Pathname("Gemfile.lock"), nil)
7
+ rbs_dep = definition.dependencies.find {|dep| dep.name == "rbs" }
8
+ if (source = rbs_dep&.source).is_a?(Bundler::Source::Path)
9
+ unless tmp_rbs_dir.directory?
10
+ FileUtils.ln_s(Pathname.pwd + source.path + "sig", tmp_rbs_dir.to_s, force: true)
11
+ end
12
+ else
13
+ FileUtils.rm_f(tmp_rbs_dir)
14
+ library "rbs"
15
+ end
16
+
3
17
  target :app do
18
+ collection_config "rbs_collection.steep.yaml"
19
+
4
20
  check "lib"
5
21
  ignore "lib/steep/shims"
6
22
 
7
23
  signature "sig"
8
-
9
- collection_config "rbs_collection.steep.yaml"
24
+ ignore_signature "sig/test"
10
25
 
11
26
  configure_code_diagnostics(D::Ruby.strict) do |hash|
12
27
  end
13
28
 
14
- FileUtils.mkpath("tmp")
15
- tmp_rbs_dir = File.join("tmp", "rbs-sig")
29
+ if tmp_rbs_dir.directory?
30
+ signature tmp_rbs_dir.to_s
31
+ else
32
+ library "rbs"
33
+ end
34
+ end
35
+
36
+ target :test do
37
+ collection_config "rbs_collection.steep.yaml"
38
+
39
+ unreferenced!
40
+
41
+ check "test"
42
+ signature "sig/test"
43
+
44
+ configure_code_diagnostics(D::Ruby.lenient)
16
45
 
17
- definition = Bundler::Definition.build(Pathname("Gemfile"), Pathname("Gemfile.lock"), nil)
18
- rbs_dep = definition.dependencies.find {|dep| dep.name == "rbs" }
19
- if (source = rbs_dep&.source).is_a?(Bundler::Source::Path)
20
- unless Pathname(tmp_rbs_dir).exist?
21
- FileUtils.ln_s(Pathname.pwd + source.path + "sig", tmp_rbs_dir, force: true)
22
- end
23
- signature tmp_rbs_dir
46
+ if tmp_rbs_dir.directory?
47
+ signature tmp_rbs_dir.to_s
24
48
  else
25
- FileUtils.rm_f(tmp_rbs_dir)
26
49
  library "rbs"
27
50
  end
28
51
  end
data/bin/rbs-inline ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ BINSTUB_DIR=$(cd $(dirname $0); pwd)
4
+ GEMFILE=$(readlink -f ${BINSTUB_DIR}/../gemfile_steep/Gemfile)
5
+ ROOT_DIR=$(readlink -f ${BINSTUB_DIR}/..)
6
+
7
+ RBSINLINE="bundle exec --gemfile=${GEMFILE} rbs-inline"
8
+
9
+ if type "rbenv" > /dev/null 2>&1; then
10
+ RBSINLINE="rbenv exec ${RBSINLINE}"
11
+ else
12
+ if type "rvm" > /dev/null 2>&1; then
13
+ if [ -e ${ROOT_DIR}/.ruby-version ]; then
14
+ RBS="rvm ${ROOT_DIR} do ${RBSINLINE}"
15
+ fi
16
+ fi
17
+ fi
18
+
19
+ exec $RBSINLINE $@
data/lib/steep/cli.rb CHANGED
@@ -138,31 +138,22 @@ module Steep
138
138
  command.type_check_code = v ? true : false
139
139
  end
140
140
 
141
- opts.on("--validate=OPTION", ["skip", "group", "target", "project", "library"], "Validation levels of signatures (default: group, options: skip,group,target,project,library)") do |level|
141
+ opts.on("--validate=OPTION", ["skip", "group", "project", "library"], "Validation levels of signatures (default: group, options: skip,group,project,library)") do |level|
142
142
  case level
143
143
  when "skip"
144
144
  command.validate_group_signatures = false
145
- command.validate_target_signatures = false
146
145
  command.validate_project_signatures = false
147
146
  command.validate_library_signatures = false
148
147
  when "group"
149
148
  command.validate_group_signatures = true
150
- command.validate_target_signatures = false
151
- command.validate_project_signatures = false
152
- command.validate_library_signatures = false
153
- when "target"
154
- command.validate_group_signatures = true
155
- command.validate_target_signatures = true
156
149
  command.validate_project_signatures = false
157
150
  command.validate_library_signatures = false
158
151
  when "project"
159
152
  command.validate_group_signatures = true
160
- command.validate_target_signatures = true
161
153
  command.validate_project_signatures = true
162
154
  command.validate_library_signatures = false
163
155
  when "library"
164
156
  command.validate_group_signatures = true
165
- command.validate_target_signatures = true
166
157
  command.validate_project_signatures = true
167
158
  command.validate_library_signatures = true
168
159
  end
@@ -917,6 +917,13 @@ module Steep
917
917
  end
918
918
  end
919
919
 
920
+ class UnannotatedEmptyCollection < Base
921
+ def header_line
922
+ node or raise
923
+ "Empty #{node.type} doesn't have type annotation"
924
+ end
925
+ end
926
+
920
927
  ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
921
928
  if klass < Base
922
929
  array << klass
@@ -963,6 +970,7 @@ module Steep
963
970
  SetterReturnTypeMismatch => :information,
964
971
  SyntaxError => :hint,
965
972
  TypeArgumentMismatchError => :hint,
973
+ UnannotatedEmptyCollection => :warning,
966
974
  UnexpectedBlockGiven => :warning,
967
975
  UnexpectedDynamicMethod => :hint,
968
976
  UnexpectedError => :hint,
@@ -1019,6 +1027,7 @@ module Steep
1019
1027
  SetterReturnTypeMismatch => :error,
1020
1028
  SyntaxError => :hint,
1021
1029
  TypeArgumentMismatchError => :error,
1030
+ UnannotatedEmptyCollection => :error,
1022
1031
  UnexpectedBlockGiven => :error,
1023
1032
  UnexpectedDynamicMethod => :information,
1024
1033
  UnexpectedError => :information,
@@ -1075,6 +1084,7 @@ module Steep
1075
1084
  SetterReturnTypeMismatch => nil,
1076
1085
  SyntaxError => :hint,
1077
1086
  TypeArgumentMismatchError => nil,
1087
+ UnannotatedEmptyCollection => :hint,
1078
1088
  UnexpectedBlockGiven => :hint,
1079
1089
  UnexpectedDynamicMethod => nil,
1080
1090
  UnexpectedError => :hint,
@@ -14,7 +14,6 @@ module Steep
14
14
  attr_reader :active_group_names
15
15
  attr_accessor :type_check_code
16
16
  attr_accessor :validate_group_signatures
17
- attr_accessor :validate_target_signatures
18
17
  attr_accessor :validate_project_signatures
19
18
  attr_accessor :validate_library_signatures
20
19
 
@@ -29,7 +28,6 @@ module Steep
29
28
  @active_group_names = []
30
29
  @type_check_code = true
31
30
  @validate_group_signatures = true
32
- @validate_target_signatures = false
33
31
  @validate_project_signatures = false
34
32
  @validate_library_signatures = false
35
33
  end
@@ -217,19 +215,17 @@ module Steep
217
215
  params[:signature_paths] << [target.name.to_s, target.project.absolute_path(path).to_s]
218
216
  end
219
217
  end
220
- if validate_target_signatures
221
- if group.is_a?(Project::Group)
222
- files.each_target_signature_path(target, group) do |path|
223
- params[:signature_paths] << [target.name.to_s, target.project.absolute_path(path).to_s]
224
- end
225
- end
226
- end
227
218
  if validate_project_signatures
228
219
  files.each_project_signature_path(target) do |path|
229
220
  if path_target = files.signature_path_target(path)
230
221
  params[:signature_paths] << [path_target.name.to_s, target.project.absolute_path(path).to_s]
231
222
  end
232
223
  end
224
+ if group.is_a?(Project::Group)
225
+ files.each_target_signature_path(target, group) do |path|
226
+ params[:signature_paths] << [target.name.to_s, target.project.absolute_path(path).to_s]
227
+ end
228
+ end
233
229
  end
234
230
  if validate_library_signatures
235
231
  files.each_library_path(target) do |path|
@@ -3,6 +3,7 @@ module Steep
3
3
  module Utils
4
4
  module DriverHelper
5
5
  attr_accessor :steepfile
6
+ attr_accessor :disable_install_collection
6
7
 
7
8
  def load_config(path: steepfile || Pathname("Steepfile"))
8
9
  if path.file?
@@ -25,17 +26,47 @@ module Steep
25
26
  case result = target.options.load_collection_lock
26
27
  when nil, RBS::Collection::Config::Lockfile
27
28
  # ok
28
- else
29
+ when Pathname
30
+ # File is missing
29
31
  if result == target.options.collection_config_path
30
- Steep.ui_logger.error { "rbs-collection setup is broken: `#{result}` is missing" }
32
+ # Config file is missing
33
+ Steep.ui_logger.error { "rbs-collection configuration is missing: `#{result}`" }
31
34
  else
32
- Steep.ui_logger.error { "Run `rbs collection install` to install type definitions" }
35
+ # Lockfile is missing
36
+ Steep.ui_logger.error { "Run `rbs collection install` to generate missing lockfile: `#{result}`" }
37
+ end
38
+ when YAML::SyntaxError
39
+ # File is broken
40
+ Steep.ui_logger.error { "rbs-collection setup is broken:\nsyntax error #{result.inspect}" }
41
+ when RBS::Collection::Config::CollectionNotAvailable
42
+ unless disable_install_collection
43
+ install_collection(target, target.options.collection_config_path || raise)
44
+ else
45
+ Steep.ui_logger.error { "Run `rbs collection install` to set up RBS files for gems" }
33
46
  end
34
47
  end
35
48
  end
36
49
  end
37
50
  end
38
51
 
52
+ def install_collection(target, config_path)
53
+ Steep.ui_logger.info { "Installing RBS files for collection: #{config_path}" }
54
+ lockfile_path = RBS::Collection::Config.to_lockfile_path(config_path)
55
+ io = StringIO.new
56
+ begin
57
+ RBS::Collection::Installer.new(lockfile_path: lockfile_path, stdout: io).install_from_lockfile()
58
+ target.options.load_collection_lock(force: true)
59
+ Steep.ui_logger.debug { "Finished setting up RBS collection: " + io.string }
60
+
61
+ result = target.options.load_collection_lock(force: true)
62
+ unless result.is_a?(RBS::Collection::Config::Lockfile)
63
+ raise "Failed to set up RBS collection: #{result.inspect}"
64
+ end
65
+ rescue => exn
66
+ Steep.ui_logger.error { "Failed to set up RBS collection: #{exn.inspect}" }
67
+ end
68
+ end
69
+
39
70
  def request_id
40
71
  SecureRandom.alphanumeric(10)
41
72
  end
@@ -50,6 +50,10 @@ module Steep
50
50
  patterns.any? {|pat| File.fnmatch(pat, string, File::FNM_PATHNAME) } ||
51
51
  prefixes.any? {|prefix| File.fnmatch("#{prefix}**/*#{ext}", string, File::FNM_PATHNAME) }
52
52
  end
53
+
54
+ def empty?
55
+ patterns.empty?
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -29,6 +29,14 @@ module Steep
29
29
  end
30
30
  end
31
31
 
32
+ module TypeCheckGroups
33
+ METHOD = "$/steep/typecheck/groups"
34
+
35
+ def self.notification(params)
36
+ { method: METHOD, params: params }
37
+ end
38
+ end
39
+
32
40
  module TypeCheck__Start
33
41
  METHOD = "$/steep/typecheck/start"
34
42
 
@@ -56,6 +64,14 @@ module Steep
56
64
  { id: id, result: result }
57
65
  end
58
66
  end
67
+
68
+ module Groups
69
+ METHOD = "$/steep/groups"
70
+
71
+ def self.response(id, result)
72
+ { id: id, result: result }
73
+ end
74
+ end
59
75
  end
60
76
  end
61
77
  end
@@ -382,7 +382,11 @@ module Steep
382
382
  declaration_provider: false,
383
383
  implementation_provider: true,
384
384
  type_definition_provider: true
385
- )
385
+ ),
386
+ server_info: {
387
+ name: "steep",
388
+ version: VERSION
389
+ }
386
390
  )
387
391
  }
388
392
  )
@@ -657,6 +661,18 @@ module Steep
657
661
 
658
662
  start_type_check(request: request, last_request: nil)
659
663
 
664
+ when CustomMethods::TypeCheckGroups::METHOD
665
+ params = message[:params] #: CustomMethods::TypeCheckGroups::params
666
+
667
+ groups = params.fetch(:groups)
668
+
669
+ progress = work_done_progress(SecureRandom.uuid)
670
+ progress.begin("Type checking #{groups.empty? ? "project" : groups.join(", ")}", request_id: fresh_request_id)
671
+
672
+ request = controller.make_group_request(groups, progress: progress)
673
+ request.needs_response = false
674
+ start_type_check(request: request, last_request: current_type_check_request, report_progress_threshold: 0)
675
+
660
676
  when "$/ping"
661
677
  enqueue_write_job SendMessageJob.to_client(
662
678
  message: {
@@ -665,6 +681,25 @@ module Steep
665
681
  }
666
682
  )
667
683
 
684
+ when CustomMethods::Groups::METHOD
685
+ groups = [] #: Array[String]
686
+
687
+ project.targets.each do |target|
688
+ unless target.source_pattern.empty? && target.signature_pattern.empty?
689
+ groups << target.name.to_s
690
+ end
691
+
692
+ target.groups.each do |group|
693
+ unless group.source_pattern.empty? && group.signature_pattern.empty?
694
+ groups << "#{target.name}.#{group.name}"
695
+ end
696
+ end
697
+ end
698
+
699
+ enqueue_write_job(SendMessageJob.to_client(
700
+ message: CustomMethods::Groups.response(message[:id], groups)
701
+ ))
702
+
668
703
  when "shutdown"
669
704
  start_type_checking_queue.cancel
670
705
 
@@ -254,6 +254,50 @@ module Steep
254
254
  end
255
255
  end
256
256
 
257
+ def make_group_request(groups, progress:)
258
+ TypeCheckController::Request.new(guid: progress.guid, progress: progress).tap do |request|
259
+ if groups.empty?
260
+ files.signature_paths.each do |path, target_group|
261
+ target_group = target_group.target if target_group.is_a?(Project::Group)
262
+ request.signature_paths << [target_group.name, path]
263
+ end
264
+ files.source_paths.each do |path, target_group|
265
+ target_group = target_group.target if target_group.is_a?(Project::Group)
266
+ request.code_paths << [target_group.name, path]
267
+ end
268
+ else
269
+ group_set = groups.map do |group_name|
270
+ target_name, group_name = group_name.split(".", 2)
271
+ target_name or raise
272
+
273
+ target_name = target_name.to_sym
274
+ group_name = group_name.to_sym if group_name
275
+
276
+ if group_name
277
+ if target = project.targets.find {|target| target.name == target_name }
278
+ target.groups.find {|group| group.name == group_name }
279
+ end
280
+ else
281
+ project.targets.find {|target| target.name == target_name }
282
+ end
283
+ end.compact.to_set
284
+
285
+ files.signature_paths.each do |path, target_group|
286
+ if group_set.include?(target_group)
287
+ target_group = target_group.target if target_group.is_a?(Project::Group)
288
+ request.signature_paths << [target_group.name, path]
289
+ end
290
+ end
291
+ files.source_paths.each do |path, target_group|
292
+ if group_set.include?(target_group)
293
+ target_group = target_group.target if target_group.is_a?(Project::Group)
294
+ request.code_paths << [target_group.name, path]
295
+ end
296
+ end
297
+ end
298
+ end
299
+ end
300
+
257
301
  def make_request(guid: SecureRandom.uuid, include_unchanged: false, progress:)
258
302
  TypeCheckController::Request.new(guid: guid, progress: progress).tap do |request|
259
303
  if include_unchanged
@@ -1436,7 +1436,7 @@ module Steep
1436
1436
  # ok
1437
1437
  else
1438
1438
  unless hint == pair.type
1439
- pair.constr.typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
1439
+ pair.constr.typing.add_error Diagnostic::Ruby::UnannotatedEmptyCollection.new(node: node)
1440
1440
  end
1441
1441
  end
1442
1442
  end
@@ -1704,7 +1704,7 @@ module Steep
1704
1704
  add_typing node, type: array
1705
1705
  end
1706
1706
  else
1707
- typing.add_error Diagnostic::Ruby::FallbackAny.new(node: node)
1707
+ typing.add_error Diagnostic::Ruby::UnannotatedEmptyCollection.new(node: node)
1708
1708
  add_typing node, type: AST::Builtin::Array.instance_type(AST::Builtin.any_type)
1709
1709
  end
1710
1710
  else
@@ -4763,6 +4763,15 @@ module Steep
4763
4763
 
4764
4764
  def try_tuple_type!(node, hint: nil)
4765
4765
  if node.type == :array
4766
+ if node.children.size == 1 && node.children[0]&.type == :splat
4767
+ # Skip the array construct
4768
+ splat_node = node.children[0] or raise
4769
+ splat_value = splat_node.children[0] or raise
4770
+
4771
+ type, constr = try_tuple_type!(splat_value, hint: hint)
4772
+ _, constr = constr.add_typing(splat_node, type: AST::Types::Any.instance)
4773
+ return constr.add_typing(node, type: type)
4774
+ end
4766
4775
  if hint.nil? || hint.is_a?(AST::Types::Tuple)
4767
4776
  typing.new_child() do |child_typing|
4768
4777
  if pair = with_new_typing(child_typing).try_tuple_type(node, hint)
data/lib/steep/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "1.9.0.dev.1"
2
+ VERSION = "1.9.0.dev.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0.dev.1
4
+ version: 1.9.0.dev.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-18 00:00:00.000000000 Z
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -245,6 +245,7 @@ files:
245
245
  - bin/output_rebaseline.rb
246
246
  - bin/output_test.rb
247
247
  - bin/rbs
248
+ - bin/rbs-inline
248
249
  - bin/setup
249
250
  - bin/stackprof_test.rb
250
251
  - bin/steep
@@ -412,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
412
413
  - !ruby/object:Gem::Version
413
414
  version: '0'
414
415
  requirements: []
415
- rubygems_version: 3.5.22
416
+ rubygems_version: 3.5.11
416
417
  signing_key:
417
418
  specification_version: 4
418
419
  summary: Gradual Typing for Ruby