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

Sign up to get free protection for your applications and to get access to all the features.
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