steep 1.8.0.dev.2 → 1.8.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/bin/mem_graph.rb +67 -0
- data/bin/mem_prof.rb +102 -0
- data/bin/stackprof_test.rb +19 -0
- data/bin/steep-check.rb +251 -0
- data/lib/steep/annotation_parser.rb +1 -1
- data/lib/steep/ast/builtin.rb +5 -5
- data/lib/steep/ast/node/type_application.rb +7 -6
- data/lib/steep/ast/types/any.rb +1 -9
- data/lib/steep/ast/types/boolean.rb +8 -16
- data/lib/steep/ast/types/bot.rb +2 -10
- data/lib/steep/ast/types/class.rb +1 -13
- data/lib/steep/ast/types/factory.rb +101 -85
- data/lib/steep/ast/types/instance.rb +1 -13
- data/lib/steep/ast/types/intersection.rb +8 -15
- data/lib/steep/ast/types/literal.rb +2 -8
- data/lib/steep/ast/types/logic.rb +3 -24
- data/lib/steep/ast/types/name.rb +5 -16
- data/lib/steep/ast/types/nil.rb +3 -12
- data/lib/steep/ast/types/proc.rb +4 -13
- data/lib/steep/ast/types/record.rb +21 -12
- data/lib/steep/ast/types/self.rb +1 -13
- data/lib/steep/ast/types/shared_instance.rb +11 -0
- data/lib/steep/ast/types/top.rb +1 -9
- data/lib/steep/ast/types/tuple.rb +4 -10
- data/lib/steep/ast/types/union.rb +10 -15
- data/lib/steep/ast/types/var.rb +4 -13
- data/lib/steep/ast/types/void.rb +2 -10
- data/lib/steep/diagnostic/ruby.rb +4 -4
- data/lib/steep/drivers/check.rb +11 -14
- data/lib/steep/drivers/checkfile.rb +8 -10
- data/lib/steep/drivers/stats.rb +17 -13
- data/lib/steep/drivers/utils/driver_helper.rb +24 -3
- data/lib/steep/drivers/watch.rb +3 -3
- data/lib/steep/interface/builder.rb +162 -138
- data/lib/steep/interface/method_type.rb +12 -20
- data/lib/steep/interface/shape.rb +66 -10
- data/lib/steep/interface/substitution.rb +2 -0
- data/lib/steep/interface/type_param.rb +20 -7
- data/lib/steep/located_value.rb +20 -0
- data/lib/steep/server/change_buffer.rb +5 -7
- data/lib/steep/server/custom_methods.rb +61 -0
- data/lib/steep/server/delay_queue.rb +8 -1
- data/lib/steep/server/interaction_worker.rb +10 -5
- data/lib/steep/server/lsp_formatter.rb +8 -6
- data/lib/steep/server/master.rb +193 -140
- data/lib/steep/server/type_check_worker.rb +18 -19
- data/lib/steep/server/work_done_progress.rb +64 -0
- data/lib/steep/services/completion_provider.rb +24 -22
- data/lib/steep/services/goto_service.rb +3 -2
- data/lib/steep/services/hover_provider/ruby.rb +7 -6
- data/lib/steep/services/signature_help_provider.rb +7 -6
- data/lib/steep/services/signature_service.rb +1 -1
- data/lib/steep/services/type_check_service.rb +3 -3
- data/lib/steep/signature/validator.rb +17 -20
- data/lib/steep/subtyping/check.rb +105 -55
- data/lib/steep/subtyping/constraints.rb +11 -15
- data/lib/steep/type_construction.rb +100 -100
- data/lib/steep/type_inference/block_params.rb +6 -6
- data/lib/steep/type_inference/logic_type_interpreter.rb +11 -7
- data/lib/steep/type_inference/method_call.rb +3 -3
- data/lib/steep/type_inference/method_params.rb +1 -1
- data/lib/steep/type_inference/send_args.rb +1 -1
- data/lib/steep/typing.rb +158 -102
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +28 -3
- data/steep.gemspec +2 -2
- metadata +16 -9
- data/lib/steep/type_inference/context_array.rb +0 -112
@@ -1,28 +1,83 @@
|
|
1
1
|
module Steep
|
2
2
|
module Interface
|
3
3
|
class Shape
|
4
|
+
class MethodOverload
|
5
|
+
attr_reader :method_type
|
6
|
+
|
7
|
+
attr_reader :method_defs
|
8
|
+
|
9
|
+
def initialize(method_type, defs)
|
10
|
+
@method_type = method_type
|
11
|
+
@method_defs = defs.sort_by do |defn|
|
12
|
+
buf = +""
|
13
|
+
|
14
|
+
if loc = defn.type.location
|
15
|
+
buf << loc.buffer.name.to_s
|
16
|
+
buf << ":"
|
17
|
+
buf << loc.start_pos.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
buf
|
21
|
+
end
|
22
|
+
@method_defs.uniq!
|
23
|
+
end
|
24
|
+
|
25
|
+
def subst(s)
|
26
|
+
overload = MethodOverload.new(method_type.subst(s), [])
|
27
|
+
overload.method_defs.replace(method_defs)
|
28
|
+
overload
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_decls(name)
|
32
|
+
method_defs.map do |defn|
|
33
|
+
type_name = defn.implemented_in || defn.defined_in
|
34
|
+
|
35
|
+
if name == :new && defn.member.is_a?(RBS::AST::Members::MethodDefinition) && defn.member.name == :initialize
|
36
|
+
method_name = SingletonMethodName.new(type_name: type_name, method_name: name)
|
37
|
+
else
|
38
|
+
method_name =
|
39
|
+
if defn.member.kind == :singleton
|
40
|
+
SingletonMethodName.new(type_name: defn.defined_in, method_name: name)
|
41
|
+
else
|
42
|
+
# Call the `self?` method an instance method, because the definition is done with instance method definition, not with singleton method
|
43
|
+
InstanceMethodName.new(type_name: defn.defined_in, method_name: name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
TypeInference::MethodCall::MethodDecl.new(method_def: defn, method_name: method_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
4
52
|
class Entry
|
5
|
-
|
6
|
-
|
53
|
+
attr_reader :method_name
|
54
|
+
|
55
|
+
def initialize(overloads: nil, private_method:, method_name:, &block)
|
56
|
+
@overloads = overloads
|
7
57
|
@generator = block
|
8
58
|
@private_method = private_method
|
59
|
+
@method_name = method_name
|
9
60
|
end
|
10
61
|
|
11
62
|
def force
|
12
|
-
unless @
|
13
|
-
@
|
63
|
+
unless @overloads
|
64
|
+
@overloads = @generator&.call
|
14
65
|
@generator = nil
|
15
66
|
end
|
16
67
|
end
|
17
68
|
|
18
|
-
def
|
69
|
+
def overloads
|
19
70
|
force
|
20
|
-
@
|
71
|
+
@overloads or raise
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_types
|
75
|
+
overloads.map(&:method_type)
|
21
76
|
end
|
22
77
|
|
23
78
|
def has_method_type?
|
24
79
|
force
|
25
|
-
@
|
80
|
+
@overloads ? true : false
|
26
81
|
end
|
27
82
|
|
28
83
|
def to_s
|
@@ -50,7 +105,7 @@ module Steep
|
|
50
105
|
def initialize(substs:, methods:)
|
51
106
|
@substs = substs
|
52
107
|
@methods = methods
|
53
|
-
@resolved_methods =
|
108
|
+
@resolved_methods = {}
|
54
109
|
end
|
55
110
|
|
56
111
|
def key?(name)
|
@@ -72,8 +127,9 @@ module Steep
|
|
72
127
|
resolved_methods[name] ||= begin
|
73
128
|
entry = methods[name]
|
74
129
|
Entry.new(
|
75
|
-
|
76
|
-
|
130
|
+
method_name: name,
|
131
|
+
overloads: entry.overloads.map do |overload|
|
132
|
+
overload.subst(subst)
|
77
133
|
end,
|
78
134
|
private_method: entry.private_method?
|
79
135
|
)
|
@@ -6,13 +6,15 @@ module Steep
|
|
6
6
|
attr_reader :variance
|
7
7
|
attr_reader :unchecked
|
8
8
|
attr_reader :location
|
9
|
+
attr_reader :default_type
|
9
10
|
|
10
|
-
def initialize(name:, upper_bound:, variance:, unchecked:, location: nil)
|
11
|
+
def initialize(name:, upper_bound:, variance:, unchecked:, location: nil, default_type:)
|
11
12
|
@name = name
|
12
13
|
@upper_bound = upper_bound
|
13
14
|
@variance = variance
|
14
15
|
@unchecked = unchecked
|
15
16
|
@location = location
|
17
|
+
@default_type = default_type
|
16
18
|
end
|
17
19
|
|
18
20
|
def ==(other)
|
@@ -20,13 +22,14 @@ module Steep
|
|
20
22
|
other.name == name &&
|
21
23
|
other.upper_bound == upper_bound &&
|
22
24
|
other.variance == variance &&
|
23
|
-
other.unchecked == unchecked
|
25
|
+
other.unchecked == unchecked &&
|
26
|
+
other.default_type == default_type
|
24
27
|
end
|
25
28
|
|
26
29
|
alias eql? ==
|
27
30
|
|
28
31
|
def hash
|
29
|
-
name.hash ^ upper_bound.hash ^ variance.hash ^ unchecked.hash
|
32
|
+
name.hash ^ upper_bound.hash ^ variance.hash ^ unchecked.hash ^ default_type.hash
|
30
33
|
end
|
31
34
|
|
32
35
|
def self.rename(params, conflicting_names = params.map(&:name), new_names = conflicting_names.map {|n| AST::Types::Var.fresh_name(n) })
|
@@ -44,7 +47,8 @@ module Steep
|
|
44
47
|
upper_bound: param.upper_bound&.subst(subst),
|
45
48
|
variance: param.variance,
|
46
49
|
unchecked: param.unchecked,
|
47
|
-
location: param.location
|
50
|
+
location: param.location,
|
51
|
+
default_type: param.default_type&.subst(subst)
|
48
52
|
)
|
49
53
|
else
|
50
54
|
param
|
@@ -80,19 +84,28 @@ module Steep
|
|
80
84
|
buf
|
81
85
|
end
|
82
86
|
|
83
|
-
def update(name: self.name, upper_bound: self.upper_bound, variance: self.variance, unchecked: self.unchecked, location: self.location)
|
87
|
+
def update(name: self.name, upper_bound: self.upper_bound, variance: self.variance, unchecked: self.unchecked, location: self.location, default_type: self.default_type)
|
84
88
|
TypeParam.new(
|
85
89
|
name: name,
|
86
90
|
upper_bound: upper_bound,
|
87
91
|
variance: variance,
|
88
92
|
unchecked: unchecked,
|
89
|
-
location: location
|
93
|
+
location: location,
|
94
|
+
default_type: default_type
|
90
95
|
)
|
91
96
|
end
|
92
97
|
|
93
98
|
def subst(s)
|
94
99
|
if u = upper_bound
|
95
|
-
|
100
|
+
ub = u.subst(s)
|
101
|
+
end
|
102
|
+
|
103
|
+
if d = default_type
|
104
|
+
dt = d.subst(s)
|
105
|
+
end
|
106
|
+
|
107
|
+
if ub || dt
|
108
|
+
update(upper_bound: ub, default_type: dt)
|
96
109
|
else
|
97
110
|
self
|
98
111
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Steep
|
2
|
+
class LocatedValue
|
3
|
+
attr_reader :value, :location
|
4
|
+
|
5
|
+
def initialize(value:, location:)
|
6
|
+
@value = value
|
7
|
+
@location = location
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
other.is_a?(LocatedValue) && other.value == value
|
12
|
+
end
|
13
|
+
|
14
|
+
alias eql? ==
|
15
|
+
|
16
|
+
def hash
|
17
|
+
value.hash # steep:ignore NoMethod
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -24,16 +24,14 @@ module Steep
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def load_files(
|
27
|
+
def load_files(input)
|
28
28
|
Steep.logger.tagged "#load_files" do
|
29
29
|
push_buffer do |changes|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
project.targets.each do |target|
|
34
|
-
loader.load_changes(target.source_pattern, commandline_args, changes: changes)
|
35
|
-
loader.load_changes(target.signature_pattern, changes: changes)
|
30
|
+
input.each do |filename, content|
|
31
|
+
if content.is_a?(Hash)
|
32
|
+
content = Base64.decode64(content[:text]).force_encoding(Encoding::UTF_8)
|
36
33
|
end
|
34
|
+
changes[Pathname(filename.to_s)] = [Services::ContentChange.new(text: content)]
|
37
35
|
end
|
38
36
|
end
|
39
37
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Steep
|
2
|
+
module Server
|
3
|
+
module CustomMethods
|
4
|
+
module FileLoad
|
5
|
+
METHOD = "$/steep/file/load"
|
6
|
+
|
7
|
+
def self.notification(params)
|
8
|
+
{ method: METHOD, params: params }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module FileReset
|
13
|
+
METHOD = "$/steep/file/reset"
|
14
|
+
|
15
|
+
def self.notification(params)
|
16
|
+
{ method: METHOD, params: params }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module TypeCheck
|
21
|
+
METHOD = "$/steep/typecheck"
|
22
|
+
|
23
|
+
def self.request(id, params)
|
24
|
+
{ method: METHOD, id: id, params: params }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.response(id, result)
|
28
|
+
{ id: id, result: result }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module TypeCheck__Start
|
33
|
+
METHOD = "$/steep/typecheck/start"
|
34
|
+
|
35
|
+
def self.notification(params)
|
36
|
+
{ method: METHOD, params: params }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module TypeCheck__Progress
|
41
|
+
METHOD = "$/steep/typecheck/progress"
|
42
|
+
|
43
|
+
def self.notification(params)
|
44
|
+
{ method: METHOD, params: params }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module Stats
|
49
|
+
METHOD = "$/steep/stats"
|
50
|
+
|
51
|
+
def self.request(id)
|
52
|
+
{ method: METHOD, id: id, params: nil }
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.response(id, result)
|
56
|
+
{ id: id, result: result }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -25,12 +25,19 @@ module Steep
|
|
25
25
|
end
|
26
26
|
|
27
27
|
if proc.equal?(last_task)
|
28
|
-
|
28
|
+
unless @cancelled
|
29
|
+
proc[]
|
30
|
+
end
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
36
|
+
def cancel
|
37
|
+
@cancelled = true
|
38
|
+
queue.clear()
|
39
|
+
end
|
40
|
+
|
34
41
|
def execute(&block)
|
35
42
|
@last_task = block
|
36
43
|
scheduled_at = Time.now + delay
|
@@ -82,17 +82,22 @@ module Steep
|
|
82
82
|
def handle_request(request)
|
83
83
|
case request[:method]
|
84
84
|
when "initialize"
|
85
|
-
load_files(project: project, commandline_args: [])
|
86
|
-
queue_job ApplyChangeJob.new
|
87
85
|
writer.write({ id: request[:id], result: nil })
|
88
86
|
|
89
87
|
when "textDocument/didChange"
|
90
88
|
collect_changes(request)
|
91
89
|
queue_job ApplyChangeJob.new
|
92
90
|
|
93
|
-
when
|
94
|
-
|
95
|
-
|
91
|
+
when CustomMethods::FileLoad::METHOD
|
92
|
+
params = request[:params] #: CustomMethods::FileLoad::params
|
93
|
+
input = params[:content]
|
94
|
+
load_files(input)
|
95
|
+
queue_job ApplyChangeJob.new
|
96
|
+
|
97
|
+
when CustomMethods::FileReset::METHOD
|
98
|
+
params = request[:params] #: CustomMethods::FileReset::params
|
99
|
+
uri = params[:uri]
|
100
|
+
text = params[:content]
|
96
101
|
reset_change(uri: uri, text: text)
|
97
102
|
queue_job ApplyChangeJob.new
|
98
103
|
|
@@ -36,7 +36,8 @@ module Steep
|
|
36
36
|
----
|
37
37
|
MD
|
38
38
|
|
39
|
-
|
39
|
+
method_decls = call.method_decls.sort_by {|decl| decl.method_name.to_s }
|
40
|
+
method_types = method_decls.map(&:method_type)
|
40
41
|
|
41
42
|
if call.is_a?(TypeInference::MethodCall::Special)
|
42
43
|
method_types = [
|
@@ -52,7 +53,8 @@ module Steep
|
|
52
53
|
MD
|
53
54
|
end
|
54
55
|
when TypeInference::MethodCall::Error
|
55
|
-
|
56
|
+
method_decls = call.method_decls.sort_by {|decl| decl.method_name.to_s }
|
57
|
+
method_types = method_decls.map {|decl| decl.method_type }
|
56
58
|
|
57
59
|
header = <<~MD
|
58
60
|
**🚨 No compatible method type found**
|
@@ -61,8 +63,8 @@ module Steep
|
|
61
63
|
MD
|
62
64
|
end
|
63
65
|
|
64
|
-
method_names =
|
65
|
-
docs =
|
66
|
+
method_names = method_decls.map {|decl| decl.method_name.relative }
|
67
|
+
docs = method_decls.map {|decl| [decl.method_name, decl.method_def.comment] }.to_h
|
66
68
|
|
67
69
|
if header
|
68
70
|
io.puts header
|
@@ -373,8 +375,8 @@ module Steep
|
|
373
375
|
end
|
374
376
|
s << param.name.to_s
|
375
377
|
|
376
|
-
if param.
|
377
|
-
s << " < #{param.
|
378
|
+
if param.upper_bound_type
|
379
|
+
s << " < #{param.upper_bound_type.to_s}"
|
378
380
|
end
|
379
381
|
|
380
382
|
s
|