steep 1.10.0.dev.1 → 1.10.0.pre.1
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 +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/steep/annotations_helper.rb +25 -0
- data/lib/steep/cli.rb +4 -0
- data/lib/steep/diagnostic/lsp_formatter.rb +3 -0
- data/lib/steep/diagnostic/signature.rb +20 -0
- data/lib/steep/drivers/check.rb +3 -1
- data/lib/steep/drivers/diagnostic_printer/base_formatter.rb +19 -0
- data/lib/steep/drivers/diagnostic_printer/code_formatter.rb +95 -0
- data/lib/steep/drivers/diagnostic_printer/github_actions_formatter.rb +44 -0
- data/lib/steep/drivers/diagnostic_printer.rb +9 -86
- data/lib/steep/server/interaction_worker.rb +19 -4
- data/lib/steep/services/completion_provider.rb +1 -13
- data/lib/steep/services/signature_service.rb +1 -1
- data/lib/steep/signature/validator.rb +56 -4
- data/lib/steep/type_construction.rb +52 -27
- data/lib/steep/type_inference/logic_type_interpreter.rb +32 -20
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +3 -0
- data/sample/lib/deprecated.rb +3 -0
- data/sample/sig/deprecated.rbs +6 -1
- data/steep.gemspec +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2233f51ac985ee697a7f3617582dc034f32b1cd3b0732a87b8184210f2c1d7b0
|
4
|
+
data.tar.gz: 1298685cafa59f5074afa950df4c1f14cff9a8b6be9b99b914902b37e537aad3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cb518e2f5743330e58b0c6032ed99d22f29254b91d9c8e33e3bafc3cb1a9f46247f181ee5b9b078dba13768f675f03b1c2e8fb24b53609902d6534092625282
|
7
|
+
data.tar.gz: e26fde370f8d793b13138d71dc6295ffde59e781ed2d0a39cf73e639c8440517d7fa13586d871c9eab6880ae8864c31a711beb45c49280152416d0111935f3da
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,46 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.10.0.pre.1 (2025-03-11)
|
4
|
+
|
5
|
+
### Type checker core
|
6
|
+
|
7
|
+
* Skip type checking forwarded argument if the method is undeclared ([#1519](https://github.com/soutaro/steep/pull/1519))
|
8
|
+
* Dedup error message on ancestors check ([#1515](https://github.com/soutaro/steep/pull/1515))
|
9
|
+
* Add deprecation validation on RBS ([#1518](https://github.com/soutaro/steep/pull/1518))
|
10
|
+
* Fix union self type refinement based on method call ([#1517](https://github.com/soutaro/steep/pull/1517))
|
11
|
+
* Check deprecations in Ruby code ([#1513](https://github.com/soutaro/steep/pull/1513))
|
12
|
+
* Support `InvalidTypeApplication` on `#update_env` ([#1507](https://github.com/soutaro/steep/pull/1507))
|
13
|
+
* Fix Source.parse crashes with selector-less sendish node ([#1433](https://github.com/soutaro/steep/pull/1433))
|
14
|
+
* Fix steep:ignore does not work with CR/LF ([#1406](https://github.com/soutaro/steep/pull/1406))
|
15
|
+
* Fix self union type checking ([#1467](https://github.com/soutaro/steep/pull/1467))
|
16
|
+
* Type narrowing union types via return type of method call ([#1497](https://github.com/soutaro/steep/pull/1497))
|
17
|
+
* Fix `else` clause of `case-when` syntax typing ([#1475](https://github.com/soutaro/steep/pull/1475))
|
18
|
+
* Strict record and tuple subtyping ([#1460](https://github.com/soutaro/steep/pull/1460))
|
19
|
+
* Allow to annotate "self" on toplevel ([#1455](https://github.com/soutaro/steep/pull/1455))
|
20
|
+
* Let annotations in `when` clause without `cond` expression work ([#1459](https://github.com/soutaro/steep/pull/1459))
|
21
|
+
* Fix `RuntimeError` on `when` clause with assertion ([#1458](https://github.com/soutaro/steep/pull/1458))
|
22
|
+
* Add diagnostic for method definition without types ([#1457](https://github.com/soutaro/steep/pull/1457))
|
23
|
+
|
24
|
+
### Commandline tool
|
25
|
+
|
26
|
+
* Implement GitHub formatter ([#1516](https://github.com/soutaro/steep/pull/1516))
|
27
|
+
* Refine `--help` messages ([#1463](https://github.com/soutaro/steep/pull/1463))
|
28
|
+
|
29
|
+
### Language server
|
30
|
+
|
31
|
+
* Reforking steep ([#1492](https://github.com/soutaro/steep/pull/1492))
|
32
|
+
* Set up file watcher for groups ([#1485](https://github.com/soutaro/steep/pull/1485))
|
33
|
+
|
34
|
+
### Miscellaneous
|
35
|
+
|
36
|
+
* Fix a runtime warning for ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator ([#1438](https://github.com/soutaro/steep/pull/1438))
|
37
|
+
* Fix a runtime warning for ambiguous `*` has been interpreted as an argument prefix ([#1439](https://github.com/soutaro/steep/pull/1439))
|
38
|
+
* Fix a runtime warning for key :cursor is duplicated and overwritten on line 99 ([#1440](https://github.com/soutaro/steep/pull/1440))
|
39
|
+
* Use release version of RBS ([#1511](https://github.com/soutaro/steep/pull/1511))
|
40
|
+
* Prepare for rbs-3.9 ([#1510](https://github.com/soutaro/steep/pull/1510))
|
41
|
+
* Fix typos ([#1506](https://github.com/soutaro/steep/pull/1506))
|
42
|
+
* Fix CI ([#1486](https://github.com/soutaro/steep/pull/1486))
|
43
|
+
|
3
44
|
## 1.9.3 (2024-12-26)
|
4
45
|
|
5
46
|
### Miscellaneous
|
@@ -14,5 +14,30 @@ module Steep
|
|
14
14
|
|
15
15
|
nil
|
16
16
|
end
|
17
|
+
|
18
|
+
def deprecated_type_name?(type_name, env)
|
19
|
+
annotations =
|
20
|
+
case
|
21
|
+
when type_name.class?
|
22
|
+
case
|
23
|
+
when decl = env.class_decls.fetch(type_name, nil)
|
24
|
+
decl.decls.flat_map { _1.decl.annotations }
|
25
|
+
when decl = env.class_alias_decls.fetch(type_name, nil)
|
26
|
+
decl.decl.annotations
|
27
|
+
end
|
28
|
+
when type_name.interface?
|
29
|
+
if decl = env.interface_decls.fetch(type_name, nil)
|
30
|
+
decl.decl.annotations
|
31
|
+
end
|
32
|
+
when type_name.alias?
|
33
|
+
if decl = env.type_alias_decls.fetch(type_name, nil)
|
34
|
+
decl.decl.annotations
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if annotations
|
39
|
+
deprecated_annotation?(annotations)
|
40
|
+
end
|
41
|
+
end
|
17
42
|
end
|
18
43
|
end
|
data/lib/steep/cli.rb
CHANGED
@@ -187,6 +187,10 @@ BANNER
|
|
187
187
|
end
|
188
188
|
end
|
189
189
|
|
190
|
+
opts.on("--format=FORMATTER", ["code", "github"], "Output formatters (default: code, options: code,github)") do |formatter|
|
191
|
+
command.formatter = formatter
|
192
|
+
end
|
193
|
+
|
190
194
|
handle_jobs_option command.jobs_option, opts
|
191
195
|
handle_logging_options opts
|
192
196
|
end.parse!(argv)
|
@@ -54,6 +54,9 @@ module Steep
|
|
54
54
|
case diagnostic
|
55
55
|
when Ruby::DeprecatedReference
|
56
56
|
tags << LSP::Constant::DiagnosticTag::DEPRECATED
|
57
|
+
when Signature::DeprecatedTypeName
|
58
|
+
tags << LSP::Constant::DiagnosticTag::DEPRECATED
|
59
|
+
severity = LSP::Constant::DiagnosticSeverity::WARNING
|
57
60
|
end
|
58
61
|
|
59
62
|
json = {
|
@@ -460,6 +460,26 @@ module Steep
|
|
460
460
|
end
|
461
461
|
end
|
462
462
|
|
463
|
+
class DeprecatedTypeName < Base
|
464
|
+
attr_reader :type_name
|
465
|
+
attr_reader :message
|
466
|
+
|
467
|
+
def initialize(type_name, message, location:)
|
468
|
+
super(location: location)
|
469
|
+
@type_name = type_name
|
470
|
+
@message = message
|
471
|
+
end
|
472
|
+
|
473
|
+
def header_line
|
474
|
+
buffer = "Type `#{type_name}` is deprecated"
|
475
|
+
if message
|
476
|
+
buffer = +buffer
|
477
|
+
buffer << ": " << message
|
478
|
+
end
|
479
|
+
buffer
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
463
483
|
|
464
484
|
def self.from_rbs_error(error, factory:)
|
465
485
|
case error
|
data/lib/steep/drivers/check.rb
CHANGED
@@ -16,6 +16,7 @@ module Steep
|
|
16
16
|
attr_accessor :validate_group_signatures
|
17
17
|
attr_accessor :validate_project_signatures
|
18
18
|
attr_accessor :validate_library_signatures
|
19
|
+
attr_accessor :formatter
|
19
20
|
|
20
21
|
include Utils::DriverHelper
|
21
22
|
|
@@ -30,6 +31,7 @@ module Steep
|
|
30
31
|
@validate_group_signatures = true
|
31
32
|
@validate_project_signatures = false
|
32
33
|
@validate_library_signatures = false
|
34
|
+
@formatter = 'code'
|
33
35
|
end
|
34
36
|
|
35
37
|
def active_group?(group)
|
@@ -322,7 +324,7 @@ module Steep
|
|
322
324
|
errors.each do |notification|
|
323
325
|
path = Steep::PathHelper.to_pathname(notification[:uri]) or raise
|
324
326
|
buffer = RBS::Buffer.new(name: project.relative_path(path), content: path.read)
|
325
|
-
printer = DiagnosticPrinter.new(buffer: buffer, stdout: stdout)
|
327
|
+
printer = DiagnosticPrinter.new(buffer: buffer, stdout: stdout, formatter: formatter)
|
326
328
|
|
327
329
|
notification[:diagnostics].each do |diag|
|
328
330
|
printer.print(diag)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class DiagnosticPrinter
|
4
|
+
class BaseFormatter
|
5
|
+
attr_reader :stdout
|
6
|
+
attr_reader :buffer
|
7
|
+
|
8
|
+
def initialize(stdout:, buffer:)
|
9
|
+
@stdout = stdout
|
10
|
+
@buffer = buffer
|
11
|
+
end
|
12
|
+
|
13
|
+
def path
|
14
|
+
Pathname(buffer.name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class DiagnosticPrinter
|
4
|
+
class CodeFormatter < BaseFormatter
|
5
|
+
def print(diagnostic, prefix: "", source: true)
|
6
|
+
header, *rest = diagnostic[:message].split(/\n/)
|
7
|
+
|
8
|
+
stdout.puts "#{prefix}#{location(diagnostic)}: [#{severity_message(diagnostic[:severity])}] #{Rainbow(header).underline}"
|
9
|
+
|
10
|
+
unless rest.empty?
|
11
|
+
rest.each do |message|
|
12
|
+
stdout.puts "#{prefix}│ #{message}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if diagnostic[:code]
|
17
|
+
stdout.puts "#{prefix}│" unless rest.empty?
|
18
|
+
stdout.puts "#{prefix}│ Diagnostic ID: #{diagnostic[:code]}"
|
19
|
+
end
|
20
|
+
|
21
|
+
stdout.puts "#{prefix}│"
|
22
|
+
|
23
|
+
if source
|
24
|
+
print_source_line(diagnostic, prefix: prefix)
|
25
|
+
else
|
26
|
+
stdout.puts "#{prefix}└ (no source code available)"
|
27
|
+
stdout.puts "#{prefix}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def color_severity(string, severity:)
|
34
|
+
s = Rainbow(string)
|
35
|
+
|
36
|
+
case severity
|
37
|
+
when LSP::Constant::DiagnosticSeverity::ERROR
|
38
|
+
s.red
|
39
|
+
when LSP::Constant::DiagnosticSeverity::WARNING
|
40
|
+
s.yellow
|
41
|
+
when LSP::Constant::DiagnosticSeverity::INFORMATION
|
42
|
+
s.blue
|
43
|
+
else
|
44
|
+
s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def severity_message(severity)
|
49
|
+
string = case severity
|
50
|
+
when LSP::Constant::DiagnosticSeverity::ERROR
|
51
|
+
"error"
|
52
|
+
when LSP::Constant::DiagnosticSeverity::WARNING
|
53
|
+
"warning"
|
54
|
+
when LSP::Constant::DiagnosticSeverity::INFORMATION
|
55
|
+
"information"
|
56
|
+
when LSP::Constant::DiagnosticSeverity::HINT
|
57
|
+
"hint"
|
58
|
+
else
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
|
62
|
+
color_severity(string, severity: severity)
|
63
|
+
end
|
64
|
+
|
65
|
+
def location(diagnostic)
|
66
|
+
start = diagnostic[:range][:start]
|
67
|
+
Rainbow("#{path}:#{start[:line]+1}:#{start[:character]}").magenta
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_source_line(diagnostic, prefix: "")
|
71
|
+
start_pos = diagnostic[:range][:start]
|
72
|
+
end_pos = diagnostic[:range][:end]
|
73
|
+
|
74
|
+
line = buffer.lines.fetch(start_pos[:line])
|
75
|
+
|
76
|
+
leading = line[0...start_pos[:character]] || ""
|
77
|
+
if start_pos[:line] == end_pos[:line]
|
78
|
+
subject = line[start_pos[:character]...end_pos[:character]] || ""
|
79
|
+
trailing = (line[end_pos[:character]...] || "").chomp
|
80
|
+
else
|
81
|
+
subject = (line[start_pos[:character]...] || "").chomp
|
82
|
+
trailing = ""
|
83
|
+
end
|
84
|
+
|
85
|
+
unless subject.valid_encoding?
|
86
|
+
subject.scrub!
|
87
|
+
end
|
88
|
+
|
89
|
+
stdout.puts "#{prefix}└ #{leading}#{color_severity(subject, severity: diagnostic[:severity])}#{trailing}"
|
90
|
+
stdout.puts "#{prefix} #{" " * leading.size}#{"~" * subject.size}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Steep
|
2
|
+
module Drivers
|
3
|
+
class DiagnosticPrinter
|
4
|
+
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions
|
5
|
+
class GitHubActionsFormatter < BaseFormatter
|
6
|
+
ESCAPE_MAP = { '%' => '%25', "\n" => '%0A', "\r" => '%0D' }.freeze
|
7
|
+
|
8
|
+
def print(diagnostic, prefix: "", source: true)
|
9
|
+
stdout.printf(
|
10
|
+
"::%<severity>s file=%<file>s,line=%<line>d,endLine=%<endLine>d,col=%<column>d,endColumn=%<endColumn>d::%<message>s",
|
11
|
+
severity: github_severity(diagnostic[:severity]),
|
12
|
+
file: path,
|
13
|
+
line: diagnostic[:range][:start][:line] + 1,
|
14
|
+
endLine: diagnostic[:range][:end][:line] + 1,
|
15
|
+
column: diagnostic[:range][:start][:character],
|
16
|
+
endColumn: diagnostic[:range][:end][:character],
|
17
|
+
message: github_escape("[#{diagnostic[:code]}] #{diagnostic[:message]}")
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def github_severity(severity)
|
24
|
+
case severity
|
25
|
+
when LSP::Constant::DiagnosticSeverity::ERROR
|
26
|
+
"error"
|
27
|
+
when LSP::Constant::DiagnosticSeverity::WARNING
|
28
|
+
"warning"
|
29
|
+
when LSP::Constant::DiagnosticSeverity::INFORMATION
|
30
|
+
"notice"
|
31
|
+
when LSP::Constant::DiagnosticSeverity::HINT
|
32
|
+
"notice"
|
33
|
+
else
|
34
|
+
raise
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def github_escape(string)
|
39
|
+
string.gsub(Regexp.union(ESCAPE_MAP.keys), ESCAPE_MAP)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,104 +1,27 @@
|
|
1
1
|
module Steep
|
2
2
|
module Drivers
|
3
3
|
class DiagnosticPrinter
|
4
|
+
|
4
5
|
LSP = LanguageServer::Protocol
|
5
6
|
|
6
7
|
attr_reader :stdout
|
7
8
|
attr_reader :buffer
|
8
9
|
|
9
|
-
def initialize(stdout:, buffer:)
|
10
|
+
def initialize(stdout:, buffer:, formatter: 'code')
|
10
11
|
@stdout = stdout
|
11
12
|
@buffer = buffer
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def color_severity(string, severity:)
|
19
|
-
s = Rainbow(string)
|
20
|
-
|
21
|
-
case severity
|
22
|
-
when LSP::Constant::DiagnosticSeverity::ERROR
|
23
|
-
s.red
|
24
|
-
when LSP::Constant::DiagnosticSeverity::WARNING
|
25
|
-
s.yellow
|
26
|
-
when LSP::Constant::DiagnosticSeverity::INFORMATION
|
27
|
-
s.blue
|
13
|
+
@formatter = case formatter
|
14
|
+
when 'code'
|
15
|
+
CodeFormatter.new(stdout: stdout, buffer: buffer)
|
16
|
+
when 'github'
|
17
|
+
GitHubActionsFormatter.new(stdout: stdout, buffer: buffer)
|
28
18
|
else
|
29
|
-
|
19
|
+
raise "Unknown formatter: #{formatter}"
|
30
20
|
end
|
31
21
|
end
|
32
22
|
|
33
|
-
def severity_message(severity)
|
34
|
-
string = case severity
|
35
|
-
when LSP::Constant::DiagnosticSeverity::ERROR
|
36
|
-
"error"
|
37
|
-
when LSP::Constant::DiagnosticSeverity::WARNING
|
38
|
-
"warning"
|
39
|
-
when LSP::Constant::DiagnosticSeverity::INFORMATION
|
40
|
-
"information"
|
41
|
-
when LSP::Constant::DiagnosticSeverity::HINT
|
42
|
-
"hint"
|
43
|
-
else
|
44
|
-
raise
|
45
|
-
end
|
46
|
-
|
47
|
-
color_severity(string, severity: severity)
|
48
|
-
end
|
49
|
-
|
50
|
-
def location(diagnostic)
|
51
|
-
start = diagnostic[:range][:start]
|
52
|
-
Rainbow("#{path}:#{start[:line]+1}:#{start[:character]}").magenta
|
53
|
-
end
|
54
|
-
|
55
23
|
def print(diagnostic, prefix: "", source: true)
|
56
|
-
|
57
|
-
|
58
|
-
stdout.puts "#{prefix}#{location(diagnostic)}: [#{severity_message(diagnostic[:severity])}] #{Rainbow(header).underline}"
|
59
|
-
|
60
|
-
unless rest.empty?
|
61
|
-
rest.each do |message|
|
62
|
-
stdout.puts "#{prefix}│ #{message}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
if diagnostic[:code]
|
67
|
-
stdout.puts "#{prefix}│" unless rest.empty?
|
68
|
-
stdout.puts "#{prefix}│ Diagnostic ID: #{diagnostic[:code]}"
|
69
|
-
end
|
70
|
-
|
71
|
-
stdout.puts "#{prefix}│"
|
72
|
-
|
73
|
-
if source
|
74
|
-
print_source_line(diagnostic, prefix: prefix)
|
75
|
-
else
|
76
|
-
stdout.puts "#{prefix}└ (no source code available)"
|
77
|
-
stdout.puts "#{prefix}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def print_source_line(diagnostic, prefix: "")
|
82
|
-
start_pos = diagnostic[:range][:start]
|
83
|
-
end_pos = diagnostic[:range][:end]
|
84
|
-
|
85
|
-
line = buffer.lines.fetch(start_pos[:line])
|
86
|
-
|
87
|
-
leading = line[0...start_pos[:character]] || ""
|
88
|
-
if start_pos[:line] == end_pos[:line]
|
89
|
-
subject = line[start_pos[:character]...end_pos[:character]] || ""
|
90
|
-
trailing = (line[end_pos[:character]...] || "").chomp
|
91
|
-
else
|
92
|
-
subject = (line[start_pos[:character]...] || "").chomp
|
93
|
-
trailing = ""
|
94
|
-
end
|
95
|
-
|
96
|
-
unless subject.valid_encoding?
|
97
|
-
subject.scrub!
|
98
|
-
end
|
99
|
-
|
100
|
-
stdout.puts "#{prefix}└ #{leading}#{color_severity(subject, severity: diagnostic[:severity])}#{trailing}"
|
101
|
-
stdout.puts "#{prefix} #{" " * leading.size}#{"~" * subject.size}"
|
24
|
+
@formatter.print(diagnostic, prefix: prefix, source: source)
|
102
25
|
end
|
103
26
|
end
|
104
27
|
end
|
@@ -268,6 +268,11 @@ module Steep
|
|
268
268
|
|
269
269
|
type_name = sig_service.latest_env.normalize_type_name(type_name)
|
270
270
|
|
271
|
+
tags = [] #: Array[LSP::Constant::CompletionItemTag::t]
|
272
|
+
if AnnotationsHelper.deprecated_type_name?(type_name, sig_service.latest_env)
|
273
|
+
tags << LSP::Constant::CompletionItemTag::DEPRECATED
|
274
|
+
end
|
275
|
+
|
271
276
|
case type_name.kind
|
272
277
|
when :class
|
273
278
|
env = sig_service.latest_env
|
@@ -290,7 +295,8 @@ module Steep
|
|
290
295
|
range: range,
|
291
296
|
new_text: complete_text
|
292
297
|
),
|
293
|
-
kind: LSP::Constant::CompletionItemKind::CLASS
|
298
|
+
kind: LSP::Constant::CompletionItemKind::CLASS,
|
299
|
+
tags: tags
|
294
300
|
)
|
295
301
|
when :alias
|
296
302
|
alias_decl = sig_service.latest_env.type_alias_decls[type_name]&.decl or raise
|
@@ -303,7 +309,8 @@ module Steep
|
|
303
309
|
new_text: complete_text
|
304
310
|
),
|
305
311
|
documentation: LSPFormatter.markup_content { LSPFormatter.format_rbs_completion_docs(type_name, alias_decl, [alias_decl.comment].compact) },
|
306
|
-
kind: LSP::Constant::CompletionItemKind::FIELD
|
312
|
+
kind: LSP::Constant::CompletionItemKind::FIELD,
|
313
|
+
tags: tags
|
307
314
|
)
|
308
315
|
when :interface
|
309
316
|
interface_decl = sig_service.latest_env.interface_decls[type_name]&.decl or raise
|
@@ -316,7 +323,8 @@ module Steep
|
|
316
323
|
new_text: complete_text
|
317
324
|
),
|
318
325
|
documentation: LSPFormatter.markup_content { LSPFormatter.format_rbs_completion_docs(type_name, interface_decl, [interface_decl.comment].compact) },
|
319
|
-
kind: LSP::Constant::CompletionItemKind::INTERFACE
|
326
|
+
kind: LSP::Constant::CompletionItemKind::INTERFACE,
|
327
|
+
tags: tags
|
320
328
|
)
|
321
329
|
else
|
322
330
|
raise
|
@@ -435,6 +443,12 @@ module Steep
|
|
435
443
|
when item.absolute_type_name.alias?
|
436
444
|
LSP::Constant::CompletionItemKind::FIELD
|
437
445
|
end
|
446
|
+
|
447
|
+
tags = [] #: Array[LSP::Constant::CompletionItemTag::t]
|
448
|
+
if AnnotationsHelper.deprecated_type_name?(item.absolute_type_name, item.env)
|
449
|
+
tags << LSP::Constant::CompletionItemTag::DEPRECATED
|
450
|
+
end
|
451
|
+
|
438
452
|
LSP::Interface::CompletionItem.new(
|
439
453
|
label: item.relative_type_name.to_s,
|
440
454
|
kind: kind,
|
@@ -443,7 +457,8 @@ module Steep
|
|
443
457
|
text_edit: LSP::Interface::TextEdit.new(
|
444
458
|
range: range,
|
445
459
|
new_text: item.relative_type_name.to_s
|
446
|
-
)
|
460
|
+
),
|
461
|
+
tags: tags
|
447
462
|
)
|
448
463
|
when Services::CompletionProvider::TextItem
|
449
464
|
LSP::Interface::CompletionItem.new(
|
@@ -53,19 +53,7 @@ module Steep
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def deprecated?
|
56
|
-
|
57
|
-
case entry = env.constant_entry(full_name)
|
58
|
-
when RBS::Environment::ConstantEntry
|
59
|
-
entry.decl.annotations
|
60
|
-
when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
|
61
|
-
entry.decls.flat_map { _1.decl.annotations }
|
62
|
-
when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
|
63
|
-
entry.decl.annotations
|
64
|
-
else
|
65
|
-
raise
|
66
|
-
end
|
67
|
-
|
68
|
-
if AnnotationsHelper.deprecated_annotation?(annotations)
|
56
|
+
if AnnotationsHelper.deprecated_type_name?(full_name, env)
|
69
57
|
true
|
70
58
|
else
|
71
59
|
false
|
@@ -294,7 +294,7 @@ module Steep
|
|
294
294
|
end
|
295
295
|
|
296
296
|
unless errors.empty?
|
297
|
-
|
297
|
+
errors.uniq! { |e| [e.class, e.message] }
|
298
298
|
factory = AST::Types::Factory.new(builder: RBS::DefinitionBuilder.new(env: env, ancestor_builder: builder))
|
299
299
|
return errors.map {|error| Diagnostic::Signature.from_rbs_error(error, factory: factory) }
|
300
300
|
end
|
@@ -144,17 +144,39 @@ module Steep
|
|
144
144
|
validate_type_application_constraints(name, type_params, type_args, location: type.location)
|
145
145
|
end
|
146
146
|
end
|
147
|
-
|
148
|
-
type.each_type do |child|
|
149
|
-
validate_type_application(child)
|
150
|
-
end
|
151
147
|
end
|
152
148
|
|
153
149
|
def validate_type(type)
|
154
150
|
Steep.logger.debug { "#{Location.to_string type.location}: Validating #{type}..." }
|
155
151
|
|
156
152
|
validator.validate_type(type, context: nil)
|
153
|
+
validate_type_0(type)
|
154
|
+
end
|
155
|
+
|
156
|
+
def validate_type_0(type)
|
157
157
|
validate_type_application(type)
|
158
|
+
|
159
|
+
case type
|
160
|
+
when RBS::Types::ClassInstance, RBS::Types::Interface, RBS::Types::ClassSingleton, RBS::Types::Alias
|
161
|
+
type_name = type.name
|
162
|
+
if type.location
|
163
|
+
location = type.location[:name]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
if type_name && location
|
168
|
+
validate_type_name_deprecation(type_name, location)
|
169
|
+
end
|
170
|
+
|
171
|
+
type.each_type do |child|
|
172
|
+
validate_type_0(child)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def validate_type_name_deprecation(type_name, location)
|
177
|
+
if (_, message = AnnotationsHelper.deprecated_type_name?(type_name, env))
|
178
|
+
@errors << Diagnostic::Signature::DeprecatedTypeName.new(type_name, message, location: location)
|
179
|
+
end
|
158
180
|
end
|
159
181
|
|
160
182
|
def ancestor_to_type(ancestor)
|
@@ -269,6 +291,9 @@ module Steep
|
|
269
291
|
type_params.each do |type_param|
|
270
292
|
param = checker.factory.type_param(type_param)
|
271
293
|
|
294
|
+
validate_type(type_param.upper_bound_type) if type_param.upper_bound_type
|
295
|
+
validate_type(type_param.default_type) if type_param.default_type
|
296
|
+
|
272
297
|
default_type = param.default_type or next
|
273
298
|
upper_bound = param.upper_bound or next
|
274
299
|
|
@@ -296,6 +321,16 @@ module Steep
|
|
296
321
|
args: entry.type_params.map { AST::Types::Any.instance() }
|
297
322
|
)
|
298
323
|
|
324
|
+
entry.decls.each do |decl|
|
325
|
+
ast = decl.decl
|
326
|
+
|
327
|
+
unless AnnotationsHelper.deprecated_annotation?(ast.annotations)
|
328
|
+
if location = ast.location
|
329
|
+
validate_type_name_deprecation(name, location[:name])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
299
334
|
Steep.logger.tagged "#{name}" do
|
300
335
|
builder.build_instance(name).tap do |definition|
|
301
336
|
upper_bounds = definition.type_params_decl.each.with_object({}) do |param, bounds| #$ Hash[Symbol, AST::Types::t?]
|
@@ -353,6 +388,20 @@ module Steep
|
|
353
388
|
case ancestor
|
354
389
|
when RBS::Definition::Ancestor::Instance
|
355
390
|
validate_ancestor_application(name, ancestor)
|
391
|
+
location =
|
392
|
+
case ancestor.source
|
393
|
+
when :super
|
394
|
+
if (primary_decl = entry.primary.decl).is_a?(RBS::AST::Declarations::Class)
|
395
|
+
primary_decl.super_class&.location
|
396
|
+
end
|
397
|
+
when nil
|
398
|
+
# skip
|
399
|
+
else
|
400
|
+
ancestor.source.location
|
401
|
+
end
|
402
|
+
if location
|
403
|
+
validate_type_name_deprecation(ancestor.name, location)
|
404
|
+
end
|
356
405
|
end
|
357
406
|
end
|
358
407
|
|
@@ -632,6 +681,9 @@ module Steep
|
|
632
681
|
rescue_validation_errors(name) do
|
633
682
|
Steep.logger.debug "Validating class/module alias `#{name}`..."
|
634
683
|
validator.validate_class_alias(entry: entry)
|
684
|
+
if location = entry.decl.location
|
685
|
+
validate_type_name_deprecation(entry.decl.old_name, location[:old_name])
|
686
|
+
end
|
635
687
|
end
|
636
688
|
end
|
637
689
|
|
@@ -3864,26 +3864,40 @@ module Steep
|
|
3864
3864
|
if forwarded_args
|
3865
3865
|
method_name or raise "method_name cannot be nil if `forwarded_args` is given, because proc/block doesn't support `...` arg"
|
3866
3866
|
|
3867
|
-
|
3868
|
-
|
3869
|
-
checker.with_context(self_type: self_type, instance_type: context.module_context.instance_type, class_type: context.module_context.module_type, constraints: constraints) do
|
3870
|
-
result = checker.check_method_params(
|
3871
|
-
:"... (argument forwarding)",
|
3872
|
-
Subtyping::Relation.new(
|
3873
|
-
sub_type: forwarded_args.params,
|
3874
|
-
super_type: params
|
3875
|
-
)
|
3876
|
-
)
|
3867
|
+
method_context = context.method_context or raise
|
3868
|
+
forward_arg_type = method_context.forward_arg_type
|
3877
3869
|
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
3881
|
-
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3870
|
+
case forward_arg_type
|
3871
|
+
when nil
|
3872
|
+
if context.method_context.method_type
|
3873
|
+
raise "Method context must have `forwarded_arg_type` if `...` node appears in it"
|
3874
|
+
else
|
3875
|
+
# Skips type checking forwarded argument because the method type is not given
|
3876
|
+
end
|
3877
|
+
when true
|
3878
|
+
# Skip type checking forwarded argument because the method is untyped function
|
3879
|
+
else
|
3880
|
+
params, _block = forward_arg_type
|
3881
|
+
|
3882
|
+
checker.with_context(self_type: self_type, instance_type: context.module_context.instance_type, class_type: context.module_context.module_type, constraints: constraints) do
|
3883
|
+
result = checker.check_method_params(
|
3884
|
+
:"... (argument forwarding)",
|
3885
|
+
Subtyping::Relation.new(
|
3886
|
+
sub_type: forwarded_args.params,
|
3887
|
+
super_type: params
|
3885
3888
|
)
|
3886
3889
|
)
|
3890
|
+
|
3891
|
+
if result.failure?
|
3892
|
+
errors.push(
|
3893
|
+
Diagnostic::Ruby::IncompatibleArgumentForwarding.new(
|
3894
|
+
method_name: method_name,
|
3895
|
+
node: forwarded_args.node,
|
3896
|
+
params_pair: [params, forwarded_args.params],
|
3897
|
+
result: result
|
3898
|
+
)
|
3899
|
+
)
|
3900
|
+
end
|
3887
3901
|
end
|
3888
3902
|
end
|
3889
3903
|
end
|
@@ -4237,18 +4251,29 @@ module Steep
|
|
4237
4251
|
|
4238
4252
|
case
|
4239
4253
|
when forwarded_args_node = args.forwarded_args_node
|
4240
|
-
|
4254
|
+
case forward_arg_type = method_context!.forward_arg_type
|
4255
|
+
when nil
|
4256
|
+
if method_context!.method_type
|
4257
|
+
raise "Method context must have `forwarded_arg_type` if `...` node appears in it"
|
4258
|
+
else
|
4259
|
+
# Skips type checking forwarded argument because the method type is not given
|
4260
|
+
end
|
4261
|
+
when true
|
4262
|
+
# Skip type checking because it's untyped function
|
4263
|
+
else
|
4264
|
+
_, block = forward_arg_type
|
4241
4265
|
|
4242
|
-
|
4243
|
-
|
4266
|
+
method_block_type = method_type.block&.to_proc_type || AST::Builtin.nil_type
|
4267
|
+
forwarded_block_type = block&.to_proc_type || AST::Builtin.nil_type
|
4244
4268
|
|
4245
|
-
|
4246
|
-
|
4247
|
-
|
4248
|
-
|
4249
|
-
|
4250
|
-
|
4251
|
-
|
4269
|
+
if result = constr.no_subtyping?(sub_type: forwarded_block_type, super_type: method_block_type)
|
4270
|
+
errors << Diagnostic::Ruby::IncompatibleArgumentForwarding.new(
|
4271
|
+
method_name: method_name,
|
4272
|
+
node: forwarded_args_node,
|
4273
|
+
block_pair: [block, method_type.block],
|
4274
|
+
result: result
|
4275
|
+
)
|
4276
|
+
end
|
4252
4277
|
end
|
4253
4278
|
|
4254
4279
|
when arg.compatible?
|
@@ -173,29 +173,41 @@ module Steep
|
|
173
173
|
receiver_type = typing.type_of(node: receiver) if receiver
|
174
174
|
|
175
175
|
if env[receiver] && receiver_type.is_a?(AST::Types::Union)
|
176
|
-
result = evaluate_union_method_call(node: node, env: env, receiver: receiver, receiver_type: receiver_type)
|
177
|
-
|
176
|
+
result = evaluate_union_method_call(node: node, type: type, env: env, receiver: receiver, receiver_type: receiver_type)
|
177
|
+
if result
|
178
|
+
truthy_result = result[0] unless result[0].unreachable
|
179
|
+
falsy_result = result[1] unless result[1].unreachable
|
180
|
+
end
|
178
181
|
end
|
179
182
|
|
180
|
-
|
181
|
-
|
183
|
+
truthy_result ||= Result.new(type: type, env: env, unreachable: false)
|
184
|
+
falsy_result ||= Result.new(type: type, env: env, unreachable: false)
|
182
185
|
|
183
|
-
|
184
|
-
if truthy_type
|
185
|
-
Result.new(type: truthy_type, env: env.refine_types(pure_call_types: { node => truthy_type }), unreachable: false)
|
186
|
-
else
|
187
|
-
Result.new(type: type, env: env, unreachable: true)
|
188
|
-
end
|
186
|
+
truthy_type, falsy_type = factory.partition_union(type)
|
189
187
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
end
|
188
|
+
if truthy_type
|
189
|
+
truthy_result = truthy_result.update_type { truthy_type }
|
190
|
+
else
|
191
|
+
truthy_result = truthy_result.update_type { BOT }.unreachable!
|
192
|
+
end
|
196
193
|
|
197
|
-
|
194
|
+
if falsy_type
|
195
|
+
falsy_result = falsy_result.update_type { falsy_type }
|
196
|
+
else
|
197
|
+
falsy_result = falsy_result.update_type { BOT }.unreachable!
|
198
|
+
end
|
199
|
+
|
200
|
+
if truthy_result.env[node] && falsy_result.env[node]
|
201
|
+
if truthy_type
|
202
|
+
truthy_result = Result.new(type: truthy_type, env: truthy_result.env.refine_types(pure_call_types: { node => truthy_type }), unreachable: false)
|
203
|
+
end
|
204
|
+
|
205
|
+
if falsy_type
|
206
|
+
falsy_result = Result.new(type: falsy_type, env: falsy_result.env.refine_types(pure_call_types: { node => falsy_type }), unreachable: false)
|
207
|
+
end
|
198
208
|
end
|
209
|
+
|
210
|
+
return [truthy_result, falsy_result]
|
199
211
|
end
|
200
212
|
end
|
201
213
|
|
@@ -416,7 +428,7 @@ module Steep
|
|
416
428
|
end
|
417
429
|
end
|
418
430
|
|
419
|
-
def evaluate_union_method_call(node:, env:, receiver:, receiver_type:)
|
431
|
+
def evaluate_union_method_call(node:, type:, env:, receiver:, receiver_type:)
|
420
432
|
call_type = typing.call_of(node: node) rescue nil
|
421
433
|
return unless call_type.is_a?(Steep::TypeInference::MethodCall::Typed)
|
422
434
|
|
@@ -453,8 +465,8 @@ module Steep
|
|
453
465
|
)
|
454
466
|
|
455
467
|
return [
|
456
|
-
Result.new(type:
|
457
|
-
Result.new(type:
|
468
|
+
Result.new(type: type, env: truthy_env, unreachable: truthy_type.nil?),
|
469
|
+
Result.new(type: type, env: falsy_env, unreachable: falsy_type.nil?)
|
458
470
|
]
|
459
471
|
end
|
460
472
|
|
data/lib/steep/version.rb
CHANGED
data/lib/steep.rb
CHANGED
@@ -151,6 +151,9 @@ require "steep/drivers/init"
|
|
151
151
|
require "steep/drivers/vendor"
|
152
152
|
require "steep/drivers/worker"
|
153
153
|
require "steep/drivers/diagnostic_printer"
|
154
|
+
require "steep/drivers/diagnostic_printer/base_formatter"
|
155
|
+
require "steep/drivers/diagnostic_printer/code_formatter"
|
156
|
+
require "steep/drivers/diagnostic_printer/github_actions_formatter"
|
154
157
|
|
155
158
|
require "steep/annotations_helper"
|
156
159
|
|
data/sample/lib/deprecated.rb
CHANGED
data/sample/sig/deprecated.rbs
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
%a{deprecated} class Foo end
|
1
|
+
%a{deprecated: Use Bar instead} class Foo end
|
2
2
|
|
3
3
|
class Bar
|
4
4
|
# Original bar
|
@@ -6,6 +6,11 @@ class Bar
|
|
6
6
|
|
7
7
|
# Overloading bar
|
8
8
|
def self.bar: (String) -> String | ...
|
9
|
+
|
10
|
+
def hogehoge: (String) -> void
|
11
|
+
| %a{deprecated: Pass an positional argument} (string: String) -> void
|
9
12
|
end
|
10
13
|
|
14
|
+
type t = Foo
|
15
|
+
|
11
16
|
%a{deprecated} $test: untyped
|
data/steep.gemspec
CHANGED
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
|
43
43
|
spec.add_runtime_dependency "listen", "~> 3.0"
|
44
44
|
spec.add_runtime_dependency "language_server-protocol", ">= 3.17.0.4", "< 4.0"
|
45
|
-
spec.add_runtime_dependency "rbs", "~> 3.9.
|
45
|
+
spec.add_runtime_dependency "rbs", "~> 3.9.pre"
|
46
46
|
spec.add_runtime_dependency "concurrent-ruby", ">= 1.1.10"
|
47
47
|
spec.add_runtime_dependency "terminal-table", ">= 2", "< 5"
|
48
48
|
spec.add_runtime_dependency "securerandom", ">= 0.1"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.10.0.
|
4
|
+
version: 1.10.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: parser
|
@@ -97,14 +97,14 @@ dependencies:
|
|
97
97
|
requirements:
|
98
98
|
- - "~>"
|
99
99
|
- !ruby/object:Gem::Version
|
100
|
-
version: 3.9.
|
100
|
+
version: 3.9.pre
|
101
101
|
type: :runtime
|
102
102
|
prerelease: false
|
103
103
|
version_requirements: !ruby/object:Gem::Requirement
|
104
104
|
requirements:
|
105
105
|
- - "~>"
|
106
106
|
- !ruby/object:Gem::Version
|
107
|
-
version: 3.9.
|
107
|
+
version: 3.9.pre
|
108
108
|
- !ruby/object:Gem::Dependency
|
109
109
|
name: concurrent-ruby
|
110
110
|
requirement: !ruby/object:Gem::Requirement
|
@@ -328,6 +328,9 @@ files:
|
|
328
328
|
- lib/steep/drivers/check.rb
|
329
329
|
- lib/steep/drivers/checkfile.rb
|
330
330
|
- lib/steep/drivers/diagnostic_printer.rb
|
331
|
+
- lib/steep/drivers/diagnostic_printer/base_formatter.rb
|
332
|
+
- lib/steep/drivers/diagnostic_printer/code_formatter.rb
|
333
|
+
- lib/steep/drivers/diagnostic_printer/github_actions_formatter.rb
|
331
334
|
- lib/steep/drivers/init.rb
|
332
335
|
- lib/steep/drivers/langserver.rb
|
333
336
|
- lib/steep/drivers/print_project.rb
|