steep 0.33.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 +7 -0
- data/lib/steep.rb +3 -0
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/types/factory.rb +63 -57
- 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 +24 -15
- data/lib/steep/project/source_file.rb +2 -1
- data/lib/steep/server/interaction_worker.rb +1 -1
- 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/local_variable_type_env.rb +10 -1
- 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/range.rb +5 -0
- data/steep.gemspec +1 -1
- metadata +8 -4
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,13 @@
|
|
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
|
+
|
5
12
|
## 0.33.0 (2020-10-13)
|
6
13
|
|
7
14
|
* Make `!` typing flow sensitive ([#240](https://github.com/soutaro/steep/pull/240))
|
data/lib/steep.rb
CHANGED
@@ -16,6 +16,7 @@ require 'uri'
|
|
16
16
|
|
17
17
|
require "rbs"
|
18
18
|
|
19
|
+
require "steep/method_name"
|
19
20
|
require "steep/ast/types/helper"
|
20
21
|
require "steep/ast/types/any"
|
21
22
|
require "steep/ast/types/instance"
|
@@ -70,6 +71,7 @@ require "steep/type_inference/type_env"
|
|
70
71
|
require "steep/type_inference/local_variable_type_env"
|
71
72
|
require "steep/type_inference/logic"
|
72
73
|
require "steep/type_inference/logic_type_interpreter"
|
74
|
+
require "steep/type_inference/method_call"
|
73
75
|
require "steep/ast/types"
|
74
76
|
|
75
77
|
require "steep/server/utils"
|
@@ -91,6 +93,7 @@ require "steep/project/hover_content"
|
|
91
93
|
require "steep/project/completion_provider"
|
92
94
|
require "steep/drivers/utils/driver_helper"
|
93
95
|
require "steep/drivers/check"
|
96
|
+
require "steep/drivers/stats"
|
94
97
|
require "steep/drivers/validate"
|
95
98
|
require "steep/drivers/annotations"
|
96
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?
|
@@ -344,46 +345,44 @@ module Steep
|
|
344
345
|
|
345
346
|
NilClassName = TypeName("::NilClass")
|
346
347
|
|
347
|
-
def setup_primitives(method_name, method_type)
|
348
|
-
|
349
|
-
|
350
|
-
member = method_def.member
|
351
|
-
|
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
|
348
|
+
def setup_primitives(method_name, method_def, method_type)
|
349
|
+
defined_in = method_def.defined_in
|
350
|
+
member = method_def.member
|
360
351
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
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
|
369
360
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
end
|
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
|
379
369
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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
|
@@ -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, :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
|
data/lib/steep/errors.rb
CHANGED
@@ -101,20 +101,6 @@ module Steep
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
class IncompatibleBlockParameters < Base
|
105
|
-
attr_reader :node
|
106
|
-
attr_reader :method_type
|
107
|
-
|
108
|
-
def initialize(node:, method_type:)
|
109
|
-
super(node: node)
|
110
|
-
@method_type = method_type
|
111
|
-
end
|
112
|
-
|
113
|
-
def to_s
|
114
|
-
"#{location_to_str}: IncompatibleBlockParameters: method_type=#{method_type}"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
104
|
class BlockParameterTypeMismatch < Base
|
119
105
|
attr_reader :expected
|
120
106
|
attr_reader :actual
|
@@ -186,7 +172,7 @@ module Steep
|
|
186
172
|
end
|
187
173
|
|
188
174
|
def to_s
|
189
|
-
"#{location_to_str}: RequiredBlockMissing: method_type=#{method_type.
|
175
|
+
"#{location_to_str}: RequiredBlockMissing: method_type=#{method_type.to_s}"
|
190
176
|
end
|
191
177
|
end
|
192
178
|
|
@@ -557,5 +543,23 @@ module Steep
|
|
557
543
|
"#{location_to_str}: UnsupportedSyntax: #{msg}"
|
558
544
|
end
|
559
545
|
end
|
546
|
+
|
547
|
+
class UnexpectedError < Base
|
548
|
+
attr_reader :message
|
549
|
+
attr_reader :error
|
550
|
+
|
551
|
+
def initialize(node:, error:)
|
552
|
+
super(node: node)
|
553
|
+
@error = error
|
554
|
+
@message = error.message
|
555
|
+
end
|
556
|
+
|
557
|
+
def to_s
|
558
|
+
<<-MESSAGE
|
559
|
+
#{location_to_str}: UnexpectedError: #{error.class}
|
560
|
+
>> #{message}
|
561
|
+
MESSAGE
|
562
|
+
end
|
563
|
+
end
|
560
564
|
end
|
561
565
|
end
|