steep 1.0.2 → 1.1.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +5 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +22 -3
  5. data/Gemfile +6 -3
  6. data/Gemfile.lock +12 -16
  7. data/Gemfile.steep +3 -0
  8. data/Gemfile.steep.lock +49 -0
  9. data/Rakefile +5 -0
  10. data/Steepfile +6 -1
  11. data/bin/setup +2 -0
  12. data/bin/steep +19 -0
  13. data/lib/steep/ast/types/factory.rb +1 -1
  14. data/lib/steep/diagnostic/ruby.rb +49 -3
  15. data/lib/steep/diagnostic/signature.rb +18 -0
  16. data/lib/steep/drivers/watch.rb +3 -1
  17. data/lib/steep/method_name.rb +9 -3
  18. data/lib/steep/node_helper.rb +49 -0
  19. data/lib/steep/services/completion_provider.rb +22 -15
  20. data/lib/steep/services/hover_provider/ruby.rb +30 -12
  21. data/lib/steep/services/type_check_service.rb +12 -12
  22. data/lib/steep/shims/symbol_start_with.rb +18 -0
  23. data/lib/steep/signature/validator.rb +19 -0
  24. data/lib/steep/subtyping/constraints.rb +43 -14
  25. data/lib/steep/type_construction.rb +666 -746
  26. data/lib/steep/type_inference/constant_env.rb +0 -2
  27. data/lib/steep/type_inference/context.rb +23 -17
  28. data/lib/steep/type_inference/logic_type_interpreter.rb +210 -119
  29. data/lib/steep/type_inference/method_call.rb +80 -6
  30. data/lib/steep/type_inference/multiple_assignment.rb +189 -0
  31. data/lib/steep/type_inference/type_env.rb +271 -120
  32. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  33. data/lib/steep/typing.rb +2 -0
  34. data/lib/steep/version.rb +1 -1
  35. data/lib/steep.rb +4 -3
  36. data/rbs_collection.steep.lock.yaml +112 -0
  37. data/rbs_collection.steep.yaml +19 -0
  38. data/sample/sig/conference.rbs +8 -0
  39. data/sig/shims/parser/source/map.rbs +146 -0
  40. data/sig/shims/parser/source/range.rbs +237 -0
  41. data/sig/shims/parser.rbs +17 -0
  42. data/sig/steep/ast/annotation/collection.rbs +75 -0
  43. data/sig/steep/ast/annotation.rbs +126 -0
  44. data/sig/steep/ast/builtin.rbs +69 -0
  45. data/sig/steep/ast/type_params.rbs +11 -0
  46. data/sig/steep/ast/types/any.rbs +29 -0
  47. data/sig/steep/ast/types/boolean.rbs +31 -0
  48. data/sig/steep/ast/types/bot.rbs +29 -0
  49. data/sig/steep/ast/types/class.rbs +29 -0
  50. data/sig/steep/ast/types/factory.rbs +76 -0
  51. data/sig/steep/ast/types/helper.rbs +19 -0
  52. data/sig/steep/ast/types/instance.rbs +29 -0
  53. data/sig/steep/ast/types/intersection.rbs +35 -0
  54. data/sig/steep/ast/types/literal.rbs +33 -0
  55. data/sig/steep/ast/types/logic.rbs +78 -0
  56. data/sig/steep/ast/types/name.rbs +71 -0
  57. data/sig/steep/ast/types/nil.rbs +31 -0
  58. data/sig/steep/ast/types/proc.rbs +46 -0
  59. data/sig/steep/ast/types/record.rbs +38 -0
  60. data/sig/steep/ast/types/self.rbs +29 -0
  61. data/sig/steep/ast/types/top.rbs +29 -0
  62. data/sig/steep/ast/types/tuple.rbs +34 -0
  63. data/sig/steep/ast/types/union.rbs +38 -0
  64. data/sig/steep/ast/types/var.rbs +37 -0
  65. data/sig/steep/ast/types/void.rbs +29 -0
  66. data/sig/steep/ast/types.rbs +37 -0
  67. data/sig/steep/diagnostic/deprecated/unknown_constant_assigned.rbs +15 -0
  68. data/sig/steep/diagnostic/helper.rbs +9 -0
  69. data/sig/steep/diagnostic/lsp_formatter.rbs +29 -0
  70. data/sig/steep/diagnostic/ruby.rbs +494 -0
  71. data/sig/steep/diagnostic/signature.rbs +215 -0
  72. data/sig/steep/interface/block.rbs +35 -0
  73. data/sig/steep/interface/function.rbs +253 -0
  74. data/sig/steep/interface/interface.rbs +23 -0
  75. data/sig/steep/interface/method_type.rbs +55 -0
  76. data/sig/steep/interface/substitution.rbs +53 -0
  77. data/sig/steep/interface/type_param.rbs +35 -0
  78. data/sig/steep/method_name.rbs +26 -0
  79. data/sig/steep/module_helper.rbs +7 -0
  80. data/sig/steep/node_helper.rbs +11 -0
  81. data/sig/steep/project/dsl.rbs +94 -0
  82. data/sig/steep/project/options.rbs +15 -0
  83. data/sig/steep/project/pattern.rbs +25 -0
  84. data/sig/steep/project/target.rbs +25 -0
  85. data/sig/steep/project.rbs +19 -0
  86. data/sig/steep/services/completion_provider.rbs +123 -0
  87. data/sig/steep/services/content_change.rbs +35 -0
  88. data/sig/steep/services/file_loader.rbs +13 -0
  89. data/sig/steep/services/goto_service.rbs +45 -0
  90. data/sig/steep/services/hover_provider/rbs.rbs +21 -0
  91. data/sig/steep/services/hover_provider/ruby.rbs +109 -0
  92. data/sig/steep/services/hover_provider/singleton_methods.rbs +11 -0
  93. data/sig/steep/services/path_assignment.rbs +21 -0
  94. data/sig/steep/services/signature_service.rbs +91 -0
  95. data/sig/steep/services/stats_calculator.rbs +17 -0
  96. data/sig/steep/services/type_check_service.rbs +93 -0
  97. data/sig/steep/source.rbs +55 -0
  98. data/sig/steep/subtyping/cache.rbs +17 -0
  99. data/sig/steep/subtyping/check.rbs +93 -0
  100. data/sig/steep/subtyping/constraints.rbs +111 -0
  101. data/sig/steep/subtyping/relation.rbs +51 -0
  102. data/sig/steep/subtyping/result.rbs +157 -0
  103. data/sig/steep/subtyping/variable_variance.rbs +23 -0
  104. data/sig/steep/type_construction.rbs +285 -0
  105. data/sig/steep/type_inference/block_params.rbs +52 -0
  106. data/sig/steep/type_inference/constant_env.rbs +27 -0
  107. data/sig/steep/type_inference/context.rbs +137 -0
  108. data/sig/steep/type_inference/logic_type_interpreter.rbs +72 -0
  109. data/sig/steep/type_inference/method_call.rbs +124 -0
  110. data/sig/steep/type_inference/method_params.rbs +104 -0
  111. data/sig/steep/type_inference/multiple_assignment.rbs +76 -0
  112. data/sig/steep/type_inference/type_env.rbs +158 -0
  113. data/sig/steep/type_inference/type_env_builder.rbs +77 -0
  114. data/sig/steep/typing.rbs +68 -0
  115. data/sig/steep.rbs +31 -0
  116. data/smoke/class/f.rb +1 -0
  117. data/smoke/class/test_expectations.yml +2 -2
  118. data/smoke/diagnostics/test_expectations.yml +4 -2
  119. metadata +90 -6
  120. data/lib/steep/type_inference/local_variable_type_env.rb +0 -249
  121. data/lib/steep/type_inference/logic.rb +0 -161
@@ -0,0 +1,189 @@
1
+ module Steep
2
+ module TypeInference
3
+ class MultipleAssignment
4
+ Assignments = _ = Struct.new(:rhs_type, :optional, :leading_assignments, :trailing_assignments, :splat_assignment, keyword_init: true) do
5
+ # @implements Assignments
6
+
7
+ def each(&block)
8
+ if block
9
+ leading_assignments.each(&block)
10
+ if sp = splat_assignment
11
+ yield sp
12
+ end
13
+ trailing_assignments.each(&block)
14
+ else
15
+ enum_for :each
16
+ end
17
+ end
18
+ end
19
+
20
+ def expand(mlhs, rhs_type, optional)
21
+ lhss = mlhs.children
22
+
23
+ case rhs_type
24
+ when AST::Types::Tuple
25
+ expand_tuple(lhss.dup, rhs_type, rhs_type.types.dup, optional)
26
+ when AST::Types::Name::Instance
27
+ if AST::Builtin::Array.instance_type?(rhs_type)
28
+ expand_array(lhss.dup, rhs_type, optional)
29
+ end
30
+ when AST::Types::Any
31
+ expand_any(lhss, rhs_type, AST::Builtin.any_type, optional)
32
+ end
33
+ end
34
+
35
+ def expand_tuple(lhss, rhs_type, tuples, optional)
36
+ # @type var leading_assignments: Array[node_type_pair]
37
+ leading_assignments = []
38
+ # @type var trailing_assignments: Array[node_type_pair]
39
+ trailing_assignments = []
40
+ # @type var splat_assignment: node_type_pair?
41
+ splat_assignment = nil
42
+
43
+ while !lhss.empty?
44
+ first = lhss.first or raise
45
+
46
+ case
47
+ when first.type == :splat
48
+ break
49
+ else
50
+ leading_assignments << [first, tuples.first || AST::Builtin.nil_type]
51
+ lhss.shift
52
+ tuples.shift
53
+ end
54
+ end
55
+
56
+ while !lhss.empty?
57
+ last = lhss.last or raise
58
+
59
+ case
60
+ when last.type == :splat
61
+ break
62
+ else
63
+ trailing_assignments << [last, tuples.last || AST::Builtin.nil_type]
64
+ lhss.pop
65
+ tuples.pop
66
+ end
67
+ end
68
+
69
+ case lhss.size
70
+ when 0
71
+ # nop
72
+ when 1
73
+ splat_assignment = [lhss.first || raise, AST::Types::Tuple.new(types: tuples)]
74
+ else
75
+ raise
76
+ end
77
+
78
+ Assignments.new(
79
+ rhs_type: rhs_type,
80
+ optional: optional,
81
+ leading_assignments: leading_assignments,
82
+ trailing_assignments: trailing_assignments,
83
+ splat_assignment: splat_assignment
84
+ )
85
+ end
86
+
87
+ def expand_array(lhss, rhs_type, optional)
88
+ element_type = rhs_type.args[0] or raise
89
+
90
+ # @type var leading_assignments: Array[node_type_pair]
91
+ leading_assignments = []
92
+ # @type var trailing_assignments: Array[node_type_pair]
93
+ trailing_assignments = []
94
+ # @type var splat_assignment: node_type_pair?
95
+ splat_assignment = nil
96
+
97
+ while !lhss.empty?
98
+ first = lhss.first or raise
99
+
100
+ case
101
+ when first.type == :splat
102
+ break
103
+ else
104
+ leading_assignments << [first, AST::Builtin.optional(element_type)]
105
+ lhss.shift
106
+ end
107
+ end
108
+
109
+ while !lhss.empty?
110
+ last = lhss.last or raise
111
+
112
+ case
113
+ when last.type == :splat
114
+ break
115
+ else
116
+ trailing_assignments << [last, AST::Builtin.optional(element_type)]
117
+ lhss.pop
118
+ end
119
+ end
120
+
121
+ case lhss.size
122
+ when 0
123
+ # nop
124
+ when 1
125
+ splat_assignment = [
126
+ lhss.first || raise,
127
+ AST::Builtin::Array.instance_type(element_type)
128
+ ]
129
+ else
130
+ raise
131
+ end
132
+
133
+ Assignments.new(
134
+ rhs_type: rhs_type,
135
+ optional: optional,
136
+ leading_assignments: leading_assignments,
137
+ trailing_assignments: trailing_assignments,
138
+ splat_assignment: splat_assignment
139
+ )
140
+ end
141
+
142
+ def expand_any(nodes, rhs_type, element_type, optional)
143
+ # @type var leading_assignments: Array[node_type_pair]
144
+ leading_assignments = []
145
+ # @type var trailing_assignments: Array[node_type_pair]
146
+ trailing_assignments = []
147
+ # @type var splat_assignment: node_type_pair?
148
+ splat_assignment = nil
149
+
150
+ array = leading_assignments
151
+
152
+ nodes.each do |node|
153
+ case node.type
154
+ when :splat
155
+ splat_assignment = [node, AST::Builtin::Array.instance_type(element_type)]
156
+ array = trailing_assignments
157
+ else
158
+ array << [node, element_type]
159
+ end
160
+ end
161
+
162
+ Assignments.new(
163
+ rhs_type: rhs_type,
164
+ optional: optional,
165
+ leading_assignments: leading_assignments,
166
+ trailing_assignments: trailing_assignments,
167
+ splat_assignment: splat_assignment
168
+ )
169
+ end
170
+
171
+ def hint_for_mlhs(mlhs, env)
172
+ case mlhs.type
173
+ when :mlhs
174
+ types = mlhs.children.map do |node|
175
+ hint_for_mlhs(node, env) or return
176
+ end
177
+ AST::Types::Tuple.new(types: types)
178
+ when :lvasgn, :ivasgn, :gvasgn
179
+ name = mlhs.children[0]
180
+ env[name] || AST::Builtin.any_type
181
+ when :splat
182
+ return
183
+ else
184
+ return
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -1,169 +1,320 @@
1
1
  module Steep
2
2
  module TypeInference
3
3
  class TypeEnv
4
- attr_reader :subtyping
5
- attr_reader :const_types
6
- attr_reader :gvar_types
7
- attr_reader :ivar_types
8
- attr_reader :const_env
9
-
10
- def initialize(subtyping:, const_env:)
11
- @subtyping = subtyping
12
- @const_types = {}
13
- @gvar_types = {}
14
- @ivar_types = {}
15
- @const_env = const_env
16
- end
17
-
18
- def initialize_copy(other)
19
- @subtyping = other.subtyping
20
- @const_types = other.const_types.dup
21
- @gvar_types = other.gvar_types.dup
22
- @ivar_types = other.ivar_types.dup
23
- @const_env = other.const_env
24
- end
25
-
26
- def self.build(annotations:, signatures:, subtyping:, const_env:)
27
- new(subtyping: subtyping, const_env: const_env).tap do |env|
28
- annotations.ivar_types.each do |name, type|
29
- env.set(ivar: name, type: type)
30
- end
31
- annotations.const_types.each do |name, type|
32
- env.set(const: name, type: type)
33
- end
34
- signatures.global_decls.each do |name, entry|
35
- type = entry.decl.type
36
- env.set(gvar: name, type: subtyping.factory.type(type))
4
+ include NodeHelper
5
+
6
+ attr_reader :local_variable_types
7
+ attr_reader :instance_variable_types, :global_types, :constant_types
8
+ attr_reader :constant_env
9
+ attr_reader :pure_method_calls
10
+
11
+ def to_s
12
+ array = []
13
+
14
+ local_variable_types.each do |name, entry|
15
+ if enforced_type = entry[1]
16
+ array << "#{name}: #{entry[0].to_s} <#{enforced_type.to_s}>"
17
+ else
18
+ array << "#{name}: #{entry[0].to_s}"
37
19
  end
38
20
  end
39
- end
40
21
 
41
- def with_annotations(ivar_types: {}, const_types: {}, gvar_types: {}, self_type:, instance_type:, class_type:, &block)
42
- dup.tap do |env|
43
- merge!(original_env: env.ivar_types, override_env: ivar_types, self_type: self_type, instance_type: instance_type, class_type: class_type, &block)
44
- merge!(original_env: env.gvar_types, override_env: gvar_types, self_type: self_type, instance_type: instance_type, class_type: class_type, &block)
22
+ instance_variable_types.each do |name, type|
23
+ array << "#{name}: #{type.to_s}"
24
+ end
45
25
 
46
- const_types.each do |name, annotated_type|
47
- env.const_types[name] = annotated_type
48
- end
26
+ global_types.each do |name, type|
27
+ array << "#{name}: #{type.to_s}"
28
+ end
29
+
30
+ constant_types.each do |name, type|
31
+ array << "#{name}: #{type.to_s}"
49
32
  end
33
+
34
+ pure_method_calls.each do |node, pair|
35
+ call, type = pair
36
+ array << "`#{node.loc.expression.source.lines[0]}`: #{type || call.return_type}"
37
+ end
38
+
39
+ "{ #{array.join(", ")} }"
40
+ end
41
+
42
+ def initialize(constant_env, local_variable_types: {}, instance_variable_types: {}, global_types: {}, constant_types: {}, pure_method_calls: {})
43
+ @constant_env = constant_env
44
+ @local_variable_types = local_variable_types
45
+ @instance_variable_types = instance_variable_types
46
+ @global_types = global_types
47
+ @constant_types = constant_types
48
+ @pure_method_calls = pure_method_calls
49
+
50
+ @pure_node_descendants = {}
51
+ end
52
+
53
+ def update(local_variable_types: self.local_variable_types, instance_variable_types: self.instance_variable_types, global_types: self.global_types, constant_types: self.constant_types, pure_method_calls: self.pure_method_calls)
54
+ TypeEnv.new(
55
+ constant_env,
56
+ local_variable_types: local_variable_types,
57
+ instance_variable_types: instance_variable_types,
58
+ global_types: global_types,
59
+ constant_types: constant_types,
60
+ pure_method_calls: pure_method_calls
61
+ )
62
+ end
63
+
64
+ def merge(local_variable_types: {}, instance_variable_types: {}, global_types: {}, constant_types: {}, pure_method_calls: {})
65
+ local_variable_types = self.local_variable_types.merge(local_variable_types)
66
+ instance_variable_types = self.instance_variable_types.merge(instance_variable_types)
67
+ global_types = self.global_types.merge(global_types)
68
+ constant_types = self.constant_types.merge(constant_types)
69
+ pure_method_calls = self.pure_method_calls.merge(pure_method_calls)
70
+
71
+ TypeEnv.new(
72
+ constant_env,
73
+ local_variable_types: local_variable_types,
74
+ instance_variable_types: instance_variable_types,
75
+ global_types: global_types,
76
+ constant_types: constant_types,
77
+ pure_method_calls: pure_method_calls
78
+ )
50
79
  end
51
80
 
52
- # @type method assert: (const: TypeName) { () -> void } -> AST::Type
53
- # | (gvar: Symbol) { () -> void } -> AST::Type
54
- # | (ivar: Symbol) { () -> void } -> AST::Type
55
- def get(const: nil, gvar: nil, ivar: nil)
56
- case
57
- when const
58
- if const_types.key?(const)
59
- const_types[const]
81
+ def [](name)
82
+ case name
83
+ when Symbol
84
+ case
85
+ when local_variable_name?(name)
86
+ local_variable_types[name]&.[](0)
87
+ when instance_variable_name?(name)
88
+ instance_variable_types[name]
89
+ when global_name?(name)
90
+ global_types[name]
60
91
  else
61
- yield
62
- AST::Types::Any.new
92
+ raise "Unexpected variable name: #{name}"
63
93
  end
64
- else
65
- lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
66
- if dictionary.key?(var_name)
67
- dictionary[var_name]
68
- else
69
- yield
70
- AST::Types::Any.new
94
+ when Parser::AST::Node
95
+ case name.type
96
+ when :lvar
97
+ self[name.children[0]]
98
+ when :send
99
+ if (call, type = pure_method_calls[name])
100
+ type || call.return_type
71
101
  end
72
102
  end
73
103
  end
74
104
  end
75
105
 
76
- def merge_const_types(env)
77
- env.const_types.each do |name, type|
78
- const_types[name] = type unless const_types.key?(name)
106
+ def enforced_type(name)
107
+ local_variable_types[name]&.[](1)
108
+ end
109
+
110
+ def assign_local_variables(assignments)
111
+ local_variable_types = {}
112
+ invalidated_nodes = Set[]
113
+
114
+ assignments.each do |name, new_type|
115
+ local_variable_types[name] = [new_type, enforced_type(name)]
116
+ invalidated_nodes.merge(invalidated_pure_nodes(::Parser::AST::Node.new(:lvar, [name])))
79
117
  end
118
+
119
+ invalidation = pure_node_invalidation(invalidated_nodes)
120
+
121
+ merge(
122
+ local_variable_types: local_variable_types,
123
+ pure_method_calls: invalidation
124
+ )
80
125
  end
81
126
 
82
- def set(const: nil, gvar: nil, ivar: nil, type:)
83
- case
84
- when const
85
- const_types[const] = type
86
- else
87
- lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
88
- dictionary[var_name] = type
89
- end
127
+ def assign_local_variable(name, var_type, enforced_type)
128
+ merge(
129
+ local_variable_types: { name => [enforced_type || var_type, enforced_type] },
130
+ pure_method_calls: pure_node_invalidation(invalidated_pure_nodes(::Parser::AST::Node.new(:lvar, [name])))
131
+ )
132
+ end
133
+
134
+ def refine_types(local_variable_types: {}, pure_call_types: {})
135
+ local_variable_updates = {}
136
+
137
+ local_variable_types.each do |name, type|
138
+ local_variable_updates[name] = [type, enforced_type(name)]
139
+ end
140
+
141
+ invalidated_nodes = Set.new(pure_call_types.each_key)
142
+ local_variable_types.each_key do |name|
143
+ invalidated_nodes.merge(invalidated_pure_nodes(Parser::AST::Node.new(:lvar, [name])))
144
+ end
145
+
146
+ pure_call_updates = pure_node_invalidation(invalidated_nodes)
147
+
148
+ pure_call_types.each do |node, type|
149
+ call, _ = pure_call_updates[node]
150
+ pure_call_updates[node] = [call, type]
90
151
  end
152
+
153
+ merge(local_variable_types: local_variable_updates, pure_method_calls: pure_call_updates)
91
154
  end
92
155
 
93
- # @type method assign: (const: TypeName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
94
- # | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
95
- # | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
96
- def assign(gvar: nil, ivar: nil, type:, self_type:, instance_type:, class_type:, &block)
97
- lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
98
- if dictionary.key?(var_name)
99
- assert_assign(
100
- var_type: dictionary[var_name],
101
- lhs_type: type,
102
- self_type: self_type,
103
- instance_type: instance_type,
104
- class_type: class_type,
105
- &block
106
- )
156
+ def constant(arg1, arg2)
157
+ if arg1.is_a?(RBS::TypeName) && arg2.is_a?(Symbol)
158
+ constant_env.resolve_child(arg1, arg2)
159
+ elsif arg1.is_a?(Symbol)
160
+ if arg2
161
+ constant_env.toplevel(arg1)
107
162
  else
108
- yield nil
109
- AST::Types::Any.new
163
+ constant_env.resolve(arg1)
110
164
  end
111
165
  end
112
166
  end
113
167
 
114
- def lookup_dictionary(ivar:, gvar:)
115
- case
116
- when ivar
117
- yield ivar, ivar_types
118
- when gvar
119
- yield gvar, gvar_types
168
+ def annotated_constant(name)
169
+ constant_types[name]
170
+ end
171
+
172
+ def pin_local_variables(names)
173
+ names = Set.new(names) if names
174
+
175
+ local_variable_types.each.with_object({}) do |pair, hash|
176
+ name, entry = pair
177
+
178
+ if names.nil? || names.include?(name)
179
+ type, enforced_type = entry
180
+ unless enforced_type
181
+ hash[name] = [type, type]
182
+ end
183
+ end
120
184
  end
121
185
  end
122
186
 
123
- def assert_assign(var_type:, lhs_type:, self_type:, instance_type:, class_type:)
124
- return var_type if var_type == lhs_type
187
+ def unpin_local_variables(names)
188
+ names = Set.new(names) if names
125
189
 
126
- var_type = subtyping.expand_alias(var_type)
127
- lhs_type = subtyping.expand_alias(lhs_type)
190
+ local_var_types = local_variable_types.each.with_object({}) do |pair, hash|
191
+ name, entry = pair
192
+
193
+ if names.nil? || names.include?(name)
194
+ type, _ = entry
195
+ hash[name] = [type, nil]
196
+ end
197
+ end
128
198
 
129
- relation = Subtyping::Relation.new(sub_type: lhs_type, super_type: var_type)
130
- constraints = Subtyping::Constraints.new(unknowns: Set.new)
199
+ merge(local_variable_types: local_var_types)
200
+ end
201
+
202
+ def subst(s)
203
+ update(
204
+ local_variable_types: local_variable_types.transform_values do |entry|
205
+ # @type block: local_variable_entry
206
+
207
+ type, enforced_type = entry
208
+ [
209
+ type.subst(s),
210
+ enforced_type&.yield_self {|ty| ty.subst(s) }
211
+ ]
212
+ end
213
+ )
214
+ end
131
215
 
132
- subtyping.check(relation, self_type: self_type, constraints: constraints, instance_type: instance_type, class_type: class_type).else do |result|
133
- yield result
216
+ def join(*envs)
217
+ # @type var all_lvar_types: Hash[Symbol, Array[AST::Types::t]]
218
+ all_lvar_types = envs.each_with_object({}) do |env, hash|
219
+ env.local_variable_types.each_key do |name|
220
+ hash[name] = []
221
+ end
222
+ end
223
+
224
+ envs.each do |env|
225
+ all_lvar_types.each_key do |name|
226
+ all_lvar_types[name] << (env[name] || AST::Builtin.nil_type)
227
+ end
228
+ end
229
+
230
+ assignments =
231
+ all_lvar_types
232
+ .transform_values {|types| AST::Types::Union.build(types: types) }
233
+ .reject {|var, type| self[var] == type }
234
+
235
+ common_pure_nodes = envs
236
+ .map {|env| Set.new(env.pure_method_calls.each_key) }
237
+ .inject(Set.new(pure_method_calls.each_key)) {|s1, s2| s1.intersection(s2) }
238
+
239
+ pure_call_updates = common_pure_nodes.each_with_object({}) do |node, hash|
240
+ pairs = envs.map {|env| env.pure_method_calls[node] }
241
+ refined_type = AST::Types::Union.build(types: pairs.map {|pair| pair[1] || pair[0].return_type })
242
+ call, _ = (pure_method_calls[node] or raise)
243
+
244
+ hash[node] = [call, refined_type]
134
245
  end
135
246
 
136
- var_type
247
+ assign_local_variables(assignments).merge(pure_method_calls: pure_call_updates)
137
248
  end
138
249
 
139
- def merge!(original_env:, override_env:, self_type:, instance_type:, class_type:, &block)
140
- original_env.merge!(override_env) do |name, original_type, override_type|
141
- assert_annotation(
142
- name,
143
- annotated_type: override_type,
144
- original_type: original_type,
145
- self_type: self_type,
146
- instance_type: instance_type,
147
- class_type: class_type,
148
- &block
149
- )
250
+ def add_pure_call(node, call, type)
251
+ if (c, _ = pure_method_calls[node]) && c == call
252
+ return self
253
+ end
254
+
255
+ update =
256
+ pure_node_invalidation(invalidated_pure_nodes(node))
257
+ .merge!({ node => [call, type] })
258
+
259
+ merge(pure_method_calls: update)
260
+ end
261
+
262
+ def replace_pure_call_type(node, type)
263
+ if (call, _ = pure_method_calls[node])
264
+ calls = pure_method_calls.dup
265
+ calls[node] = [call, type]
266
+ update(pure_method_calls: calls)
267
+ else
268
+ raise
150
269
  end
151
270
  end
152
271
 
153
- def assert_annotation(name, annotated_type:, original_type:, self_type:, instance_type:, class_type:)
154
- return annotated_type if annotated_type == original_type
272
+ def invalidate_pure_node(node)
273
+ merge(pure_method_calls: pure_node_invalidation(invalidated_pure_nodes(node)))
274
+ end
275
+
276
+ def pure_node_invalidation(invalidated_nodes)
277
+ # @type var invalidation: Hash[Parser::AST::Node, [MethodCall::Typed, AST::Types::t?]]
278
+ invalidation = {}
279
+
280
+ invalidated_nodes.each do |node|
281
+ if (call, _ = pure_method_calls[node])
282
+ invalidation[node] = [call, nil]
283
+ end
284
+ end
155
285
 
156
- annotated_type = subtyping.expand_alias(annotated_type)
157
- original_type = subtyping.expand_alias(original_type)
286
+ invalidation
287
+ end
158
288
 
159
- relation = Subtyping::Relation.new(sub_type: annotated_type, super_type: original_type)
160
- constraints = Subtyping::Constraints.new(unknowns: Set.new)
289
+ def invalidated_pure_nodes(invalidated_node)
290
+ invalidated_nodes = Set[]
161
291
 
162
- subtyping.check(relation, constraints: constraints, self_type: self_type, instance_type: instance_type, class_type: class_type).else do |result|
163
- yield name, relation, result
292
+ pure_method_calls.each_key do |pure_node|
293
+ descendants = @pure_node_descendants[pure_node] ||= each_descendant_node(pure_node).to_set
294
+ if descendants.member?(invalidated_node)
295
+ invalidated_nodes << pure_node
296
+ end
164
297
  end
165
298
 
166
- annotated_type
299
+ invalidated_nodes
300
+ end
301
+
302
+ def local_variable_name?(name)
303
+ name.start_with?(/[a-z_]/)
304
+ end
305
+
306
+ def instance_variable_name?(name)
307
+ name.start_with?(/@[^@]/)
308
+ end
309
+
310
+ def global_name?(name)
311
+ name.start_with?('$')
312
+ end
313
+
314
+ def inspect
315
+ s = "#<%s:%#018x " % [self.class, object_id]
316
+ s << instance_variables.map(&:to_s).sort.map {|name| "#{name}=..." }.join(", ")
317
+ s + ">"
167
318
  end
168
319
  end
169
320
  end