steep 0.30.0 → 0.34.0
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 +26 -0
- data/bin/steep-prof +1 -2
- data/lib/steep.rb +3 -2
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/types/factory.rb +79 -60
- data/lib/steep/cli.rb +14 -1
- data/lib/steep/drivers/stats.rb +85 -0
- data/lib/steep/errors.rb +19 -15
- data/lib/steep/interface/method_type.rb +12 -23
- data/lib/steep/method_name.rb +28 -0
- data/lib/steep/project/completion_provider.rb +33 -22
- data/lib/steep/project/hover_content.rb +91 -80
- data/lib/steep/project/source_file.rb +2 -1
- data/lib/steep/server/interaction_worker.rb +43 -39
- data/lib/steep/server/utils.rb +1 -1
- data/lib/steep/source.rb +60 -3
- data/lib/steep/subtyping/variable_occurrence.rb +2 -0
- data/lib/steep/type_construction.rb +577 -415
- data/lib/steep/type_inference/context.rb +7 -3
- data/lib/steep/type_inference/context_array.rb +1 -1
- data/lib/steep/type_inference/local_variable_type_env.rb +10 -1
- data/lib/steep/type_inference/logic_type_interpreter.rb +6 -0
- data/lib/steep/type_inference/method_call.rb +116 -0
- data/lib/steep/typing.rb +38 -8
- data/lib/steep/version.rb +1 -1
- data/smoke/regression/fun.rb +8 -0
- data/smoke/regression/fun.rbs +4 -0
- data/smoke/regression/range.rb +5 -0
- data/steep.gemspec +2 -2
- metadata +12 -8
- data/lib/steep/ast/buffer.rb +0 -51
- data/lib/steep/ast/location.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ec77465913e4b2146e068c58f63b7ae8b5c51fd2391f6eb2776dba8372a81c2
|
4
|
+
data.tar.gz: 7528dbaf4873d9eb77728521837ecb0fe43a2010036572be2c3dc017c5b903cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0426373f8fb9e48ccec48d0676d70d5a674a389a83624df78dc3deacaba23840b02cc94becba92304de35f98c8d8bb3af12ef185161e4e6a6c37600cb61a82d
|
7
|
+
data.tar.gz: 5f3a32240541f116b6299c354fada0c8de398b6139b9d5e275e7b05490ccc401aa1b4f70978af5561e2ce9c6c7bb2587c1c8e43801276c0875000496ed332a5b
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,32 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.34.0 (2020-10-27)
|
6
|
+
|
7
|
+
* Add `steep stats` command to show method call typing stats ([#246](https://github.com/soutaro/steep/pull/246))
|
8
|
+
* Fix attribute assignment typing ([#243](https://github.com/soutaro/steep/pull/243))
|
9
|
+
* Let `Range[T]` be covariant ([#242](https://github.com/soutaro/steep/pull/242))
|
10
|
+
* Fix constant typing ([#247](https://github.com/soutaro/steep/pull/247), [#248](https://github.com/soutaro/steep/pull/248))
|
11
|
+
|
12
|
+
## 0.33.0 (2020-10-13)
|
13
|
+
|
14
|
+
* Make `!` typing flow sensitive ([#240](https://github.com/soutaro/steep/pull/240))
|
15
|
+
|
16
|
+
## 0.32.0 (2020-10-09)
|
17
|
+
|
18
|
+
* Let type-case support interface types ([#237](https://github.com/soutaro/steep/pull/237))
|
19
|
+
|
20
|
+
## 0.31.1 (2020-10-07)
|
21
|
+
|
22
|
+
* Fix `if-then-else` parsing ([#236](https://github.com/soutaro/steep/pull/236))
|
23
|
+
|
24
|
+
## 0.31.0 (2020-10-04)
|
25
|
+
|
26
|
+
* Fix type checking performance ([#230](https://github.com/soutaro/steep/pull/230))
|
27
|
+
* Improve LSP completion/hover performance ([#232](https://github.com/soutaro/steep/pull/232))
|
28
|
+
* Fix instance variable completion ([#234](https://github.com/soutaro/steep/pull/234))
|
29
|
+
* Relax version requirements on Listen to allow installing on Ruby 3 ([#235](https://github.com/soutaro/steep/pull/235))
|
30
|
+
|
5
31
|
## 0.30.0 (2020-10-03)
|
6
32
|
|
7
33
|
* Let top-level defs be methods of Object ([#227](https://github.com/soutaro/steep/pull/227))
|
data/bin/steep-prof
CHANGED
data/lib/steep.rb
CHANGED
@@ -16,7 +16,7 @@ require 'uri'
|
|
16
16
|
|
17
17
|
require "rbs"
|
18
18
|
|
19
|
-
require "steep/
|
19
|
+
require "steep/method_name"
|
20
20
|
require "steep/ast/types/helper"
|
21
21
|
require "steep/ast/types/any"
|
22
22
|
require "steep/ast/types/instance"
|
@@ -39,7 +39,6 @@ require "steep/ast/types/logic"
|
|
39
39
|
require "steep/ast/type_params"
|
40
40
|
require "steep/ast/annotation"
|
41
41
|
require "steep/ast/annotation/collection"
|
42
|
-
require "steep/ast/buffer"
|
43
42
|
require "steep/ast/builtin"
|
44
43
|
require "steep/ast/types/factory"
|
45
44
|
|
@@ -72,6 +71,7 @@ require "steep/type_inference/type_env"
|
|
72
71
|
require "steep/type_inference/local_variable_type_env"
|
73
72
|
require "steep/type_inference/logic"
|
74
73
|
require "steep/type_inference/logic_type_interpreter"
|
74
|
+
require "steep/type_inference/method_call"
|
75
75
|
require "steep/ast/types"
|
76
76
|
|
77
77
|
require "steep/server/utils"
|
@@ -93,6 +93,7 @@ require "steep/project/hover_content"
|
|
93
93
|
require "steep/project/completion_provider"
|
94
94
|
require "steep/drivers/utils/driver_helper"
|
95
95
|
require "steep/drivers/check"
|
96
|
+
require "steep/drivers/stats"
|
96
97
|
require "steep/drivers/validate"
|
97
98
|
require "steep/drivers/annotations"
|
98
99
|
require "steep/drivers/watch"
|
@@ -68,7 +68,7 @@ module Steep
|
|
68
68
|
name = match[:name]
|
69
69
|
type = match[:type]
|
70
70
|
|
71
|
-
method_type = factory.method_type(RBS::Parser.parse_method_type(type), self_type: AST::Types::Self.new)
|
71
|
+
method_type = factory.method_type(RBS::Parser.parse_method_type(type), self_type: AST::Types::Self.new, method_decls: Set[])
|
72
72
|
|
73
73
|
AST::Annotation::MethodType.new(name: name.to_sym,
|
74
74
|
type: method_type,
|
@@ -7,11 +7,14 @@ module Steep
|
|
7
7
|
attr_reader :type_name_cache
|
8
8
|
attr_reader :type_cache
|
9
9
|
|
10
|
+
attr_reader :type_interface_cache
|
11
|
+
|
10
12
|
def initialize(builder:)
|
11
13
|
@definition_builder = builder
|
12
14
|
|
13
15
|
@type_name_cache = {}
|
14
16
|
@type_cache = {}
|
17
|
+
@type_interface_cache = {}
|
15
18
|
end
|
16
19
|
|
17
20
|
def type_name_resolver
|
@@ -146,6 +149,8 @@ module Steep
|
|
146
149
|
type: function_1(type.params, type.return_type),
|
147
150
|
location: nil
|
148
151
|
)
|
152
|
+
when Logic::Base
|
153
|
+
RBS::Types::Bases::Bool.new(location: nil)
|
149
154
|
else
|
150
155
|
raise "Unexpected type given: #{type} (#{type.class})"
|
151
156
|
end
|
@@ -175,7 +180,7 @@ module Steep
|
|
175
180
|
)
|
176
181
|
end
|
177
182
|
|
178
|
-
def method_type(method_type, self_type:, subst2: nil,
|
183
|
+
def method_type(method_type, self_type:, subst2: nil, method_decls:)
|
179
184
|
fvs = self_type.free_variables()
|
180
185
|
|
181
186
|
type_params = []
|
@@ -206,8 +211,7 @@ module Steep
|
|
206
211
|
return_type: type(block.type.return_type).subst(subst), location: nil)
|
207
212
|
)
|
208
213
|
end,
|
209
|
-
|
210
|
-
location: method_def&.member&.location
|
214
|
+
method_decls: method_decls
|
211
215
|
)
|
212
216
|
|
213
217
|
if block_given?
|
@@ -339,48 +343,46 @@ module Steep
|
|
339
343
|
end
|
340
344
|
end
|
341
345
|
|
342
|
-
|
343
|
-
if method_def = method_type.method_def
|
344
|
-
defined_in = method_def.defined_in
|
345
|
-
member = method_def.member
|
346
|
-
|
347
|
-
if member.is_a?(RBS::AST::Members::MethodDefinition)
|
348
|
-
case
|
349
|
-
when defined_in == RBS::BuiltinNames::Object.name && member.instance?
|
350
|
-
case method_name
|
351
|
-
when :is_a?, :kind_of?, :instance_of?
|
352
|
-
return method_type.with(
|
353
|
-
return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
|
354
|
-
)
|
355
|
-
when :nil?
|
356
|
-
return method_type.with(
|
357
|
-
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
358
|
-
)
|
359
|
-
end
|
346
|
+
NilClassName = TypeName("::NilClass")
|
360
347
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
return method_type.with(
|
365
|
-
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
366
|
-
)
|
367
|
-
end
|
348
|
+
def setup_primitives(method_name, method_def, method_type)
|
349
|
+
defined_in = method_def.defined_in
|
350
|
+
member = method_def.member
|
368
351
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
)
|
375
|
-
|
352
|
+
if member.is_a?(RBS::AST::Members::MethodDefinition)
|
353
|
+
case method_name
|
354
|
+
when :is_a?, :kind_of?, :instance_of?
|
355
|
+
if defined_in == RBS::BuiltinNames::Object.name && member.instance?
|
356
|
+
return method_type.with(
|
357
|
+
return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
|
358
|
+
)
|
359
|
+
end
|
376
360
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
)
|
383
|
-
|
361
|
+
when :nil?
|
362
|
+
case defined_in
|
363
|
+
when RBS::BuiltinNames::Object.name,
|
364
|
+
NilClassName
|
365
|
+
return method_type.with(
|
366
|
+
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
367
|
+
)
|
368
|
+
end
|
369
|
+
|
370
|
+
when :!
|
371
|
+
case defined_in
|
372
|
+
when RBS::BuiltinNames::BasicObject.name,
|
373
|
+
RBS::BuiltinNames::TrueClass.name,
|
374
|
+
RBS::BuiltinNames::FalseClass.name
|
375
|
+
return method_type.with(
|
376
|
+
return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
|
377
|
+
)
|
378
|
+
end
|
379
|
+
|
380
|
+
when :===
|
381
|
+
case defined_in
|
382
|
+
when RBS::BuiltinNames::Module.name
|
383
|
+
return method_type.with(
|
384
|
+
return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
|
385
|
+
)
|
384
386
|
end
|
385
387
|
end
|
386
388
|
end
|
@@ -390,15 +392,23 @@ module Steep
|
|
390
392
|
|
391
393
|
def interface(type, private:, self_type: type)
|
392
394
|
Steep.logger.debug { "Factory#interface: #{type}, private=#{private}, self_type=#{self_type}" }
|
393
|
-
|
395
|
+
|
396
|
+
cache_key = [type, self_type, private]
|
397
|
+
if type_interface_cache.key?(cache_key)
|
398
|
+
return type_interface_cache[cache_key]
|
399
|
+
end
|
394
400
|
|
395
401
|
case type
|
402
|
+
when Name::Alias
|
403
|
+
interface(expand_alias(type), private: private, self_type: self_type)
|
404
|
+
|
396
405
|
when Self
|
397
406
|
if self_type != type
|
398
407
|
interface self_type, private: private, self_type: Self.new
|
399
408
|
else
|
400
409
|
raise "Unexpected `self` type interface"
|
401
410
|
end
|
411
|
+
|
402
412
|
when Name::Instance
|
403
413
|
Interface::Interface.new(type: self_type, private: private).tap do |interface|
|
404
414
|
definition = definition_builder.build_instance(type.name)
|
@@ -422,10 +432,13 @@ module Steep
|
|
422
432
|
|
423
433
|
interface.methods[name] = Interface::Interface::Entry.new(
|
424
434
|
method_types: method.defs.map do |type_def|
|
435
|
+
method_name = InstanceMethodName.new(type_name: type_def.implemented_in || type_def.defined_in, method_name: name)
|
436
|
+
decl = TypeInference::MethodCall::MethodDecl.new(method_name: method_name, method_def: type_def)
|
425
437
|
setup_primitives(
|
426
438
|
name,
|
439
|
+
type_def,
|
427
440
|
method_type(type_def.type,
|
428
|
-
|
441
|
+
method_decls: Set[decl],
|
429
442
|
self_type: self_type,
|
430
443
|
subst2: subst)
|
431
444
|
)
|
@@ -449,7 +462,11 @@ module Steep
|
|
449
462
|
definition.methods.each do |name, method|
|
450
463
|
interface.methods[name] = Interface::Interface::Entry.new(
|
451
464
|
method_types: method.defs.map do |type_def|
|
452
|
-
|
465
|
+
decls = Set[TypeInference::MethodCall::MethodDecl.new(
|
466
|
+
method_name: InstanceMethodName.new(type_name: type_def.implemented_in || type_def.defined_in, method_name: name),
|
467
|
+
method_def: type_def
|
468
|
+
)]
|
469
|
+
method_type(type_def.type, method_decls: decls, self_type: self_type, subst2: subst)
|
453
470
|
end
|
454
471
|
)
|
455
472
|
end
|
@@ -474,10 +491,16 @@ module Steep
|
|
474
491
|
|
475
492
|
interface.methods[name] = Interface::Interface::Entry.new(
|
476
493
|
method_types: method.defs.map do |type_def|
|
494
|
+
decl = TypeInference::MethodCall::MethodDecl.new(
|
495
|
+
method_name: SingletonMethodName.new(type_name: type_def.implemented_in || type_def.defined_in,
|
496
|
+
method_name: name),
|
497
|
+
method_def: type_def
|
498
|
+
)
|
477
499
|
setup_primitives(
|
478
500
|
name,
|
501
|
+
type_def,
|
479
502
|
method_type(type_def.type,
|
480
|
-
|
503
|
+
method_decls: Set[decl],
|
481
504
|
self_type: self_type,
|
482
505
|
subst2: subst)
|
483
506
|
)
|
@@ -557,8 +580,7 @@ module Steep
|
|
557
580
|
rest_keywords: nil),
|
558
581
|
block: nil,
|
559
582
|
return_type: elem_type,
|
560
|
-
|
561
|
-
location: nil
|
583
|
+
method_decls: Set[]
|
562
584
|
)
|
563
585
|
} + aref.method_types
|
564
586
|
)
|
@@ -577,8 +599,7 @@ module Steep
|
|
577
599
|
rest_keywords: nil),
|
578
600
|
block: nil,
|
579
601
|
return_type: elem_type,
|
580
|
-
|
581
|
-
location: nil
|
602
|
+
method_decls: Set[]
|
582
603
|
)
|
583
604
|
} + update.method_types
|
584
605
|
)
|
@@ -592,8 +613,7 @@ module Steep
|
|
592
613
|
params: Interface::Params.empty,
|
593
614
|
block: nil,
|
594
615
|
return_type: type.types[0] || AST::Builtin.nil_type,
|
595
|
-
|
596
|
-
location: nil
|
616
|
+
method_decls: Set[]
|
597
617
|
)
|
598
618
|
]
|
599
619
|
)
|
@@ -607,8 +627,7 @@ module Steep
|
|
607
627
|
params: Interface::Params.empty,
|
608
628
|
block: nil,
|
609
629
|
return_type: type.types.last || AST::Builtin.nil_type,
|
610
|
-
|
611
|
-
location: nil
|
630
|
+
method_decls: Set[]
|
612
631
|
)
|
613
632
|
]
|
614
633
|
)
|
@@ -629,6 +648,7 @@ module Steep
|
|
629
648
|
Interface::Interface::Entry.new(
|
630
649
|
method_types: type.elements.map {|key_value, value_type|
|
631
650
|
key_type = Literal.new(value: key_value, location: nil)
|
651
|
+
|
632
652
|
Interface::MethodType.new(
|
633
653
|
type_params: [],
|
634
654
|
params: Interface::Params.new(required: [key_type],
|
@@ -639,8 +659,7 @@ module Steep
|
|
639
659
|
rest_keywords: nil),
|
640
660
|
block: nil,
|
641
661
|
return_type: value_type,
|
642
|
-
|
643
|
-
location: nil
|
662
|
+
method_decls: Set[]
|
644
663
|
)
|
645
664
|
} + ref.method_types
|
646
665
|
)
|
@@ -660,8 +679,7 @@ module Steep
|
|
660
679
|
rest_keywords: nil),
|
661
680
|
block: nil,
|
662
681
|
return_type: value_type,
|
663
|
-
|
664
|
-
location: nil
|
682
|
+
method_decls: Set[]
|
665
683
|
)
|
666
684
|
} + update.method_types
|
667
685
|
)
|
@@ -676,8 +694,7 @@ module Steep
|
|
676
694
|
params: type.params,
|
677
695
|
return_type: type.return_type,
|
678
696
|
block: nil,
|
679
|
-
|
680
|
-
location: nil
|
697
|
+
method_decls: Set[]
|
681
698
|
)
|
682
699
|
|
683
700
|
interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type])
|
@@ -689,6 +706,8 @@ module Steep
|
|
689
706
|
|
690
707
|
else
|
691
708
|
raise "Unexpected type for interface: #{type}"
|
709
|
+
end.tap do |interface|
|
710
|
+
type_interface_cache[cache_key] = interface
|
692
711
|
end
|
693
712
|
end
|
694
713
|
|
data/lib/steep/cli.rb
CHANGED
@@ -16,7 +16,7 @@ module Steep
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.available_commands
|
19
|
-
[:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :vendor]
|
19
|
+
[:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :vendor, :stats]
|
20
20
|
end
|
21
21
|
|
22
22
|
def process_global_options
|
@@ -91,6 +91,19 @@ module Steep
|
|
91
91
|
end.run
|
92
92
|
end
|
93
93
|
|
94
|
+
def process_stats
|
95
|
+
Drivers::Stats.new(stdout: stdout, stderr: stderr).tap do |check|
|
96
|
+
OptionParser.new do |opts|
|
97
|
+
opts.banner = "Usage: steep stats [options] [sources]"
|
98
|
+
|
99
|
+
opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
|
100
|
+
handle_logging_options opts
|
101
|
+
end.parse!(argv)
|
102
|
+
|
103
|
+
check.command_line_patterns.push *argv
|
104
|
+
end.run
|
105
|
+
end
|
106
|
+
|
94
107
|
def process_validate
|
95
108
|
Drivers::Validate.new(stdout: stdout, stderr: stderr).tap do |command|
|
96
109
|
OptionParser.new do |opts|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
module Steep
|
4
|
+
module Drivers
|
5
|
+
class Stats
|
6
|
+
attr_reader :stdout
|
7
|
+
attr_reader :stderr
|
8
|
+
attr_reader :command_line_patterns
|
9
|
+
|
10
|
+
include Utils::DriverHelper
|
11
|
+
|
12
|
+
def initialize(stdout:, stderr:)
|
13
|
+
@stdout = stdout
|
14
|
+
@stderr = stderr
|
15
|
+
@command_line_patterns = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
project = load_config()
|
20
|
+
|
21
|
+
loader = Project::FileLoader.new(project: project)
|
22
|
+
loader.load_sources(command_line_patterns)
|
23
|
+
loader.load_signatures()
|
24
|
+
|
25
|
+
type_check(project)
|
26
|
+
|
27
|
+
stdout.puts(
|
28
|
+
CSV.generate do |csv|
|
29
|
+
csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
|
30
|
+
|
31
|
+
project.targets.each do |target|
|
32
|
+
case (status = target.status)
|
33
|
+
when Project::Target::TypeCheckStatus
|
34
|
+
status.type_check_sources.each do |source_file|
|
35
|
+
case source_file.status
|
36
|
+
when Project::SourceFile::TypeCheckStatus
|
37
|
+
typing = source_file.status.typing
|
38
|
+
|
39
|
+
typed = 0
|
40
|
+
untyped = 0
|
41
|
+
total = 0
|
42
|
+
typing.method_calls.each_value do |call|
|
43
|
+
case call
|
44
|
+
when TypeInference::MethodCall::Typed
|
45
|
+
typed += 1
|
46
|
+
when TypeInference::MethodCall::Untyped
|
47
|
+
untyped += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
total += 1
|
51
|
+
end
|
52
|
+
|
53
|
+
csv << format_stats(target, source_file.path, "success", typed, untyped, total)
|
54
|
+
when Project::SourceFile::TypeCheckErrorStatus
|
55
|
+
csv << format_stats(target, source_file.path, "error", 0, 0, 0)
|
56
|
+
else
|
57
|
+
csv << format_stats(target, source_file.path, "unknown (#{source_file.status.class.to_s.split(/::/).last})", 0, 0, 0)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
)
|
64
|
+
|
65
|
+
0
|
66
|
+
end
|
67
|
+
|
68
|
+
def format_stats(target, path, status, typed, untyped, total)
|
69
|
+
[
|
70
|
+
target.name,
|
71
|
+
path.to_s,
|
72
|
+
status,
|
73
|
+
typed,
|
74
|
+
untyped,
|
75
|
+
total,
|
76
|
+
if total.nonzero?
|
77
|
+
format("%.2f", (typed.to_f/total)*100)
|
78
|
+
else
|
79
|
+
0
|
80
|
+
end
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|