steep 0.44.0 → 0.47.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +0 -1
- data/CHANGELOG.md +42 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +75 -0
- data/README.md +2 -1
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/builtin.rb +7 -1
- data/lib/steep/ast/types/factory.rb +19 -25
- data/lib/steep/cli.rb +7 -1
- data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
- data/lib/steep/diagnostic/ruby.rb +188 -60
- data/lib/steep/diagnostic/signature.rb +38 -15
- data/lib/steep/drivers/check.rb +3 -0
- data/lib/steep/drivers/init.rb +10 -3
- data/lib/steep/drivers/utils/driver_helper.rb +15 -0
- data/lib/steep/drivers/validate.rb +1 -1
- data/lib/steep/drivers/watch.rb +3 -0
- data/lib/steep/equatable.rb +21 -0
- data/lib/steep/interface/function.rb +798 -579
- data/lib/steep/project/dsl.rb +135 -36
- data/lib/steep/project/options.rb +13 -53
- data/lib/steep/project/target.rb +22 -8
- data/lib/steep/server/interaction_worker.rb +245 -26
- data/lib/steep/server/master.rb +2 -2
- data/lib/steep/server/type_check_worker.rb +6 -9
- data/lib/steep/services/file_loader.rb +26 -19
- data/lib/steep/services/goto_service.rb +1 -0
- data/lib/steep/services/hover_content.rb +135 -80
- data/lib/steep/source.rb +12 -11
- data/lib/steep/type_construction.rb +435 -502
- data/lib/steep/type_inference/block_params.rb +3 -6
- data/lib/steep/type_inference/method_params.rb +483 -0
- data/lib/steep/type_inference/send_args.rb +599 -128
- data/lib/steep/typing.rb +46 -21
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +4 -2
- data/sample/Steepfile +10 -3
- data/smoke/alias/Steepfile +2 -1
- data/smoke/and/Steepfile +2 -1
- data/smoke/array/Steepfile +2 -1
- data/smoke/array/test_expectations.yml +3 -3
- data/smoke/block/Steepfile +2 -2
- data/smoke/block/c.rb +0 -1
- data/smoke/case/Steepfile +2 -1
- data/smoke/class/Steepfile +2 -1
- data/smoke/class/test_expectations.yml +12 -15
- data/smoke/const/Steepfile +2 -1
- data/smoke/diagnostics/Steepfile +2 -1
- data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
- data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
- data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
- data/smoke/diagnostics/test_expectations.yml +108 -31
- data/smoke/diagnostics-rbs/Steepfile +1 -1
- data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
- data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
- data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
- data/smoke/diagnostics-ruby-unsat/Steepfile +2 -1
- data/smoke/dstr/Steepfile +2 -1
- data/smoke/ensure/Steepfile +2 -1
- data/smoke/ensure/test_expectations.yml +3 -3
- data/smoke/enumerator/Steepfile +2 -1
- data/smoke/enumerator/test_expectations.yml +1 -1
- data/smoke/extension/Steepfile +2 -1
- data/smoke/extension/e.rbs +1 -1
- data/smoke/hash/Steepfile +2 -1
- data/smoke/hello/Steepfile +2 -1
- data/smoke/if/Steepfile +2 -1
- data/smoke/implements/Steepfile +2 -1
- data/smoke/initialize/Steepfile +2 -1
- data/smoke/integer/Steepfile +2 -1
- data/smoke/interface/Steepfile +2 -1
- data/smoke/kwbegin/Steepfile +2 -1
- data/smoke/lambda/Steepfile +2 -1
- data/smoke/literal/Steepfile +2 -1
- data/smoke/literal/test_expectations.yml +2 -2
- data/smoke/map/Steepfile +2 -1
- data/smoke/method/Steepfile +2 -1
- data/smoke/method/test_expectations.yml +11 -10
- data/smoke/module/Steepfile +2 -1
- data/smoke/regexp/Steepfile +2 -1
- data/smoke/regression/Steepfile +2 -1
- data/smoke/rescue/Steepfile +2 -1
- data/smoke/rescue/test_expectations.yml +3 -3
- data/smoke/self/Steepfile +2 -1
- data/smoke/skip/Steepfile +2 -1
- data/smoke/stdout/Steepfile +2 -1
- data/smoke/super/Steepfile +2 -1
- data/smoke/toplevel/Steepfile +2 -1
- data/smoke/toplevel/test_expectations.yml +3 -3
- data/smoke/tsort/Steepfile +4 -5
- data/smoke/tsort/test_expectations.yml +2 -2
- data/smoke/type_case/Steepfile +2 -1
- data/smoke/unexpected/Steepfile +2 -1
- data/smoke/yield/Steepfile +2 -1
- data/steep.gemspec +2 -2
- metadata +16 -10
- data/sig/project.rbi +0 -109
data/lib/steep/project/dsl.rb
CHANGED
@@ -7,21 +7,34 @@ module Steep
|
|
7
7
|
attr_reader :libraries
|
8
8
|
attr_reader :signatures
|
9
9
|
attr_reader :ignored_sources
|
10
|
-
attr_reader :
|
11
|
-
attr_reader :
|
12
|
-
attr_reader :typing_option_hash
|
10
|
+
attr_reader :stdlib_root
|
11
|
+
attr_reader :core_root
|
13
12
|
attr_reader :repo_paths
|
13
|
+
attr_reader :code_diagnostics_config
|
14
|
+
attr_reader :project
|
15
|
+
attr_reader :collection_config_path
|
14
16
|
|
15
|
-
|
17
|
+
NONE = Object.new.freeze
|
18
|
+
|
19
|
+
def initialize(name, sources: [], libraries: [], signatures: [], ignored_sources: [], repo_paths: [], code_diagnostics_config: {}, project: nil, collection_config_path: NONE)
|
16
20
|
@name = name
|
17
21
|
@sources = sources
|
18
22
|
@libraries = libraries
|
19
23
|
@signatures = signatures
|
20
24
|
@ignored_sources = ignored_sources
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@typing_option_hash = {}
|
25
|
+
@core_root = nil
|
26
|
+
@stdlib_root = nil
|
24
27
|
@repo_paths = []
|
28
|
+
@code_diagnostics_config = code_diagnostics_config
|
29
|
+
@project = project
|
30
|
+
@collection_config_path =
|
31
|
+
case collection_config_path
|
32
|
+
when NONE
|
33
|
+
path = project&.absolute_path(RBS::Collection::Config::PATH)
|
34
|
+
path&.exist? ? path : nil
|
35
|
+
else
|
36
|
+
collection_config_path
|
37
|
+
end
|
25
38
|
end
|
26
39
|
|
27
40
|
def initialize_copy(other)
|
@@ -30,10 +43,12 @@ module Steep
|
|
30
43
|
@libraries = other.libraries.dup
|
31
44
|
@signatures = other.signatures.dup
|
32
45
|
@ignored_sources = other.ignored_sources.dup
|
33
|
-
@vendor_dir = other.vendor_dir
|
34
|
-
@strictness_level = other.strictness_level
|
35
|
-
@typing_option_hash = other.typing_option_hash
|
36
46
|
@repo_paths = other.repo_paths.dup
|
47
|
+
@core_root = other.core_root
|
48
|
+
@stdlib_root = other.stdlib_root
|
49
|
+
@code_diagnostics_config = other.code_diagnostics_config.dup
|
50
|
+
@project = other.project
|
51
|
+
@collection_config_path = other.collection_config_path
|
37
52
|
end
|
38
53
|
|
39
54
|
def check(*args)
|
@@ -48,40 +63,122 @@ module Steep
|
|
48
63
|
libraries.push(*args)
|
49
64
|
end
|
50
65
|
|
51
|
-
def typing_options(level =
|
52
|
-
|
53
|
-
|
66
|
+
def typing_options(level = nil, **hash)
|
67
|
+
Steep.logger.error "#typing_options is deprecated and has no effect as of version 0.46.0. Update your Steepfile as follows for (almost) equivalent setting:"
|
68
|
+
|
69
|
+
messages = []
|
70
|
+
|
71
|
+
messages << "# D = Steep::Diagnostic # Define a constant to shorten namespace"
|
72
|
+
|
73
|
+
case level
|
74
|
+
when :strict
|
75
|
+
messages << "configure_code_diagnostics(D::Ruby.strict) # :strict"
|
76
|
+
when :default
|
77
|
+
messages << "configure_code_diagnostics(D::Ruby.default) # :default"
|
78
|
+
when :lenient
|
79
|
+
messages << "configure_code_diagnostics(D::Ruby.lenient) # :lenient"
|
80
|
+
end
|
81
|
+
|
82
|
+
messages.each do |msg|
|
83
|
+
Steep.logger.error " #{msg}"
|
84
|
+
end
|
85
|
+
|
86
|
+
config = []
|
87
|
+
|
88
|
+
if hash[:allow_missing_definitions]
|
89
|
+
config << "hash[D::Ruby::MethodDefinitionMissing] = nil # allow_missing_definitions"
|
90
|
+
end
|
91
|
+
|
92
|
+
if hash[:allow_fallback_any]
|
93
|
+
config << "hash[D::Ruby::FallbackAny] = nil # allow_fallback_any"
|
94
|
+
end
|
95
|
+
|
96
|
+
if hash[:allow_unknown_constant_assignment]
|
97
|
+
config << "hash[D::Ruby::UnknownConstantAssigned] = nil # allow_unknown_constant_assignment"
|
98
|
+
end
|
99
|
+
|
100
|
+
if hash[:allow_unknown_method_calls]
|
101
|
+
config << "hash[D::Ruby::NoMethod] = nil # allow_unknown_method_calls"
|
102
|
+
end
|
103
|
+
|
104
|
+
unless config.empty?
|
105
|
+
Steep.logger.error " configure_code_diagnostics do |hash|"
|
106
|
+
config.each do |c|
|
107
|
+
Steep.logger.error " #{c}"
|
108
|
+
end
|
109
|
+
Steep.logger.error " end"
|
110
|
+
end
|
111
|
+
|
54
112
|
end
|
55
113
|
|
56
114
|
def signature(*args)
|
57
115
|
signatures.push(*args)
|
58
116
|
end
|
59
117
|
|
60
|
-
def update(name: self.name, sources: self.sources, libraries: self.libraries, ignored_sources: self.ignored_sources, signatures: self.signatures)
|
118
|
+
def update(name: self.name, sources: self.sources, libraries: self.libraries, ignored_sources: self.ignored_sources, signatures: self.signatures, project: self.project)
|
61
119
|
self.class.new(
|
62
120
|
name,
|
63
121
|
sources: sources,
|
64
122
|
libraries: libraries,
|
65
123
|
signatures: signatures,
|
66
|
-
ignored_sources: ignored_sources
|
124
|
+
ignored_sources: ignored_sources,
|
125
|
+
project: project,
|
67
126
|
)
|
68
127
|
end
|
69
128
|
|
70
129
|
def no_builtin!(value = true)
|
71
|
-
Steep.logger.error "
|
130
|
+
Steep.logger.error "`#no_builtin!` in Steepfile is deprecated and ignored. Use `#stdlib_path` instead."
|
72
131
|
end
|
73
132
|
|
74
133
|
def vendor(dir = "vendor/sigs", stdlib: nil, gems: nil)
|
75
|
-
|
76
|
-
|
77
|
-
end
|
134
|
+
Steep.logger.error "`#vendor` in Steepfile is deprecated and ignored. Use `#stdlib_path` instead."
|
135
|
+
end
|
78
136
|
|
79
|
-
|
137
|
+
def stdlib_path(core_root:, stdlib_root:)
|
138
|
+
@core_root = core_root ? Pathname(core_root) : core_root
|
139
|
+
@stdlib_root = stdlib_root ? Pathname(stdlib_root) : stdlib_root
|
80
140
|
end
|
81
141
|
|
82
142
|
def repo_path(*paths)
|
83
143
|
@repo_paths.push(*paths.map {|s| Pathname(s) })
|
84
144
|
end
|
145
|
+
|
146
|
+
# Configure the code diagnostics printing setup.
|
147
|
+
#
|
148
|
+
# Yields a hash, and the update the hash in the block.
|
149
|
+
#
|
150
|
+
# ```rb
|
151
|
+
# D = Steep::Diagnostic
|
152
|
+
#
|
153
|
+
# configure_code_diagnostics do |hash|
|
154
|
+
# # Assign one of :error, :warning, :information, :hint or :nil to error classes.
|
155
|
+
# hash[D::Ruby::UnexpectedPositionalArgument] = :error
|
156
|
+
# end
|
157
|
+
# ```
|
158
|
+
#
|
159
|
+
# Passing a hash is also allowed.
|
160
|
+
#
|
161
|
+
# ```rb
|
162
|
+
# D = Steep::Diagnostic
|
163
|
+
#
|
164
|
+
# configure_code_diagnostics(D::Ruby.lenient)
|
165
|
+
# ```
|
166
|
+
#
|
167
|
+
def configure_code_diagnostics(hash = nil)
|
168
|
+
if hash
|
169
|
+
code_diagnostics_config.merge!(hash)
|
170
|
+
end
|
171
|
+
|
172
|
+
yield code_diagnostics_config if block_given?
|
173
|
+
end
|
174
|
+
|
175
|
+
def collection_config(path)
|
176
|
+
@collection_config_path = project.absolute_path(path)
|
177
|
+
end
|
178
|
+
|
179
|
+
def disable_collection
|
180
|
+
@collection_config_path = nil
|
181
|
+
end
|
85
182
|
end
|
86
183
|
|
87
184
|
attr_reader :project
|
@@ -107,40 +204,42 @@ module Steep
|
|
107
204
|
end
|
108
205
|
|
109
206
|
def self.parse(project, code, filename: "Steepfile")
|
110
|
-
|
207
|
+
Steep.logger.tagged filename do
|
208
|
+
self.new(project: project).instance_eval(code, filename)
|
209
|
+
end
|
111
210
|
end
|
112
211
|
|
113
212
|
def target(name, template: nil, &block)
|
114
213
|
target = if template
|
115
|
-
self.class.templates[template]&.dup&.update(name: name) or
|
214
|
+
self.class.templates[template]&.dup&.update(name: name, project: project) or
|
116
215
|
raise "Unknown template: #{template}, available templates: #{@@templates.keys.join(", ")}"
|
117
216
|
else
|
118
|
-
TargetDSL.new(name)
|
217
|
+
TargetDSL.new(name, code_diagnostics_config: Diagnostic::Ruby.default.dup, project: project)
|
119
218
|
end
|
120
219
|
|
121
|
-
|
220
|
+
Steep.logger.tagged "target=#{name}" do
|
221
|
+
target.instance_eval(&block) if block_given?
|
222
|
+
end
|
122
223
|
|
123
224
|
source_pattern = Pattern.new(patterns: target.sources, ignores: target.ignored_sources, ext: ".rb")
|
124
225
|
signature_pattern = Pattern.new(patterns: target.signatures, ext: ".rbs")
|
125
226
|
|
227
|
+
collection_lock = target.collection_config_path&.then { |p| RBS::Collection::Config.lockfile_of(p) }
|
228
|
+
|
126
229
|
Project::Target.new(
|
127
230
|
name: target.name,
|
128
231
|
source_pattern: source_pattern,
|
129
232
|
signature_pattern: signature_pattern,
|
130
233
|
options: Options.new.tap do |options|
|
131
234
|
options.libraries.push(*target.libraries)
|
132
|
-
options.
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
options.merge!(target.typing_option_hash)
|
143
|
-
end
|
235
|
+
options.paths = Options::PathOptions.new(
|
236
|
+
core_root: target.core_root,
|
237
|
+
stdlib_root: target.stdlib_root,
|
238
|
+
repo_paths: target.repo_paths
|
239
|
+
)
|
240
|
+
options.collection_lock = collection_lock
|
241
|
+
end,
|
242
|
+
code_diagnostics_config: target.code_diagnostics_config
|
144
243
|
).tap do |target|
|
145
244
|
project.targets << target
|
146
245
|
end
|
@@ -1,63 +1,23 @@
|
|
1
1
|
module Steep
|
2
2
|
class Project
|
3
3
|
class Options
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :vendor_path
|
9
|
-
attr_reader :libraries
|
10
|
-
attr_reader :repository_paths
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
apply_default_typing_options!
|
14
|
-
self.vendor_path = nil
|
15
|
-
|
16
|
-
@libraries = []
|
17
|
-
@repository_paths = []
|
18
|
-
end
|
19
|
-
|
20
|
-
def apply_default_typing_options!
|
21
|
-
self.allow_fallback_any = true
|
22
|
-
self.allow_missing_definitions = true
|
23
|
-
self.allow_unknown_constant_assignment = false
|
24
|
-
self.allow_unknown_method_calls = false
|
25
|
-
end
|
26
|
-
|
27
|
-
def apply_strict_typing_options!
|
28
|
-
self.allow_fallback_any = false
|
29
|
-
self.allow_missing_definitions = false
|
30
|
-
self.allow_unknown_constant_assignment = false
|
31
|
-
self.allow_unknown_method_calls = false
|
32
|
-
end
|
33
|
-
|
34
|
-
def apply_lenient_typing_options!
|
35
|
-
self.allow_fallback_any = true
|
36
|
-
self.allow_missing_definitions = true
|
37
|
-
self.allow_unknown_constant_assignment = true
|
38
|
-
self.allow_unknown_method_calls = true
|
39
|
-
end
|
4
|
+
PathOptions = Struct.new(:core_root, :stdlib_root, :repo_paths, keyword_init: true) do
|
5
|
+
def customized_stdlib?
|
6
|
+
stdlib_root != nil
|
7
|
+
end
|
40
8
|
|
41
|
-
|
42
|
-
|
43
|
-
when error.is_a?(Diagnostic::Ruby::FallbackAny)
|
44
|
-
!allow_fallback_any
|
45
|
-
when error.is_a?(Diagnostic::Ruby::MethodDefinitionMissing)
|
46
|
-
!allow_missing_definitions
|
47
|
-
when error.is_a?(Diagnostic::Ruby::NoMethod)
|
48
|
-
!allow_unknown_method_calls
|
49
|
-
when error.is_a?(Diagnostic::Ruby::UnknownConstantAssigned)
|
50
|
-
!allow_unknown_constant_assignment
|
51
|
-
else
|
52
|
-
true
|
9
|
+
def customized_core?
|
10
|
+
core_root != nil
|
53
11
|
end
|
54
12
|
end
|
55
13
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
14
|
+
attr_reader :libraries
|
15
|
+
attr_accessor :paths
|
16
|
+
attr_accessor :collection_lock
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@paths = PathOptions.new(repo_paths: [])
|
20
|
+
@libraries = []
|
61
21
|
end
|
62
22
|
end
|
63
23
|
end
|
data/lib/steep/project/target.rb
CHANGED
@@ -6,12 +6,14 @@ module Steep
|
|
6
6
|
|
7
7
|
attr_reader :source_pattern
|
8
8
|
attr_reader :signature_pattern
|
9
|
+
attr_reader :code_diagnostics_config
|
9
10
|
|
10
|
-
def initialize(name:, options:, source_pattern:, signature_pattern:)
|
11
|
+
def initialize(name:, options:, source_pattern:, signature_pattern:, code_diagnostics_config:)
|
11
12
|
@name = name
|
12
13
|
@options = options
|
13
14
|
@source_pattern = source_pattern
|
14
15
|
@signature_pattern = signature_pattern
|
16
|
+
@code_diagnostics_config = code_diagnostics_config
|
15
17
|
|
16
18
|
@source_files = {}
|
17
19
|
@signature_files = {}
|
@@ -30,20 +32,32 @@ module Steep
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def self.construct_env_loader(options:, project:)
|
33
|
-
repo = RBS::Repository.new(no_stdlib: options.
|
34
|
-
|
35
|
+
repo = RBS::Repository.new(no_stdlib: options.paths.customized_stdlib?)
|
36
|
+
|
37
|
+
if options.paths.stdlib_root
|
38
|
+
repo.add(project.absolute_path(options.paths.stdlib_root))
|
39
|
+
end
|
40
|
+
|
41
|
+
options.paths.repo_paths.each do |path|
|
35
42
|
repo.add(project.absolute_path(path))
|
36
43
|
end
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
core_root_path =
|
46
|
+
if options.paths.customized_core?
|
47
|
+
if options.paths.core_root
|
48
|
+
project.absolute_path(options.paths.core_root)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
RBS::EnvironmentLoader::DEFAULT_CORE_ROOT
|
52
|
+
end
|
53
|
+
|
54
|
+
loader = RBS::EnvironmentLoader.new(core_root: core_root_path, repository: repo)
|
55
|
+
|
43
56
|
options.libraries.each do |lib|
|
44
57
|
name, version = lib.split(/:/, 2)
|
45
58
|
loader.add(library: name, version: version)
|
46
59
|
end
|
60
|
+
loader.add_collection(options.collection_lock) if options.collection_lock
|
47
61
|
|
48
62
|
loader
|
49
63
|
end
|