steep 1.9.0.dev.2 → 1.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -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/annotations.rb +1 -1
  15. data/lib/steep/drivers/check.rb +3 -3
  16. data/lib/steep/drivers/diagnostic_printer.rb +1 -1
  17. data/lib/steep/drivers/init.rb +6 -3
  18. data/lib/steep/expectations.rb +1 -1
  19. data/lib/steep/interface/builder.rb +7 -5
  20. data/lib/steep/interface/function.rb +13 -0
  21. data/lib/steep/interface/method_type.rb +5 -0
  22. data/lib/steep/interface/shape.rb +1 -1
  23. data/lib/steep/project/dsl.rb +11 -1
  24. data/lib/steep/project/target.rb +3 -1
  25. data/lib/steep/server/change_buffer.rb +1 -1
  26. data/lib/steep/server/interaction_worker.rb +5 -5
  27. data/lib/steep/server/master.rb +2 -17
  28. data/lib/steep/server/type_check_controller.rb +3 -3
  29. data/lib/steep/server/type_check_worker.rb +1 -1
  30. data/lib/steep/services/completion_provider.rb +4 -4
  31. data/lib/steep/services/goto_service.rb +3 -3
  32. data/lib/steep/services/hover_provider/rbs.rb +1 -1
  33. data/lib/steep/services/hover_provider/ruby.rb +6 -6
  34. data/lib/steep/services/signature_help_provider.rb +8 -8
  35. data/lib/steep/services/signature_service.rb +12 -8
  36. data/lib/steep/services/type_check_service.rb +9 -9
  37. data/lib/steep/signature/validator.rb +3 -3
  38. data/lib/steep/source.rb +4 -4
  39. data/lib/steep/subtyping/check.rb +3 -3
  40. data/lib/steep/subtyping/constraints.rb +4 -4
  41. data/lib/steep/type_construction.rb +84 -45
  42. data/lib/steep/type_inference/block_params.rb +3 -3
  43. data/lib/steep/type_inference/context.rb +1 -1
  44. data/lib/steep/type_inference/method_params.rb +1 -1
  45. data/lib/steep/type_inference/type_env.rb +3 -3
  46. data/lib/steep/version.rb +1 -1
  47. data/manual/annotations.md +37 -0
  48. data/manual/ignore.md +20 -0
  49. data/manual/ruby-diagnostics.md +1812 -0
  50. data/steep.gemspec +1 -1
  51. 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: 522d134347810d1fbb030d139f616077fcc197aabe079bf14453305c9c9562bd
4
+ data.tar.gz: bd6a1a97a815c02ba20160d6bc1bd2166c1a02cdee3901c2a84fca2fe1b22d0b
5
5
  SHA512:
6
- metadata.gz: c9800ef17d4108ff391642510701e12a0ec4e63035c74765ed1203fa9b62d964be10441d60890ab3c643dc8d0295dd2a68be5285126307f3cb401f517eaa799f
7
- data.tar.gz: 3ef2c5d7bac4dd2d492df8e5c60322de6c06d9c33cec21e2a97e4608f235e41729f0383e0817cfd324213853cad4c34308b14f5a582eedda71d36828545d6840
6
+ metadata.gz: 254fb6ef3b682ea7866e2892755e183bcd8ed797f4209faf999f40cdcb140a67083c73684ba80273cbf2e563650a2213114c474a2e0d3e50cc6d0cdc5d05caf0
7
+ data.tar.gz: b5daeab25121a44e5e9ad4a353de77115f7f626c0f5ac9342c1fe0ac061eabf75cbf3fef26a3b651d0b4849a0c05d5c1eafe9027f72294af0974f7b051f9eb71
data/CHANGELOG.md CHANGED
@@ -1,5 +1,87 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.9.1 (2024-12-09)
4
+
5
+ ### Type checker core
6
+
7
+ * Make `implicitly-returns-nil` opt-in ([#1396](https://github.com/soutaro/steep/pull/1396))
8
+
9
+ ## 1.9.0 (2024-12-06)
10
+
11
+ ### Type checker core
12
+
13
+ * Report diagnostic on unknown record key ([#1385](https://github.com/soutaro/steep/pull/1385))
14
+ * Report annotation syntax error ([#1384](https://github.com/soutaro/steep/pull/1384))
15
+ * emit UnreachableBranch to the "void" condition ([#1356](https://github.com/soutaro/steep/pull/1356))
16
+ * Support &method(:name) call for block_pass ([#1276](https://github.com/soutaro/steep/pull/1276))
17
+ * Emit SingletonTypeMismatch when class/module mismatch ([#1274](https://github.com/soutaro/steep/pull/1274))
18
+ * refactor: Use Array#fetch instead of Array#[] to resolve type errors ([#1287](https://github.com/soutaro/steep/pull/1287))
19
+ * refactor: Use Hash#fetch instead of Hash#[] to resolve type errors ([#1286](https://github.com/soutaro/steep/pull/1286))
20
+ * Expand `array(splat(expr` node ([#1347](https://github.com/soutaro/steep/pull/1347))
21
+ * Add `UnannotatedEmptyCollection` diagnostic ([#1338](https://github.com/soutaro/steep/pull/1338))
22
+ * Update type checking strategy ([#1308](https://github.com/soutaro/steep/pull/1308))
23
+ * Fix untyped hash typing ([#1299](https://github.com/soutaro/steep/pull/1299))
24
+ * Support `implicitly-returns-nil` ([#1258](https://github.com/soutaro/steep/pull/1258))
25
+ * Fix record shape ([#1265](https://github.com/soutaro/steep/pull/1265))
26
+ * Remove unused rules ([#1238](https://github.com/soutaro/steep/pull/1238))
27
+
28
+ ### Commandline tool
29
+
30
+ * Introduces a new `target.*` syntax for everything in the target ([#1387](https://github.com/soutaro/steep/pull/1387))
31
+ * Symbolize target/group names ([#1364](https://github.com/soutaro/steep/pull/1364))
32
+ * Update Steepfile template ([#1355](https://github.com/soutaro/steep/pull/1355))
33
+ * Delete `target` from `--validate` option ([#1346](https://github.com/soutaro/steep/pull/1346))
34
+ * Install rbs collection automatically ([#1345](https://github.com/soutaro/steep/pull/1345))
35
+
36
+ ### Language server
37
+
38
+ * Add link to diagnostic manual ([#1388](https://github.com/soutaro/steep/pull/1388))
39
+ * Stop accumulating diagnostics ([#1367](https://github.com/soutaro/steep/pull/1367))
40
+ * Send server version to client ([#1341](https://github.com/soutaro/steep/pull/1341))
41
+ * Add custom methods to trigger type check manually ([#1340](https://github.com/soutaro/steep/pull/1340))
42
+ * Type check thread helpers ([#1335](https://github.com/soutaro/steep/pull/1335))
43
+ * Use `URI::RFC2396_Parser` ([#1329](https://github.com/soutaro/steep/pull/1329))
44
+ * Handle file deletion notification ([#1300](https://github.com/soutaro/steep/pull/1300))
45
+ * Refactor communication between master and type check worker ([#1285](https://github.com/soutaro/steep/pull/1285))
46
+ * Skip sending response to `$/steep/typecheck` request from `steep langserver` ([#1267](https://github.com/soutaro/steep/pull/1267))
47
+
48
+ ### Miscellaneous
49
+
50
+ * Use rbs-3.7 ([#1383](https://github.com/soutaro/steep/pull/1383))
51
+ * Move diagnostic docs ([#1370](https://github.com/soutaro/steep/pull/1370))
52
+ * Add anchor ([#1359](https://github.com/soutaro/steep/pull/1359))
53
+ * Update example to not use `^` as a hash function ([#1360](https://github.com/soutaro/steep/pull/1360))
54
+ * doc: Add diagnostics for Ruby page ([#1249](https://github.com/soutaro/steep/pull/1249))
55
+ * Update filename example in initial Steepfile ([#1230](https://github.com/soutaro/steep/pull/1230))
56
+ * docs: Add document for steep:ignore comment ([#1353](https://github.com/soutaro/steep/pull/1353))
57
+ * docs: Add document for type assertion and type application ([#1235](https://github.com/soutaro/steep/pull/1235))
58
+ * Print test names in CI for investigation ([#1354](https://github.com/soutaro/steep/pull/1354))
59
+ * Fix typo ([#1352](https://github.com/soutaro/steep/pull/1352))
60
+ * Set up type checking tests ([#1339](https://github.com/soutaro/steep/pull/1339))
61
+ * Fix typo ([#1248](https://github.com/soutaro/steep/pull/1248))
62
+
63
+ ## 1.8.3 (2024-10-29)
64
+
65
+ ### Type checker core
66
+
67
+ * Fix untyped hash typing ([#1299](https://github.com/soutaro/steep/pull/1299), Backport in [#1301](https://github.com/soutaro/steep/pull/1301))
68
+
69
+ ### Language server
70
+
71
+ * Handle file deletion notification ([#1300](https://github.com/soutaro/steep/pull/1300), Backport in [#1301](https://github.com/soutaro/steep/pull/1301))
72
+
73
+ ## 1.8.2 (2024-10-24)
74
+
75
+ ### Language server
76
+
77
+ * Ignore `didChangeWatchedFiles notification` for open files ([#1290](https://github.com/soutaro/steep/pull/1290))
78
+
79
+ ## 1.8.1 (2024-10-08)
80
+
81
+ ### Language server
82
+
83
+ * 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))
84
+
3
85
  ## 1.8.0 (2024-09-30)
4
86
 
5
87
  ### 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(
@@ -21,7 +21,7 @@ module Steep
21
21
 
22
22
  project.targets.each do |target|
23
23
  Steep.logger.tagged "target=#{target.name}" do
24
- service = Services::SignatureService.load_from(target.new_env_loader())
24
+ service = Services::SignatureService.load_from(target.new_env_loader(), implicitly_returns_nil: target.implicitly_returns_nil)
25
25
 
26
26
  sigs = loader.load_changes(target.signature_pattern, changes: {})
27
27
  service.update(sigs)
@@ -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)
@@ -54,19 +54,20 @@ module Steep
54
54
  end
55
55
  end
56
56
 
57
- attr_reader :factory, :object_shape_cache, :union_shape_cache, :singleton_shape_cache
57
+ attr_reader :factory, :object_shape_cache, :union_shape_cache, :singleton_shape_cache, :implicitly_returns_nil
58
58
 
59
- def initialize(factory)
59
+ def initialize(factory, implicitly_returns_nil:)
60
60
  @factory = factory
61
61
  @object_shape_cache = {}
62
62
  @union_shape_cache = {}
63
63
  @singleton_shape_cache = {}
64
+ @implicitly_returns_nil = implicitly_returns_nil
64
65
  end
65
66
 
66
67
  def shape(type, config)
67
68
  Steep.logger.tagged "shape(#{type})" do
68
69
  if shape = raw_shape(type, config)
69
- # Optimization that skips unnecesary substittuion
70
+ # Optimization that skips unnecessary substitution
70
71
  if type.free_variables.include?(AST::Types::Self.instance)
71
72
  shape
72
73
  else
@@ -172,7 +173,7 @@ module Steep
172
173
  if bound = config.upper_bound(type.name)
173
174
  new_config = Config.new(self_type: bound, variable_bounds: config.variable_bounds)
174
175
  sub = Substitution.build([], self_type: type)
175
- # We have to use `self_shape` insead of `raw_shape` here.
176
+ # We have to use `self_shape` instead of `raw_shape` here.
176
177
  # Keep the `self` types included in the `bound`'s shape, and replace it to the type variable.
177
178
  self_shape(bound, new_config)&.subst(sub, type: type)
178
179
  end
@@ -826,6 +827,8 @@ module Steep
826
827
  end
827
828
 
828
829
  def add_implicitly_returns_nil(annotations, method_type)
830
+ return method_type unless implicitly_returns_nil
831
+
829
832
  if annotations.find { _1.string == "implicitly-returns-nil" }
830
833
  return_type = method_type.type.return_type
831
834
  method_type = method_type.with(
@@ -838,4 +841,3 @@ module Steep
838
841
  end
839
842
  end
840
843
  end
841
-