steep 1.9.0.dev.2 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -0
  3. data/README.md +9 -4
  4. data/Rakefile +1 -0
  5. data/Steepfile +11 -0
  6. data/bin/generate-diagnostics-docs.rb +112 -0
  7. data/lib/steep/ast/builtin.rb +1 -0
  8. data/lib/steep/ast/ignore.rb +1 -1
  9. data/lib/steep/ast/types/factory.rb +2 -0
  10. data/lib/steep/cli.rb +9 -2
  11. data/lib/steep/diagnostic/lsp_formatter.rb +8 -1
  12. data/lib/steep/diagnostic/ruby.rb +65 -3
  13. data/lib/steep/diagnostic/signature.rb +4 -4
  14. data/lib/steep/drivers/check.rb +3 -3
  15. data/lib/steep/drivers/diagnostic_printer.rb +1 -1
  16. data/lib/steep/drivers/init.rb +6 -3
  17. data/lib/steep/expectations.rb +1 -1
  18. data/lib/steep/interface/builder.rb +2 -3
  19. data/lib/steep/interface/function.rb +13 -0
  20. data/lib/steep/interface/method_type.rb +5 -0
  21. data/lib/steep/interface/shape.rb +1 -1
  22. data/lib/steep/project/dsl.rb +2 -0
  23. data/lib/steep/server/change_buffer.rb +1 -1
  24. data/lib/steep/server/interaction_worker.rb +5 -5
  25. data/lib/steep/server/master.rb +2 -17
  26. data/lib/steep/server/type_check_controller.rb +2 -2
  27. data/lib/steep/server/type_check_worker.rb +1 -1
  28. data/lib/steep/services/completion_provider.rb +4 -4
  29. data/lib/steep/services/goto_service.rb +3 -3
  30. data/lib/steep/services/hover_provider/rbs.rb +1 -1
  31. data/lib/steep/services/hover_provider/ruby.rb +6 -6
  32. data/lib/steep/services/signature_help_provider.rb +8 -8
  33. data/lib/steep/services/type_check_service.rb +8 -8
  34. data/lib/steep/signature/validator.rb +3 -3
  35. data/lib/steep/source.rb +4 -4
  36. data/lib/steep/subtyping/check.rb +3 -3
  37. data/lib/steep/subtyping/constraints.rb +4 -4
  38. data/lib/steep/type_construction.rb +84 -45
  39. data/lib/steep/type_inference/block_params.rb +3 -3
  40. data/lib/steep/type_inference/context.rb +1 -1
  41. data/lib/steep/type_inference/method_params.rb +1 -1
  42. data/lib/steep/type_inference/type_env.rb +3 -3
  43. data/lib/steep/version.rb +1 -1
  44. data/manual/annotations.md +37 -0
  45. data/manual/ignore.md +20 -0
  46. data/manual/ruby-diagnostics.md +1812 -0
  47. data/steep.gemspec +1 -1
  48. metadata +8 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89c207623c288c2142cdcf7d7de7f404da4d160b5bc40c84210116a721ec4029
4
- data.tar.gz: dfd95e726115676f4d293d312bd1f06afa6ea89336911e9887c8e4b5ee1167ff
3
+ metadata.gz: 7f7a4597973dff6192b6977a32875ed18b7da16a70d34bf5e811cb8a719b18d5
4
+ data.tar.gz: 8b9ec7e28728c0f6e35e962fed6dd8a43828d41763ae2ffce831b787a501b200
5
5
  SHA512:
6
- metadata.gz: c9800ef17d4108ff391642510701e12a0ec4e63035c74765ed1203fa9b62d964be10441d60890ab3c643dc8d0295dd2a68be5285126307f3cb401f517eaa799f
7
- data.tar.gz: 3ef2c5d7bac4dd2d492df8e5c60322de6c06d9c33cec21e2a97e4608f235e41729f0383e0817cfd324213853cad4c34308b14f5a582eedda71d36828545d6840
6
+ metadata.gz: f11cb6ec05bc38e2e8130b7e6860409c63a9d1ba3ef93ca14dcc3781800c00d97e59506343e8191c97741865a1fa1895dfd9ff69928b574df423e32983a315b5
7
+ data.tar.gz: d6b544a988c8f0adae6705a5b7085907bb7148dde0eeb857a3aae7b9c44b2787f47ea40aa1c0b54b5d5da650f07e4f94e0a754ead23baca844cb2f21ae6c7eaa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,81 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.9.0 (2024-12-06)
4
+
5
+ ### Type checker core
6
+
7
+ * Report diagnostic on unknown record key ([#1385](https://github.com/soutaro/steep/pull/1385))
8
+ * Report annotation syntax error ([#1384](https://github.com/soutaro/steep/pull/1384))
9
+ * emit UnreachableBranch to the "void" condition ([#1356](https://github.com/soutaro/steep/pull/1356))
10
+ * Support &method(:name) call for block_pass ([#1276](https://github.com/soutaro/steep/pull/1276))
11
+ * Emit SingletonTypeMismatch when class/module mismatch ([#1274](https://github.com/soutaro/steep/pull/1274))
12
+ * refactor: Use Array#fetch instead of Array#[] to resolve type errors ([#1287](https://github.com/soutaro/steep/pull/1287))
13
+ * refactor: Use Hash#fetch instead of Hash#[] to resolve type errors ([#1286](https://github.com/soutaro/steep/pull/1286))
14
+ * Expand `array(splat(expr` node ([#1347](https://github.com/soutaro/steep/pull/1347))
15
+ * Add `UnannotatedEmptyCollection` diagnostic ([#1338](https://github.com/soutaro/steep/pull/1338))
16
+ * Update type checking strategy ([#1308](https://github.com/soutaro/steep/pull/1308))
17
+ * Fix untyped hash typing ([#1299](https://github.com/soutaro/steep/pull/1299))
18
+ * Support `implicitly-returns-nil` ([#1258](https://github.com/soutaro/steep/pull/1258))
19
+ * Fix record shape ([#1265](https://github.com/soutaro/steep/pull/1265))
20
+ * Remove unused rules ([#1238](https://github.com/soutaro/steep/pull/1238))
21
+
22
+ ### Commandline tool
23
+
24
+ * Introduces a new `target.*` syntax for everything in the target ([#1387](https://github.com/soutaro/steep/pull/1387))
25
+ * Symbolize target/group names ([#1364](https://github.com/soutaro/steep/pull/1364))
26
+ * Update Steepfile template ([#1355](https://github.com/soutaro/steep/pull/1355))
27
+ * Delete `target` from `--validate` option ([#1346](https://github.com/soutaro/steep/pull/1346))
28
+ * Install rbs collection automatically ([#1345](https://github.com/soutaro/steep/pull/1345))
29
+
30
+ ### Language server
31
+
32
+ * Add link to diagnostic manual ([#1388](https://github.com/soutaro/steep/pull/1388))
33
+ * Stop accumulating diagnostics ([#1367](https://github.com/soutaro/steep/pull/1367))
34
+ * Send server version to client ([#1341](https://github.com/soutaro/steep/pull/1341))
35
+ * Add custom methods to trigger type check manually ([#1340](https://github.com/soutaro/steep/pull/1340))
36
+ * Type check thread helpers ([#1335](https://github.com/soutaro/steep/pull/1335))
37
+ * Use `URI::RFC2396_Parser` ([#1329](https://github.com/soutaro/steep/pull/1329))
38
+ * Handle file deletion notification ([#1300](https://github.com/soutaro/steep/pull/1300))
39
+ * Refactor communication between master and type check worker ([#1285](https://github.com/soutaro/steep/pull/1285))
40
+ * Skip sending response to `$/steep/typecheck` request from `steep langserver` ([#1267](https://github.com/soutaro/steep/pull/1267))
41
+
42
+ ### Miscellaneous
43
+
44
+ * Use rbs-3.7 ([#1383](https://github.com/soutaro/steep/pull/1383))
45
+ * Move diagnostic docs ([#1370](https://github.com/soutaro/steep/pull/1370))
46
+ * Add anchor ([#1359](https://github.com/soutaro/steep/pull/1359))
47
+ * Update example to not use `^` as a hash function ([#1360](https://github.com/soutaro/steep/pull/1360))
48
+ * doc: Add diagnostics for Ruby page ([#1249](https://github.com/soutaro/steep/pull/1249))
49
+ * Update filename example in initial Steepfile ([#1230](https://github.com/soutaro/steep/pull/1230))
50
+ * docs: Add document for steep:ignore comment ([#1353](https://github.com/soutaro/steep/pull/1353))
51
+ * docs: Add document for type assertion and type application ([#1235](https://github.com/soutaro/steep/pull/1235))
52
+ * Print test names in CI for investigation ([#1354](https://github.com/soutaro/steep/pull/1354))
53
+ * Fix typo ([#1352](https://github.com/soutaro/steep/pull/1352))
54
+ * Set up type checking tests ([#1339](https://github.com/soutaro/steep/pull/1339))
55
+ * Fix typo ([#1248](https://github.com/soutaro/steep/pull/1248))
56
+
57
+ ## 1.8.3 (2024-10-29)
58
+
59
+ ### Type checker core
60
+
61
+ * Fix untyped hash typing ([#1299](https://github.com/soutaro/steep/pull/1299), Backport in [#1301](https://github.com/soutaro/steep/pull/1301))
62
+
63
+ ### Language server
64
+
65
+ * Handle file deletion notification ([#1300](https://github.com/soutaro/steep/pull/1300), Backport in [#1301](https://github.com/soutaro/steep/pull/1301))
66
+
67
+ ## 1.8.2 (2024-10-24)
68
+
69
+ ### Language server
70
+
71
+ * Ignore `didChangeWatchedFiles notification` for open files ([#1290](https://github.com/soutaro/steep/pull/1290))
72
+
73
+ ## 1.8.1 (2024-10-08)
74
+
75
+ ### Language server
76
+
77
+ * Skip sending response to `$/steep/typecheck` request from `steep langserver` ([#1268](https://github.com/soutaro/steep/pull/1268), backport [#1267](https://github.com/soutaro/steep/pull/1267))
78
+
3
79
  ## 1.8.0 (2024-09-30)
4
80
 
5
81
  ### Type checker core
data/README.md CHANGED
@@ -120,7 +120,7 @@ class Email
120
120
  end
121
121
 
122
122
  def hash
123
- self.class.hash ^ address.hash
123
+ [self.class, address].hash
124
124
  end
125
125
  end
126
126
 
@@ -144,7 +144,7 @@ class Phone
144
144
  end
145
145
 
146
146
  def hash
147
- self.class.hash ^ country.hash ^ number.hash
147
+ [self.class, country, number].hash
148
148
  end
149
149
  end
150
150
  ```
@@ -201,11 +201,16 @@ Generally, these are by our design.
201
201
 
202
202
  `rbs prototype` offers options: `rbi` to generate prototype from Sorbet RBI and `runtime` to generate from runtime API.
203
203
 
204
- ## Guides
204
+ ## Docs
205
205
 
206
- There are some guides in the `guide` directory. I know we need more comprehensive set of documentations. Just started writing docs.
206
+ There are some documents in the `manul` and `guide` directories.
207
207
 
208
208
  * [Guides](guides)
209
+ * [Manual](manual)
210
+
211
+ The `doc` directory contains a few internal design docs.
212
+
213
+ * [Internal docs](doc)
209
214
 
210
215
  ## Examples
211
216
 
data/Rakefile CHANGED
@@ -48,6 +48,7 @@ task :changelog do
48
48
  "list",
49
49
  "--json",
50
50
  "url,title,number",
51
+ "--limit=100",
51
52
  "--search" ,
52
53
  "milestone:\"#{milestone}\" is:merged sort:updated-desc -label:Released"
53
54
  ]
data/Steepfile CHANGED
@@ -49,3 +49,14 @@ target :test do
49
49
  library "rbs"
50
50
  end
51
51
  end
52
+
53
+ target :bin do
54
+ unreferenced!
55
+
56
+ collection_config "rbs_collection.steep.yaml"
57
+
58
+ check "bin/generate-diagnostics-docs.rb"
59
+ signature "tmp/rbs-inline/bin"
60
+
61
+ library "rbs"
62
+ end
@@ -0,0 +1,112 @@
1
+ # rbs_inline: enabled
2
+
3
+ require "rbs"
4
+ require "steep"
5
+
6
+ class RubyDiagnosticsVisitor < RBS::AST::Visitor
7
+ attr_reader :classes #: Hash[String, String]
8
+ attr_reader :templates #: Hash[Symbol, String]
9
+
10
+ def initialize #: void
11
+ @classes = {}
12
+ @templates = {}
13
+ end
14
+
15
+ # @rbs ...
16
+ def visit_declaration_class(node)
17
+ unless node.annotations.find { _1.string == "diagnostics--skip" }
18
+ if node.comment
19
+ name = node.name.to_s
20
+ classes[name] = node.comment.string
21
+ end
22
+ end
23
+
24
+ super
25
+ end
26
+
27
+ # @rbs ...
28
+ def visit_member_method_definition(node)
29
+ if node.annotations.find { _1.string == "diagnostics--template" }
30
+ if node.comment
31
+ templates[node.name] = node.comment.string
32
+ end
33
+ end
34
+ end
35
+
36
+ # @rbs (IO) -> void
37
+ def format_templates(io)
38
+ io.puts "## Configuration Templates"
39
+
40
+ io.puts <<~MD
41
+ Steep provides several templates to configure diagnostics for Ruby code.
42
+ You can use these templates or customize them to suit your needs via `#configure_code_diagnostics` method in `Steepfile`.
43
+
44
+ The following templates are available:
45
+
46
+ MD
47
+
48
+ io.puts "<dl>"
49
+ templates.keys.sort.each do |key|
50
+ body = templates.fetch(key)
51
+
52
+ io.puts "<dt><code>Ruby.#{key}</code></dt>"
53
+ io.puts "<dd>#{body}</dd>"
54
+ end
55
+ io.puts "</dl>"
56
+ io.puts
57
+ end
58
+
59
+ # @rbs (IO) -> void
60
+ def format_class(io)
61
+ classes.keys.sort.each do |key|
62
+ content = classes[key]
63
+
64
+ # io.puts "<h2 id='Ruby::#{key}'>Ruby::#{key}</h2>"
65
+ io.puts "<a name='Ruby::#{key}'></a>"
66
+ io.puts "## Ruby::#{key}"
67
+ io.puts
68
+ io.puts content
69
+ io.puts
70
+
71
+ configs = templates.keys
72
+
73
+ io.puts "### Severity"
74
+ io.puts
75
+ io.puts "| #{configs.map { "#{_1}" }.join(" | ")} |"
76
+ io.puts "| #{configs.map{"-"}.join(" | ")} |"
77
+
78
+ line = configs.map {|config|
79
+ hash = Steep::Diagnostic::Ruby.__send__(config) #: Hash[Class, untyped]
80
+ const =Steep::Diagnostic::Ruby.const_get(key.to_sym)
81
+ "#{hash[const] || "-"}"
82
+ }
83
+ io.puts "| #{line.join(" | ")} |"
84
+ io.puts
85
+ end
86
+ end
87
+
88
+ # @rbs (Pathname) { (instance) -> void } -> void
89
+ def self.visit_file(path, &block)
90
+ STDERR.puts "Reading #{path}..."
91
+ buffer = RBS::Buffer.new(name: path, content: path.read)
92
+ _, _dirs, decls = RBS::Parser.parse_signature(buffer)
93
+
94
+ visitor = new()
95
+ visitor.visit_all(decls)
96
+
97
+ yield visitor
98
+ end
99
+ end
100
+
101
+ diagnostic_dir = Pathname(__dir__ || raise) + "../sig/steep/diagnostic"
102
+ output_dir = Pathname(__dir__ || raise) + "../manual"
103
+
104
+ RubyDiagnosticsVisitor.visit_file(diagnostic_dir + "ruby.rbs") do |visitor|
105
+ STDERR.puts ">> Writing #{output_dir + "ruby-diagnostics.md"}..."
106
+ (output_dir + "ruby-diagnostics.md").open("w") do |io|
107
+ io.puts "# Ruby Code Diagnostics"
108
+ io.puts
109
+ visitor.format_templates(io)
110
+ visitor.format_class(io)
111
+ end
112
+ end
@@ -66,6 +66,7 @@ module Steep
66
66
  NilClass = Type.new("::NilClass")
67
67
  Proc = Type.new("::Proc")
68
68
  Kernel = Type.new("::Kernel")
69
+ Method = Type.new("::Method")
69
70
 
70
71
  def self.nil_type
71
72
  AST::Types::Nil.instance
@@ -79,7 +79,7 @@ module Steep
79
79
  return :all
80
80
  end
81
81
 
82
- if raw_diagnostics.size == 1 && raw_diagnostics[0].source == "all"
82
+ if raw_diagnostics.size == 1 && raw_diagnostics.fetch(0).source == "all"
83
83
  return :all
84
84
  end
85
85
 
@@ -409,6 +409,8 @@ module Steep
409
409
  ]
410
410
  when AST::Types::Any, AST::Types::Boolean, AST::Types::Top, AST::Types::Logic::Base
411
411
  [type, type]
412
+ when AST::Types::Bot, AST::Types::Void
413
+ [nil, nil]
412
414
  when AST::Types::Nil
413
415
  [nil, type]
414
416
  when AST::Types::Literal
data/lib/steep/cli.rb CHANGED
@@ -128,10 +128,17 @@ module Steep
128
128
  end
129
129
 
130
130
  opts.on("--group=GROUP", "Specify target/group name to type check") do |arg|
131
- # @type var group: String
131
+ # @type var arg: String
132
132
  target, group = arg.split(".")
133
133
  target or raise
134
- command.active_group_names << [target.to_sym, group&.to_sym]
134
+ case group
135
+ when "*"
136
+ command.active_group_names << [target.to_sym, true]
137
+ when nil
138
+ command.active_group_names << [target.to_sym, nil]
139
+ else
140
+ command.active_group_names << [target.to_sym, group.to_sym]
141
+ end
135
142
  end
136
143
 
137
144
  opts.on("--[no-]type-check", "Type check Ruby code") do |v|
@@ -43,11 +43,18 @@ module Steep
43
43
  if severity
44
44
  range = diagnostic.location&.as_lsp_range || raise("#{diagnostic.class} object (#{diagnostic.full_message}) instance must have `#location`")
45
45
 
46
+ if diagnostic.is_a?(Ruby::Base)
47
+ description = {
48
+ href: "https://github.com/soutaro/steep/tree/v#{VERSION}/manual/ruby-diagnostics.md##{URI.encode_uri_component(diagnostic.diagnostic_code)}"
49
+ } #: LSP::Interface::CodeDescription::json
50
+ end
51
+
46
52
  {
47
53
  message: diagnostic.full_message,
48
54
  code: diagnostic.diagnostic_code,
49
55
  severity: severity,
50
- range: range
56
+ range: range,
57
+ codeDescription: description
51
58
  }
52
59
  end
53
60
  end
@@ -409,6 +409,33 @@ module Steep
409
409
  end
410
410
  end
411
411
 
412
+ class ClassModuleMismatch < Base
413
+ attr_reader :name
414
+
415
+ def initialize(node:, name:)
416
+ case node.type
417
+ when :module, :class
418
+ location = node.loc.name # steep:ignore NoMethod
419
+ else
420
+ raise "Unexpected node: #{node.type}"
421
+ end
422
+ super(node: node, location: location) # steep:ignore NoMethod
423
+
424
+ @name = name
425
+ end
426
+
427
+ def header_line
428
+ case node&.type
429
+ when :module
430
+ "#{name} is declared as a class in RBS"
431
+ when :class
432
+ "#{name} is declared as a module in RBS"
433
+ else
434
+ raise
435
+ end
436
+ end
437
+ end
438
+
412
439
  class MethodArityMismatch < Base
413
440
  attr_reader :method_type
414
441
 
@@ -794,6 +821,19 @@ module Steep
794
821
  end
795
822
  end
796
823
 
824
+ class AnnotationSyntaxError < Base
825
+ attr_reader :message
826
+
827
+ def initialize(message: ,location:)
828
+ super(node: nil, location: location)
829
+ @message = message
830
+ end
831
+
832
+ def header_line
833
+ "Type annotation has a syntax error: #{message}"
834
+ end
835
+ end
836
+
797
837
  class FalseAssertion < Base
798
838
  attr_reader :node, :assertion_type, :node_type
799
839
 
@@ -924,6 +964,19 @@ module Steep
924
964
  end
925
965
  end
926
966
 
967
+ class UnknownRecordKey < Base
968
+ attr_reader :key
969
+
970
+ def initialize(key:, node:)
971
+ super(node: node)
972
+ @key = key
973
+ end
974
+
975
+ def header_line
976
+ "Unknown key `#{key.inspect}` is given to a record type"
977
+ end
978
+ end
979
+
927
980
  ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
928
981
  if klass < Base
929
982
  array << klass
@@ -939,6 +992,7 @@ module Steep
939
992
  def self.default
940
993
  @default ||= _ = all_error.merge(
941
994
  {
995
+ AnnotationSyntaxError => :error,
942
996
  ArgumentTypeMismatch => :error,
943
997
  BlockBodyTypeMismatch => :warning,
944
998
  BlockTypeMismatch => :warning,
@@ -968,7 +1022,8 @@ module Steep
968
1022
  ReturnTypeMismatch => :error,
969
1023
  SetterBodyTypeMismatch => :information,
970
1024
  SetterReturnTypeMismatch => :information,
971
- SyntaxError => :hint,
1025
+ ClassModuleMismatch => :error,
1026
+ SyntaxError => :information,
972
1027
  TypeArgumentMismatchError => :hint,
973
1028
  UnannotatedEmptyCollection => :warning,
974
1029
  UnexpectedBlockGiven => :warning,
@@ -983,6 +1038,7 @@ module Steep
983
1038
  UnexpectedYield => :warning,
984
1039
  UnknownConstant => :warning,
985
1040
  UnknownGlobalVariable => :warning,
1041
+ UnknownRecordKey => :information,
986
1042
  UnknownInstanceVariable => :information,
987
1043
  UnreachableBranch => :hint,
988
1044
  UnreachableValueBranch => :hint,
@@ -996,6 +1052,7 @@ module Steep
996
1052
  def self.strict
997
1053
  @strict ||= _ = all_error.merge(
998
1054
  {
1055
+ AnnotationSyntaxError => :error,
999
1056
  ArgumentTypeMismatch => :error,
1000
1057
  BlockBodyTypeMismatch => :error,
1001
1058
  BlockTypeMismatch => :error,
@@ -1025,7 +1082,8 @@ module Steep
1025
1082
  ReturnTypeMismatch => :error,
1026
1083
  SetterBodyTypeMismatch => :error,
1027
1084
  SetterReturnTypeMismatch => :error,
1028
- SyntaxError => :hint,
1085
+ ClassModuleMismatch => :error,
1086
+ SyntaxError => :information,
1029
1087
  TypeArgumentMismatchError => :error,
1030
1088
  UnannotatedEmptyCollection => :error,
1031
1089
  UnexpectedBlockGiven => :error,
@@ -1040,6 +1098,7 @@ module Steep
1040
1098
  UnexpectedYield => :error,
1041
1099
  UnknownConstant => :error,
1042
1100
  UnknownGlobalVariable => :error,
1101
+ UnknownRecordKey => :warning,
1043
1102
  UnknownInstanceVariable => :error,
1044
1103
  UnreachableBranch => :information,
1045
1104
  UnreachableValueBranch => :warning,
@@ -1053,6 +1112,7 @@ module Steep
1053
1112
  def self.lenient
1054
1113
  @lenient ||= _ = all_error.merge(
1055
1114
  {
1115
+ AnnotationSyntaxError => :error,
1056
1116
  ArgumentTypeMismatch => :information,
1057
1117
  BlockBodyTypeMismatch => :information,
1058
1118
  BlockTypeMismatch => :information,
@@ -1082,7 +1142,8 @@ module Steep
1082
1142
  ReturnTypeMismatch => :warning,
1083
1143
  SetterBodyTypeMismatch => nil,
1084
1144
  SetterReturnTypeMismatch => nil,
1085
- SyntaxError => :hint,
1145
+ ClassModuleMismatch => nil,
1146
+ SyntaxError => :information,
1086
1147
  TypeArgumentMismatchError => nil,
1087
1148
  UnannotatedEmptyCollection => :hint,
1088
1149
  UnexpectedBlockGiven => :hint,
@@ -1097,6 +1158,7 @@ module Steep
1097
1158
  UnexpectedYield => :information,
1098
1159
  UnknownConstant => :hint,
1099
1160
  UnknownGlobalVariable => :hint,
1161
+ UnknownRecordKey => :hint,
1100
1162
  UnknownInstanceVariable => :hint,
1101
1163
  UnreachableBranch => :hint,
1102
1164
  UnreachableValueBranch => :hint,
@@ -456,7 +456,7 @@ module Steep
456
456
  end
457
457
 
458
458
  def header_line
459
- "The default type of `#{param_name}` doesn't satisfy upper bound constarint: #{relation}"
459
+ "The default type of `#{param_name}` doesn't satisfy upper bound constraint: #{relation}"
460
460
  end
461
461
  end
462
462
 
@@ -468,7 +468,7 @@ module Steep
468
468
  when RBS::DuplicatedDeclarationError
469
469
  Diagnostic::Signature::DuplicatedDeclaration.new(
470
470
  type_name: error.name,
471
- location: error.decls[0].location
471
+ location: error.decls.fetch(0).location
472
472
  )
473
473
  when RBS::GenericParameterMismatchError
474
474
  Diagnostic::Signature::GenericParameterMismatch.new(
@@ -494,7 +494,7 @@ module Steep
494
494
  Diagnostic::Signature::InvalidMethodOverload.new(
495
495
  class_name: error.type_name,
496
496
  method_name: error.method_name,
497
- location: error.members[0].location
497
+ location: error.members.fetch(0).location
498
498
  )
499
499
  when RBS::DuplicatedMethodDefinitionError
500
500
  Diagnostic::Signature::DuplicatedMethodDefinition.new(
@@ -518,7 +518,7 @@ module Steep
518
518
  Diagnostic::Signature::RecursiveAlias.new(
519
519
  class_name: error.type.name,
520
520
  names: error.defs.map(&:name),
521
- location: error.defs[0].original&.location
521
+ location: error.defs.fetch(0).original&.location
522
522
  )
523
523
  when RBS::RecursiveAncestorError
524
524
  Diagnostic::Signature::RecursiveAncestor.new(
@@ -38,12 +38,12 @@ module Steep
38
38
  case group
39
39
  when Project::Target
40
40
  active_group_names.any? {|target_name, group_name|
41
- target_name == group.name && group_name == nil
41
+ target_name == group.name && (group_name == nil || group_name == true)
42
42
  }
43
43
  when Project::Group
44
44
  active_group_names.any? {|target_name, group_name|
45
45
  target_name == group.target.name &&
46
- (group_name == group.name || group_name.nil?)
46
+ (group_name == group.name || group_name == true)
47
47
  }
48
48
  end
49
49
  end
@@ -206,7 +206,7 @@ module Steep
206
206
 
207
207
  def load_files(files, target, group, params:)
208
208
  if type_check_code
209
- files.each_group_source_path(group) do |path|
209
+ files.each_group_source_path(group, true) do |path|
210
210
  params[:code_paths] << [target.name.to_s, target.project.absolute_path(path).to_s]
211
211
  end
212
212
  end
@@ -82,7 +82,7 @@ module Steep
82
82
  start_pos = diagnostic[:range][:start]
83
83
  end_pos = diagnostic[:range][:end]
84
84
 
85
- line = buffer.lines[start_pos[:line]]
85
+ line = buffer.lines.fetch(start_pos[:line])
86
86
 
87
87
  leading = line[0...start_pos[:character]] || ""
88
88
  if start_pos[:line] == end_pos[:line]
@@ -12,9 +12,10 @@ module Steep
12
12
  #
13
13
  # target :lib do
14
14
  # signature "sig"
15
+ # ignore_signature "sig/test"
15
16
  #
16
17
  # check "lib" # Directory name
17
- # check "Gemfile" # File name
18
+ # check "path/to/source.rb" # File name
18
19
  # check "app/models/**/*.rb" # Glob
19
20
  # # ignore "lib/templates/*.rb"
20
21
  #
@@ -31,9 +32,11 @@ module Steep
31
32
  # end
32
33
 
33
34
  # target :test do
34
- # signature "sig", "sig-private"
35
+ # unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
36
+ # signature "sig/test" # Put RBS files for tests under `sig/test`
37
+ # check "test" # Type check Ruby scripts under `test`
35
38
  #
36
- # check "test"
39
+ # configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
37
40
  #
38
41
  # # library "pathname" # Standard libraries
39
42
  # end
@@ -203,7 +203,7 @@ module Steep
203
203
  array = [] #: Array[{ "file" => String, "diagnostics" => Array[untyped] }]
204
204
 
205
205
  diagnostics.each_key.sort.each do |key|
206
- ds = diagnostics[key]
206
+ ds = diagnostics.fetch(key)
207
207
  array << {
208
208
  "file" => key.to_s,
209
209
  'diagnostics' => ds.sort_by(&:sort_key).map(&:to_hash)
@@ -66,7 +66,7 @@ module Steep
66
66
  def shape(type, config)
67
67
  Steep.logger.tagged "shape(#{type})" do
68
68
  if shape = raw_shape(type, config)
69
- # Optimization that skips unnecesary substittuion
69
+ # Optimization that skips unnecessary substitution
70
70
  if type.free_variables.include?(AST::Types::Self.instance)
71
71
  shape
72
72
  else
@@ -172,7 +172,7 @@ module Steep
172
172
  if bound = config.upper_bound(type.name)
173
173
  new_config = Config.new(self_type: bound, variable_bounds: config.variable_bounds)
174
174
  sub = Substitution.build([], self_type: type)
175
- # We have to use `self_shape` insead of `raw_shape` here.
175
+ # We have to use `self_shape` instead of `raw_shape` here.
176
176
  # Keep the `self` types included in the `bound`'s shape, and replace it to the type variable.
177
177
  self_shape(bound, new_config)&.subst(sub, type: type)
178
178
  end
@@ -838,4 +838,3 @@ module Steep
838
838
  end
839
839
  end
840
840
  end
841
-
@@ -1057,6 +1057,19 @@ module Steep
1057
1057
  )
1058
1058
  end
1059
1059
 
1060
+ def accept_one_arg?
1061
+ return false unless params
1062
+ return false unless params.keyword_params.requireds.empty?
1063
+ head = params.positional_params or return false
1064
+
1065
+ case head.head
1066
+ when Params::PositionalParams::Required
1067
+ !head.tail.is_a?(Params::PositionalParams::Required)
1068
+ else
1069
+ true
1070
+ end
1071
+ end
1072
+
1060
1073
  def to_s
1061
1074
  if params
1062
1075
  "#{params} -> #{return_type}"
@@ -320,6 +320,11 @@ module Steep
320
320
  block: block
321
321
  )
322
322
  end
323
+
324
+ def accept_one_arg?
325
+ return false if block && block.required?
326
+ type.accept_one_arg?
327
+ end
323
328
  end
324
329
  end
325
330
  end
@@ -125,7 +125,7 @@ module Steep
125
125
  return nil unless key?(name)
126
126
 
127
127
  resolved_methods[name] ||= begin
128
- entry = methods[name]
128
+ entry = methods.fetch(name)
129
129
  Entry.new(
130
130
  method_name: name,
131
131
  overloads: entry.overloads.map do |overload|