steep 0.31.0 → 0.35.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 +25 -0
- data/lib/steep.rb +3 -2
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/types/factory.rb +66 -60
- data/lib/steep/cli.rb +15 -2
- data/lib/steep/drivers/print_project.rb +11 -0
- data/lib/steep/drivers/stats.rb +85 -0
- data/lib/steep/drivers/vendor.rb +1 -20
- 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 +24 -15
- data/lib/steep/project/dsl.rb +13 -17
- data/lib/steep/project/options.rb +4 -4
- data/lib/steep/project/source_file.rb +2 -1
- data/lib/steep/project/target.rb +19 -10
- data/lib/steep/server/interaction_worker.rb +1 -1
- data/lib/steep/server/utils.rb +1 -1
- data/lib/steep/source.rb +3 -3
- data/lib/steep/subtyping/check.rb +30 -16
- data/lib/steep/subtyping/variable_occurrence.rb +2 -0
- data/lib/steep/type_construction.rb +585 -416
- 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 +1 -1
- metadata +10 -6
- 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: 5ddd53798b724f6fd1a93d869b03a3864db04bed448552a75dadeabe8d1bc51e
|
4
|
+
data.tar.gz: c85f6c58a010ed11dfc1041f8ba98007e0f557d7bda133222b94915dfed0d6ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79a7742bdef0d368aa2dceaa528cf3e4bc74bccefafc0d6c366aa94994917e7d5560c8d4fd6f03adf0d50c3b8536d80d7e998bba3a9dc5cb872c7047c0079cba
|
7
|
+
data.tar.gz: 512b5bdf6efd6e465d5e3147de2df6cafb549fe68e05890efc13fffcc763b0cec1c48005a1734b6ade2cd120fa48059c435c20bad4b9998b1d15a0b4f557f615
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.35.0 (2020-11-14)
|
6
|
+
|
7
|
+
* Support third party RBS repository ([#231](https://github.com/soutaro/steep/pull/231), [#254](https://github.com/soutaro/steep/pull/254), [#255](https://github.com/soutaro/steep/pull/255))
|
8
|
+
* Boolean type semantics update ([#252](https://github.com/soutaro/steep/pull/252))
|
9
|
+
* More flexible record typing ([#256](https://github.com/soutaro/steep/pull/256))
|
10
|
+
|
11
|
+
## 0.34.0 (2020-10-27)
|
12
|
+
|
13
|
+
* Add `steep stats` command to show method call typing stats ([#246](https://github.com/soutaro/steep/pull/246))
|
14
|
+
* Fix attribute assignment typing ([#243](https://github.com/soutaro/steep/pull/243))
|
15
|
+
* Let `Range[T]` be covariant ([#242](https://github.com/soutaro/steep/pull/242))
|
16
|
+
* Fix constant typing ([#247](https://github.com/soutaro/steep/pull/247), [#248](https://github.com/soutaro/steep/pull/248))
|
17
|
+
|
18
|
+
## 0.33.0 (2020-10-13)
|
19
|
+
|
20
|
+
* Make `!` typing flow sensitive ([#240](https://github.com/soutaro/steep/pull/240))
|
21
|
+
|
22
|
+
## 0.32.0 (2020-10-09)
|
23
|
+
|
24
|
+
* Let type-case support interface types ([#237](https://github.com/soutaro/steep/pull/237))
|
25
|
+
|
26
|
+
## 0.31.1 (2020-10-07)
|
27
|
+
|
28
|
+
* Fix `if-then-else` parsing ([#236](https://github.com/soutaro/steep/pull/236))
|
29
|
+
|
5
30
|
## 0.31.0 (2020-10-04)
|
6
31
|
|
7
32
|
* Fix type checking performance ([#230](https://github.com/soutaro/steep/pull/230))
|
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,
|
@@ -149,6 +149,8 @@ module Steep
|
|
149
149
|
type: function_1(type.params, type.return_type),
|
150
150
|
location: nil
|
151
151
|
)
|
152
|
+
when Logic::Base
|
153
|
+
RBS::Types::Bases::Bool.new(location: nil)
|
152
154
|
else
|
153
155
|
raise "Unexpected type given: #{type} (#{type.class})"
|
154
156
|
end
|
@@ -178,7 +180,7 @@ module Steep
|
|
178
180
|
)
|
179
181
|
end
|
180
182
|
|
181
|
-
def method_type(method_type, self_type:, subst2: nil,
|
183
|
+
def method_type(method_type, self_type:, subst2: nil, method_decls:)
|
182
184
|
fvs = self_type.free_variables()
|
183
185
|
|
184
186
|
type_params = []
|
@@ -209,8 +211,7 @@ module Steep
|
|
209
211
|
return_type: type(block.type.return_type).subst(subst), location: nil)
|
210
212
|
)
|
211
213
|
end,
|
212
|
-
|
213
|
-
location: method_def&.member&.location
|
214
|
+
method_decls: method_decls
|
214
215
|
)
|
215
216
|
|
216
217
|
if block_given?
|
@@ -342,48 +343,46 @@ module Steep
|
|
342
343
|
end
|
343
344
|
end
|
344
345
|
|
345
|
-
|
346
|
-
if method_def = method_type.method_def
|
347
|
-
defined_in = method_def.defined_in
|
348
|
-
member = method_def.member
|
349
|
-
|
350
|
-
if member.is_a?(RBS::AST::Members::MethodDefinition)
|
351
|
-
case
|
352
|
-
when defined_in == RBS::BuiltinNames::Object.name && member.instance?
|
353
|
-
case method_name
|
354
|
-
when :is_a?, :kind_of?, :instance_of?
|
355
|
-
return method_type.with(
|
356
|
-
return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
|
357
|
-
)
|
358
|
-
when :nil?
|
359
|
-
return method_type.with(
|
360
|
-
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
361
|
-
)
|
362
|
-
end
|
346
|
+
NilClassName = TypeName("::NilClass")
|
363
347
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
return method_type.with(
|
368
|
-
return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
|
369
|
-
)
|
370
|
-
end
|
348
|
+
def setup_primitives(method_name, method_def, method_type)
|
349
|
+
defined_in = method_def.defined_in
|
350
|
+
member = method_def.member
|
371
351
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
)
|
378
|
-
|
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
|
379
360
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
)
|
386
|
-
|
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
|
+
)
|
387
386
|
end
|
388
387
|
end
|
389
388
|
end
|
@@ -409,7 +408,7 @@ module Steep
|
|
409
408
|
else
|
410
409
|
raise "Unexpected `self` type interface"
|
411
410
|
end
|
412
|
-
|
411
|
+
|
413
412
|
when Name::Instance
|
414
413
|
Interface::Interface.new(type: self_type, private: private).tap do |interface|
|
415
414
|
definition = definition_builder.build_instance(type.name)
|
@@ -433,10 +432,13 @@ module Steep
|
|
433
432
|
|
434
433
|
interface.methods[name] = Interface::Interface::Entry.new(
|
435
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)
|
436
437
|
setup_primitives(
|
437
438
|
name,
|
439
|
+
type_def,
|
438
440
|
method_type(type_def.type,
|
439
|
-
|
441
|
+
method_decls: Set[decl],
|
440
442
|
self_type: self_type,
|
441
443
|
subst2: subst)
|
442
444
|
)
|
@@ -460,7 +462,11 @@ module Steep
|
|
460
462
|
definition.methods.each do |name, method|
|
461
463
|
interface.methods[name] = Interface::Interface::Entry.new(
|
462
464
|
method_types: method.defs.map do |type_def|
|
463
|
-
|
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)
|
464
470
|
end
|
465
471
|
)
|
466
472
|
end
|
@@ -485,10 +491,16 @@ module Steep
|
|
485
491
|
|
486
492
|
interface.methods[name] = Interface::Interface::Entry.new(
|
487
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
|
+
)
|
488
499
|
setup_primitives(
|
489
500
|
name,
|
501
|
+
type_def,
|
490
502
|
method_type(type_def.type,
|
491
|
-
|
503
|
+
method_decls: Set[decl],
|
492
504
|
self_type: self_type,
|
493
505
|
subst2: subst)
|
494
506
|
)
|
@@ -568,8 +580,7 @@ module Steep
|
|
568
580
|
rest_keywords: nil),
|
569
581
|
block: nil,
|
570
582
|
return_type: elem_type,
|
571
|
-
|
572
|
-
location: nil
|
583
|
+
method_decls: Set[]
|
573
584
|
)
|
574
585
|
} + aref.method_types
|
575
586
|
)
|
@@ -588,8 +599,7 @@ module Steep
|
|
588
599
|
rest_keywords: nil),
|
589
600
|
block: nil,
|
590
601
|
return_type: elem_type,
|
591
|
-
|
592
|
-
location: nil
|
602
|
+
method_decls: Set[]
|
593
603
|
)
|
594
604
|
} + update.method_types
|
595
605
|
)
|
@@ -603,8 +613,7 @@ module Steep
|
|
603
613
|
params: Interface::Params.empty,
|
604
614
|
block: nil,
|
605
615
|
return_type: type.types[0] || AST::Builtin.nil_type,
|
606
|
-
|
607
|
-
location: nil
|
616
|
+
method_decls: Set[]
|
608
617
|
)
|
609
618
|
]
|
610
619
|
)
|
@@ -618,8 +627,7 @@ module Steep
|
|
618
627
|
params: Interface::Params.empty,
|
619
628
|
block: nil,
|
620
629
|
return_type: type.types.last || AST::Builtin.nil_type,
|
621
|
-
|
622
|
-
location: nil
|
630
|
+
method_decls: Set[]
|
623
631
|
)
|
624
632
|
]
|
625
633
|
)
|
@@ -640,6 +648,7 @@ module Steep
|
|
640
648
|
Interface::Interface::Entry.new(
|
641
649
|
method_types: type.elements.map {|key_value, value_type|
|
642
650
|
key_type = Literal.new(value: key_value, location: nil)
|
651
|
+
|
643
652
|
Interface::MethodType.new(
|
644
653
|
type_params: [],
|
645
654
|
params: Interface::Params.new(required: [key_type],
|
@@ -650,8 +659,7 @@ module Steep
|
|
650
659
|
rest_keywords: nil),
|
651
660
|
block: nil,
|
652
661
|
return_type: value_type,
|
653
|
-
|
654
|
-
location: nil
|
662
|
+
method_decls: Set[]
|
655
663
|
)
|
656
664
|
} + ref.method_types
|
657
665
|
)
|
@@ -671,8 +679,7 @@ module Steep
|
|
671
679
|
rest_keywords: nil),
|
672
680
|
block: nil,
|
673
681
|
return_type: value_type,
|
674
|
-
|
675
|
-
location: nil
|
682
|
+
method_decls: Set[]
|
676
683
|
)
|
677
684
|
} + update.method_types
|
678
685
|
)
|
@@ -687,8 +694,7 @@ module Steep
|
|
687
694
|
params: type.params,
|
688
695
|
return_type: type.return_type,
|
689
696
|
block: nil,
|
690
|
-
|
691
|
-
location: nil
|
697
|
+
method_decls: Set[]
|
692
698
|
)
|
693
699
|
|
694
700
|
interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type])
|
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, :
|
19
|
+
[:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :stats]
|
20
20
|
end
|
21
21
|
|
22
22
|
def process_global_options
|
@@ -34,7 +34,7 @@ module Steep
|
|
34
34
|
|
35
35
|
def setup_command
|
36
36
|
@command = argv.shift&.to_sym
|
37
|
-
if CLI.available_commands.include?(@command) || @command == :worker
|
37
|
+
if CLI.available_commands.include?(@command) || @command == :worker || @command == :vendor
|
38
38
|
true
|
39
39
|
else
|
40
40
|
stderr.puts "Unknown command: #{command}"
|
@@ -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|
|
@@ -47,6 +47,17 @@ module Steep
|
|
47
47
|
target.options.libraries.each do |lib|
|
48
48
|
stdout.puts " - #{lib}"
|
49
49
|
end
|
50
|
+
stdout.puts " library dirs:"
|
51
|
+
Project::Target.construct_env_loader(options: target.options).tap do |loader|
|
52
|
+
loader.each_dir do |lib, path|
|
53
|
+
case lib
|
54
|
+
when :core
|
55
|
+
stdout.puts " - core: #{path}"
|
56
|
+
else
|
57
|
+
stdout.puts " - #{lib.name}: #{path}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
50
61
|
end
|
51
62
|
|
52
63
|
0
|
@@ -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
|