steep 0.52.2 → 1.0.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/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
|