steep 0.52.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +3 -3
- data/lib/steep/ast/types/factory.rb +102 -3
- data/lib/steep/server/lsp_formatter.rb +12 -0
- data/lib/steep/source.rb +2 -2
- data/lib/steep/type_construction.rb +77 -3
- data/lib/steep/type_inference/method_call.rb +4 -1
- data/lib/steep/type_inference/method_params.rb +1 -0
- data/lib/steep/version.rb +1 -1
- data/smoke/compact/Steepfile +6 -0
- data/smoke/compact/a.rb +2 -0
- data/smoke/compact/a.rbs +5 -0
- data/smoke/compact/b.rb +2 -0
- data/smoke/compact/test_expectations.yml +18 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 899bca0fd211114d52e015acc844ee4648eadb6b739af911f7ac73560cedef83
|
4
|
+
data.tar.gz: 2fe5b52342a6b932d5ce08f5b78c417e43cda38db378c35d1b31891ca7c79465
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20e09462ddef35a3aa00a19d6f7cb86f2862c9ab700131bf439fc7750b088d43d1f2bb3380dfdf57a0c881d58c885b789d47eba35d7e146156809511e4e1c64c
|
7
|
+
data.tar.gz: dfa20a13b3b25575419ad1c9ac2417b1b873a0732eded5fa643e6e5768b644e27ea07c8d83bf9ae5e333b872d8f039aba111bee4d7ae2a48034dc06047265fee
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.0.0 (2022-05-20)
|
6
|
+
|
7
|
+
* Add special typing rule for `Array#compact` ([\#555](https://github.com/soutaro/steep/pull/555))
|
8
|
+
* Add custom method type of `#fetch` on tuples and records ([\#554](https://github.com/soutaro/steep/pull/554))
|
9
|
+
* Better `masgn` ([\#553](https://github.com/soutaro/steep/pull/553))
|
10
|
+
* Fix method parameter type checking ([\#552](https://github.com/soutaro/steep/pull/552))
|
11
|
+
|
5
12
|
## 0.52.2 (2022-05-02)
|
6
13
|
|
7
14
|
* Handle class declaration with non-const super class ([\#546](https://github.com/soutaro/steep/pull/546))
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
steep (0.
|
4
|
+
steep (1.0.0)
|
5
5
|
activesupport (>= 5.1)
|
6
6
|
language_server-protocol (>= 3.15, < 4.0)
|
7
7
|
listen (~> 3.0)
|
@@ -24,7 +24,7 @@ PATH
|
|
24
24
|
GEM
|
25
25
|
remote: https://rubygems.org/
|
26
26
|
specs:
|
27
|
-
activesupport (7.0.
|
27
|
+
activesupport (7.0.3)
|
28
28
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
29
29
|
i18n (>= 1.6, < 2)
|
30
30
|
minitest (>= 5.1)
|
@@ -51,7 +51,7 @@ GEM
|
|
51
51
|
rb-fsevent (0.11.1)
|
52
52
|
rb-inotify (0.10.1)
|
53
53
|
ffi (~> 1.0)
|
54
|
-
rbs (2.
|
54
|
+
rbs (2.4.0)
|
55
55
|
stackprof (0.2.19)
|
56
56
|
terminal-table (3.0.2)
|
57
57
|
unicode-display_width (>= 1.1.1, < 3)
|
@@ -674,6 +674,57 @@ module Steep
|
|
674
674
|
)
|
675
675
|
end
|
676
676
|
|
677
|
+
array_interface.methods[:fetch] = array_interface.methods[:fetch].yield_self do |fetch|
|
678
|
+
Interface::Interface::Entry.new(
|
679
|
+
method_types: type.types.flat_map.with_index {|elem_type, index|
|
680
|
+
[
|
681
|
+
Interface::MethodType.new(
|
682
|
+
type_params: [],
|
683
|
+
type: Interface::Function.new(
|
684
|
+
params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index)]),
|
685
|
+
return_type: elem_type,
|
686
|
+
location: nil
|
687
|
+
),
|
688
|
+
block: nil,
|
689
|
+
method_decls: Set[]
|
690
|
+
),
|
691
|
+
Interface::MethodType.new(
|
692
|
+
type_params: [Interface::TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)],
|
693
|
+
type: Interface::Function.new(
|
694
|
+
params: Interface::Function::Params.build(
|
695
|
+
required: [
|
696
|
+
AST::Types::Literal.new(value: index),
|
697
|
+
AST::Types::Var.new(name: :T)
|
698
|
+
]
|
699
|
+
),
|
700
|
+
return_type: AST::Types::Union.build(types: [elem_type, AST::Types::Var.new(name: :T)]),
|
701
|
+
location: nil
|
702
|
+
),
|
703
|
+
block: nil,
|
704
|
+
method_decls: Set[]
|
705
|
+
),
|
706
|
+
Interface::MethodType.new(
|
707
|
+
type_params: [Interface::TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)],
|
708
|
+
type: Interface::Function.new(
|
709
|
+
params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index)]),
|
710
|
+
return_type: AST::Types::Union.build(types: [elem_type, AST::Types::Var.new(name: :T)]),
|
711
|
+
location: nil
|
712
|
+
),
|
713
|
+
block: Interface::Block.new(
|
714
|
+
type: Interface::Function.new(
|
715
|
+
params: Interface::Function::Params.build(required: [AST::Builtin::Integer.instance_type]),
|
716
|
+
return_type: AST::Types::Var.new(name: :T),
|
717
|
+
location: nil
|
718
|
+
),
|
719
|
+
optional: false
|
720
|
+
),
|
721
|
+
method_decls: Set[]
|
722
|
+
)
|
723
|
+
]
|
724
|
+
} + fetch.method_types
|
725
|
+
)
|
726
|
+
end
|
727
|
+
|
677
728
|
array_interface.methods[:first] = array_interface.methods[:first].yield_self do |first|
|
678
729
|
Interface::Interface::Entry.new(
|
679
730
|
method_types: [
|
@@ -712,11 +763,11 @@ module Steep
|
|
712
763
|
|
713
764
|
when Record
|
714
765
|
yield_self do
|
715
|
-
|
766
|
+
all_key_type = type.elements.keys.map {|value| Literal.new(value: value, location: nil) }.yield_self do |types|
|
716
767
|
Union.build(types: types, location: nil)
|
717
768
|
end
|
718
|
-
|
719
|
-
hash_type = Builtin::Hash.instance_type(
|
769
|
+
all_value_type = Union.build(types: type.elements.values, location: nil)
|
770
|
+
hash_type = Builtin::Hash.instance_type(all_key_type, all_value_type)
|
720
771
|
|
721
772
|
interface(hash_type, private: private, self_type: self_type).tap do |hash_interface|
|
722
773
|
hash_interface.methods[:[]] = hash_interface.methods[:[]].yield_self do |ref|
|
@@ -768,6 +819,54 @@ module Steep
|
|
768
819
|
} + update.method_types
|
769
820
|
)
|
770
821
|
end
|
822
|
+
|
823
|
+
hash_interface.methods[:fetch] = hash_interface.methods[:fetch].yield_self do |update|
|
824
|
+
Interface::Interface::Entry.new(
|
825
|
+
method_types: type.elements.flat_map {|key_value, value_type|
|
826
|
+
key_type = Literal.new(value: key_value, location: nil)
|
827
|
+
|
828
|
+
[
|
829
|
+
Interface::MethodType.new(
|
830
|
+
type_params: [],
|
831
|
+
type: Interface::Function.new(
|
832
|
+
params: Interface::Function::Params.build(required: [key_type]),
|
833
|
+
return_type: value_type,
|
834
|
+
location: nil
|
835
|
+
),
|
836
|
+
block: nil,
|
837
|
+
method_decls: Set[]
|
838
|
+
),
|
839
|
+
Interface::MethodType.new(
|
840
|
+
type_params: [Interface::TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)],
|
841
|
+
type: Interface::Function.new(
|
842
|
+
params: Interface::Function::Params.build(required: [key_type, AST::Types::Var.new(name: :T)]),
|
843
|
+
return_type: AST::Types::Union.build(types: [value_type, AST::Types::Var.new(name: :T)]),
|
844
|
+
location: nil
|
845
|
+
),
|
846
|
+
block: nil,
|
847
|
+
method_decls: Set[]
|
848
|
+
),
|
849
|
+
Interface::MethodType.new(
|
850
|
+
type_params: [Interface::TypeParam.new(name: :T, upper_bound: nil, variance: :invariant, unchecked: false)],
|
851
|
+
type: Interface::Function.new(
|
852
|
+
params: Interface::Function::Params.build(required: [key_type]),
|
853
|
+
return_type: AST::Types::Union.build(types: [value_type, AST::Types::Var.new(name: :T)]),
|
854
|
+
location: nil
|
855
|
+
),
|
856
|
+
block: Interface::Block.new(
|
857
|
+
type: Interface::Function.new(
|
858
|
+
params: Interface::Function::Params.build(required: [all_key_type]),
|
859
|
+
return_type: AST::Types::Var.new(name: :T),
|
860
|
+
location: nil
|
861
|
+
),
|
862
|
+
optional: false
|
863
|
+
),
|
864
|
+
method_decls: Set[]
|
865
|
+
)
|
866
|
+
]
|
867
|
+
} + update.method_types
|
868
|
+
)
|
869
|
+
end
|
771
870
|
end
|
772
871
|
end
|
773
872
|
|
@@ -48,6 +48,18 @@ module Steep
|
|
48
48
|
call = content.method_call
|
49
49
|
builder.push do |s|
|
50
50
|
case call
|
51
|
+
when TypeInference::MethodCall::Special
|
52
|
+
mt = call.actual_method_type.with(
|
53
|
+
type: call.actual_method_type.type.with(return_type: call.return_type)
|
54
|
+
)
|
55
|
+
s << <<-EOM
|
56
|
+
**💡 Custom typing rule applies**
|
57
|
+
|
58
|
+
```rbs
|
59
|
+
#{mt.to_s}
|
60
|
+
```
|
61
|
+
|
62
|
+
EOM
|
51
63
|
when TypeInference::MethodCall::Typed
|
52
64
|
mt = call.actual_method_type.with(
|
53
65
|
type: call.actual_method_type.type.with(return_type: call.return_type)
|
data/lib/steep/source.rb
CHANGED
@@ -406,8 +406,8 @@ module Steep
|
|
406
406
|
Source.construct_mapping(node: node_, annotations: annotations, mapping: mapping)
|
407
407
|
|
408
408
|
annotations.each do |annot|
|
409
|
-
mapping[
|
410
|
-
mapping[
|
409
|
+
mapping[node_] ||= []
|
410
|
+
mapping[node_] << annot
|
411
411
|
end
|
412
412
|
|
413
413
|
Source.new(path: path, node: node_, mapping: mapping)
|
@@ -2662,11 +2662,13 @@ module Steep
|
|
2662
2662
|
when :ivasgn
|
2663
2663
|
_, constr = constr.ivasgn(assignment, element_type)
|
2664
2664
|
when :splat
|
2665
|
-
case assignment.children[0]
|
2665
|
+
case assignment.children[0]&.type
|
2666
2666
|
when :lvasgn
|
2667
2667
|
_, constr = constr.lvasgn(assignment.children[0], unwrap_rhs_type)
|
2668
2668
|
when :ivasgn
|
2669
2669
|
_, constr = constr.ivasgn(assignment.children[0], unwrap_rhs_type)
|
2670
|
+
when nil
|
2671
|
+
# foo, * = bar
|
2670
2672
|
else
|
2671
2673
|
raise
|
2672
2674
|
end
|
@@ -2684,7 +2686,31 @@ module Steep
|
|
2684
2686
|
unless rhs_type.is_a?(AST::Types::Any)
|
2685
2687
|
Steep.logger.error("Unsupported masgn rhs type: array or tuple is supported (#{rhs_type})")
|
2686
2688
|
end
|
2687
|
-
|
2689
|
+
|
2690
|
+
untyped = AST::Builtin.any_type
|
2691
|
+
|
2692
|
+
constr = lhs.children.inject(constr) do |constr, assignment|
|
2693
|
+
case assignment.type
|
2694
|
+
when :lvasgn
|
2695
|
+
_, constr = constr.lvasgn(assignment, untyped)
|
2696
|
+
when :ivasgn
|
2697
|
+
_, constr = constr.ivasgn(assignment, untyped)
|
2698
|
+
when :splat
|
2699
|
+
case assignment.children[0]&.type
|
2700
|
+
when :lvasgn
|
2701
|
+
_, constr = constr.lvasgn(assignment.children[0], untyped)
|
2702
|
+
when :ivasgn
|
2703
|
+
_, constr = constr.ivasgn(assignment.children[0], untyped)
|
2704
|
+
when nil
|
2705
|
+
# foo, * = bar
|
2706
|
+
else
|
2707
|
+
raise
|
2708
|
+
end
|
2709
|
+
end
|
2710
|
+
|
2711
|
+
constr
|
2712
|
+
end
|
2713
|
+
|
2688
2714
|
add_typing(node, type: rhs_type, constr: constr)
|
2689
2715
|
end
|
2690
2716
|
end
|
@@ -3114,13 +3140,61 @@ module Steep
|
|
3114
3140
|
end
|
3115
3141
|
end
|
3116
3142
|
|
3143
|
+
SPECIAL_METHOD_NAMES = {
|
3144
|
+
array_compact: Set[
|
3145
|
+
MethodName("::Array#compact"),
|
3146
|
+
MethodName("::Enumerable#compact")
|
3147
|
+
]
|
3148
|
+
}
|
3149
|
+
|
3150
|
+
def try_special_method(node, receiver_type:, method_name:, method_type:, arguments:, block_params:, block_body:)
|
3151
|
+
decls = method_type.method_decls
|
3152
|
+
|
3153
|
+
case
|
3154
|
+
when decl = decls.find {|decl| SPECIAL_METHOD_NAMES[:array_compact].include?(decl.method_name) }
|
3155
|
+
if arguments.empty? && !block_params
|
3156
|
+
# compact
|
3157
|
+
return_type = method_type.type.return_type
|
3158
|
+
if AST::Builtin::Array.instance_type?(return_type)
|
3159
|
+
elem = return_type.args[0]
|
3160
|
+
type = AST::Builtin::Array.instance_type(unwrap(elem))
|
3161
|
+
|
3162
|
+
_, constr = add_typing(node, type: type)
|
3163
|
+
call = TypeInference::MethodCall::Special.new(
|
3164
|
+
node: node,
|
3165
|
+
context: constr.context.method_context,
|
3166
|
+
method_name: decl.method_name,
|
3167
|
+
receiver_type: receiver_type,
|
3168
|
+
actual_method_type: method_type.with(type: method_type.type.with(return_type: type)),
|
3169
|
+
return_type: type,
|
3170
|
+
method_decls: decls
|
3171
|
+
)
|
3172
|
+
|
3173
|
+
return [call, constr]
|
3174
|
+
end
|
3175
|
+
end
|
3176
|
+
end
|
3177
|
+
|
3178
|
+
nil
|
3179
|
+
end
|
3180
|
+
|
3117
3181
|
def type_method_call(node, method_name:, receiver_type:, method:, arguments:, block_params:, block_body:, topdown_hint:)
|
3118
3182
|
node_range = node.loc.expression.yield_self {|l| l.begin_pos..l.end_pos }
|
3119
3183
|
|
3120
3184
|
results = method.method_types.map do |method_type|
|
3121
3185
|
Steep.logger.tagged method_type.to_s do
|
3122
3186
|
typing.new_child(node_range) do |child_typing|
|
3123
|
-
self.with_new_typing(child_typing)
|
3187
|
+
constr = self.with_new_typing(child_typing)
|
3188
|
+
|
3189
|
+
constr.try_special_method(
|
3190
|
+
node,
|
3191
|
+
receiver_type: receiver_type,
|
3192
|
+
method_name: method_name,
|
3193
|
+
method_type: method_type,
|
3194
|
+
arguments: arguments,
|
3195
|
+
block_params: block_params,
|
3196
|
+
block_body: block_body
|
3197
|
+
) || constr.try_method_type(
|
3124
3198
|
node,
|
3125
3199
|
receiver_type: receiver_type,
|
3126
3200
|
method_name: method_name,
|
@@ -79,13 +79,16 @@ module Steep
|
|
79
79
|
attr_reader :actual_method_type
|
80
80
|
attr_reader :method_decls
|
81
81
|
|
82
|
-
def initialize(node:, context:, method_name:, receiver_type:, actual_method_type:, method_decls:, return_type:
|
82
|
+
def initialize(node:, context:, method_name:, receiver_type:, actual_method_type:, method_decls:, return_type:)
|
83
83
|
super(node: node, context: context, method_name: method_name, receiver_type: receiver_type, return_type: return_type)
|
84
84
|
@actual_method_type = actual_method_type
|
85
85
|
@method_decls = method_decls
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
class Special < Typed
|
90
|
+
end
|
91
|
+
|
89
92
|
class Untyped < Base
|
90
93
|
def initialize(node:, context:, method_name:)
|
91
94
|
super(node: node, context: context, method_name: method_name, receiver_type: AST::Types::Any.new, return_type: AST::Types::Any.new)
|
data/lib/steep/version.rb
CHANGED
data/smoke/compact/a.rb
ADDED
data/smoke/compact/a.rbs
ADDED
data/smoke/compact/b.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
---
|
2
|
+
- file: b.rb
|
3
|
+
diagnostics:
|
4
|
+
- range:
|
5
|
+
start:
|
6
|
+
line: 2
|
7
|
+
character: 0
|
8
|
+
end:
|
9
|
+
line: 2
|
10
|
+
character: 28
|
11
|
+
severity: ERROR
|
12
|
+
message: |-
|
13
|
+
Cannot assign a value of type `::Array[(::String | bool | nil)]` to a variable of type `::Array[(::String | bool)]`
|
14
|
+
::Array[(::String | bool | nil)] <: ::Array[(::String | bool)]
|
15
|
+
(::String | bool | nil) <: (::String | bool)
|
16
|
+
nil <: (::String | bool)
|
17
|
+
nil <: ::String
|
18
|
+
code: Ruby::IncompatibleAssignment
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: steep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Soutaro Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -315,6 +315,11 @@ files:
|
|
315
315
|
- smoke/class/i.rb
|
316
316
|
- smoke/class/i.rbs
|
317
317
|
- smoke/class/test_expectations.yml
|
318
|
+
- smoke/compact/Steepfile
|
319
|
+
- smoke/compact/a.rb
|
320
|
+
- smoke/compact/a.rbs
|
321
|
+
- smoke/compact/b.rb
|
322
|
+
- smoke/compact/test_expectations.yml
|
318
323
|
- smoke/const/Steepfile
|
319
324
|
- smoke/const/a.rb
|
320
325
|
- smoke/const/b.rb
|