steep 1.0.0 → 1.1.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-windows.yml +34 -0
  3. data/.github/workflows/ruby.yml +7 -2
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +59 -0
  6. data/Gemfile +7 -4
  7. data/Gemfile.lock +17 -21
  8. data/Gemfile.steep +3 -0
  9. data/Gemfile.steep.lock +49 -0
  10. data/Rakefile +5 -0
  11. data/Steepfile +6 -1
  12. data/bin/setup +2 -0
  13. data/bin/steep +19 -0
  14. data/lib/steep/ast/builtin.rb +2 -2
  15. data/lib/steep/ast/types/factory.rb +7 -3
  16. data/lib/steep/ast/types/proc.rb +2 -0
  17. data/lib/steep/cli.rb +3 -1
  18. data/lib/steep/diagnostic/ruby.rb +50 -4
  19. data/lib/steep/diagnostic/signature.rb +18 -0
  20. data/lib/steep/drivers/check.rb +3 -3
  21. data/lib/steep/drivers/watch.rb +3 -1
  22. data/lib/steep/method_name.rb +9 -3
  23. data/lib/steep/node_helper.rb +49 -0
  24. data/lib/steep/path_helper.rb +22 -0
  25. data/lib/steep/project.rb +3 -15
  26. data/lib/steep/server/base_worker.rb +1 -0
  27. data/lib/steep/server/change_buffer.rb +1 -1
  28. data/lib/steep/server/interaction_worker.rb +3 -5
  29. data/lib/steep/server/master.rb +61 -45
  30. data/lib/steep/server/type_check_worker.rb +10 -25
  31. data/lib/steep/services/completion_provider.rb +25 -18
  32. data/lib/steep/services/goto_service.rb +2 -4
  33. data/lib/steep/services/hover_provider/rbs.rb +1 -1
  34. data/lib/steep/services/hover_provider/ruby.rb +30 -12
  35. data/lib/steep/services/stats_calculator.rb +0 -1
  36. data/lib/steep/services/type_check_service.rb +15 -12
  37. data/lib/steep/shims/symbol_start_with.rb +18 -0
  38. data/lib/steep/signature/validator.rb +25 -1
  39. data/lib/steep/source.rb +1 -1
  40. data/lib/steep/subtyping/check.rb +0 -3
  41. data/lib/steep/subtyping/constraints.rb +43 -14
  42. data/lib/steep/type_construction.rb +721 -764
  43. data/lib/steep/type_inference/constant_env.rb +0 -2
  44. data/lib/steep/type_inference/context.rb +23 -17
  45. data/lib/steep/type_inference/logic_type_interpreter.rb +210 -117
  46. data/lib/steep/type_inference/method_call.rb +80 -6
  47. data/lib/steep/type_inference/multiple_assignment.rb +189 -0
  48. data/lib/steep/type_inference/send_args.rb +1 -2
  49. data/lib/steep/type_inference/type_env.rb +273 -116
  50. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  51. data/lib/steep/typing.rb +2 -0
  52. data/lib/steep/version.rb +1 -1
  53. data/lib/steep.rb +7 -5
  54. data/rbs_collection.steep.lock.yaml +112 -0
  55. data/rbs_collection.steep.yaml +19 -0
  56. data/sample/sig/conference.rbs +8 -0
  57. data/sig/shims/parser/source/map.rbs +146 -0
  58. data/sig/shims/parser/source/range.rbs +237 -0
  59. data/sig/shims/parser.rbs +17 -0
  60. data/sig/steep/ast/annotation/collection.rbs +75 -0
  61. data/sig/steep/ast/annotation.rbs +126 -0
  62. data/sig/steep/ast/builtin.rbs +69 -0
  63. data/sig/steep/ast/type_params.rbs +11 -0
  64. data/sig/steep/ast/types/any.rbs +29 -0
  65. data/sig/steep/ast/types/boolean.rbs +31 -0
  66. data/sig/steep/ast/types/bot.rbs +29 -0
  67. data/sig/steep/ast/types/class.rbs +29 -0
  68. data/sig/steep/ast/types/factory.rbs +76 -0
  69. data/sig/steep/ast/types/helper.rbs +19 -0
  70. data/sig/steep/ast/types/instance.rbs +29 -0
  71. data/sig/steep/ast/types/intersection.rbs +35 -0
  72. data/sig/steep/ast/types/literal.rbs +33 -0
  73. data/sig/steep/ast/types/logic.rbs +78 -0
  74. data/sig/steep/ast/types/name.rbs +71 -0
  75. data/sig/steep/ast/types/nil.rbs +31 -0
  76. data/sig/steep/ast/types/proc.rbs +46 -0
  77. data/sig/steep/ast/types/record.rbs +38 -0
  78. data/sig/steep/ast/types/self.rbs +29 -0
  79. data/sig/steep/ast/types/top.rbs +29 -0
  80. data/sig/steep/ast/types/tuple.rbs +34 -0
  81. data/sig/steep/ast/types/union.rbs +38 -0
  82. data/sig/steep/ast/types/var.rbs +37 -0
  83. data/sig/steep/ast/types/void.rbs +29 -0
  84. data/sig/steep/ast/types.rbs +37 -0
  85. data/sig/steep/diagnostic/deprecated/unknown_constant_assigned.rbs +15 -0
  86. data/sig/steep/diagnostic/helper.rbs +9 -0
  87. data/sig/steep/diagnostic/lsp_formatter.rbs +29 -0
  88. data/sig/steep/diagnostic/ruby.rbs +494 -0
  89. data/sig/steep/diagnostic/signature.rbs +215 -0
  90. data/sig/steep/interface/block.rbs +35 -0
  91. data/sig/steep/interface/function.rbs +253 -0
  92. data/sig/steep/interface/interface.rbs +23 -0
  93. data/sig/steep/interface/method_type.rbs +55 -0
  94. data/sig/steep/interface/substitution.rbs +53 -0
  95. data/sig/steep/interface/type_param.rbs +35 -0
  96. data/sig/steep/method_name.rbs +26 -0
  97. data/sig/steep/module_helper.rbs +7 -0
  98. data/sig/steep/node_helper.rbs +11 -0
  99. data/sig/steep/project/dsl.rbs +94 -0
  100. data/sig/steep/project/options.rbs +15 -0
  101. data/sig/steep/project/pattern.rbs +25 -0
  102. data/sig/steep/project/target.rbs +25 -0
  103. data/sig/steep/project.rbs +19 -0
  104. data/sig/steep/services/completion_provider.rbs +123 -0
  105. data/sig/steep/services/content_change.rbs +35 -0
  106. data/sig/steep/services/file_loader.rbs +13 -0
  107. data/sig/steep/services/goto_service.rbs +45 -0
  108. data/sig/steep/services/hover_provider/rbs.rbs +21 -0
  109. data/sig/steep/services/hover_provider/ruby.rbs +109 -0
  110. data/sig/steep/services/hover_provider/singleton_methods.rbs +11 -0
  111. data/sig/steep/services/path_assignment.rbs +21 -0
  112. data/sig/steep/services/signature_service.rbs +91 -0
  113. data/sig/steep/services/stats_calculator.rbs +17 -0
  114. data/sig/steep/services/type_check_service.rbs +93 -0
  115. data/sig/steep/source.rbs +55 -0
  116. data/sig/steep/subtyping/cache.rbs +17 -0
  117. data/sig/steep/subtyping/check.rbs +93 -0
  118. data/sig/steep/subtyping/constraints.rbs +111 -0
  119. data/sig/steep/subtyping/relation.rbs +51 -0
  120. data/sig/steep/subtyping/result.rbs +157 -0
  121. data/sig/steep/subtyping/variable_variance.rbs +23 -0
  122. data/sig/steep/type_construction.rbs +285 -0
  123. data/sig/steep/type_inference/block_params.rbs +52 -0
  124. data/sig/steep/type_inference/constant_env.rbs +27 -0
  125. data/sig/steep/type_inference/context.rbs +137 -0
  126. data/sig/steep/type_inference/logic_type_interpreter.rbs +72 -0
  127. data/sig/steep/type_inference/method_call.rbs +124 -0
  128. data/sig/steep/type_inference/method_params.rbs +104 -0
  129. data/sig/steep/type_inference/multiple_assignment.rbs +76 -0
  130. data/sig/steep/type_inference/type_env.rbs +158 -0
  131. data/sig/steep/type_inference/type_env_builder.rbs +77 -0
  132. data/sig/steep/typing.rbs +68 -0
  133. data/sig/steep.rbs +31 -0
  134. data/smoke/class/f.rb +1 -0
  135. data/smoke/class/test_expectations.yml +2 -2
  136. data/smoke/diagnostics/test_expectations.yml +4 -2
  137. data/smoke/regression/lambda.rb +3 -0
  138. data/smoke/regression/test_expectations.yml +12 -0
  139. data/steep.gemspec +1 -1
  140. metadata +95 -9
  141. data/lib/steep/subtyping/variable_occurrence.rb +0 -51
  142. data/lib/steep/type_inference/local_variable_type_env.rb +0 -249
  143. 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
@@ -528,7 +528,6 @@ module Steep
528
528
  def each
529
529
  if block_given?
530
530
  errors = []
531
- positional_count = 0
532
531
 
533
532
  positional_arg.tap do |args|
534
533
  while (value, args = args.next())
@@ -615,7 +614,7 @@ module Steep
615
614
  end
616
615
  end
617
616
 
618
- pass = block_pass_arg
617
+ # pass = block_pass_arg
619
618
  # if pass.node
620
619
  # yield pass
621
620
  # end
@@ -1,163 +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)
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}"
30
19
  end
31
- annotations.const_types.each do |name, type|
32
- env.set(const: name, type: type)
20
+ end
21
+
22
+ instance_variable_types.each do |name, type|
23
+ array << "#{name}: #{type.to_s}"
24
+ end
25
+
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}"
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
+ )
79
+ end
80
+
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]
91
+ else
92
+ raise "Unexpected variable name: #{name}"
33
93
  end
34
- signatures.global_decls.each do |name, entry|
35
- type = entry.decl.type
36
- env.set(gvar: name, type: subtyping.factory.type(type))
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
101
+ end
37
102
  end
38
103
  end
39
104
  end
40
105
 
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)
106
+ def enforced_type(name)
107
+ local_variable_types[name]&.[](1)
108
+ end
45
109
 
46
- const_types.each do |name, annotated_type|
47
- env.const_types[name] = annotated_type
48
- end
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])))
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
+ )
125
+ end
126
+
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]
49
151
  end
152
+
153
+ merge(local_variable_types: local_variable_updates, pure_method_calls: pure_call_updates)
50
154
  end
51
155
 
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]
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)
60
162
  else
61
- yield
62
- AST::Types::Any.new
163
+ constant_env.resolve(arg1)
63
164
  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
165
+ end
166
+ end
167
+
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]
71
182
  end
72
183
  end
73
184
  end
74
185
  end
75
186
 
76
- def set(const: nil, gvar: nil, ivar: nil, type:)
77
- case
78
- when const
79
- const_types[const] = type
80
- else
81
- lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
82
- dictionary[var_name] = type
187
+ def unpin_local_variables(names)
188
+ names = Set.new(names) if names
189
+
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]
83
196
  end
84
197
  end
198
+
199
+ merge(local_variable_types: local_var_types)
85
200
  end
86
201
 
87
- # @type method assign: (const: TypeName, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
88
- # | (gvar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
89
- # | (ivar: Symbol, type: AST::Type) { (Subtyping::Result::Failure | nil) -> void } -> AST::Type
90
- def assign(gvar: nil, ivar: nil, type:, self_type:, instance_type:, class_type:, &block)
91
- lookup_dictionary(ivar: ivar, gvar: gvar) do |var_name, dictionary|
92
- if dictionary.key?(var_name)
93
- assert_assign(
94
- var_type: dictionary[var_name],
95
- lhs_type: type,
96
- self_type: self_type,
97
- instance_type: instance_type,
98
- class_type: class_type,
99
- &block
100
- )
101
- else
102
- yield nil
103
- AST::Types::Any.new
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
+ ]
104
212
  end
105
- end
213
+ )
106
214
  end
107
215
 
108
- def lookup_dictionary(ivar:, gvar:)
109
- case
110
- when ivar
111
- yield ivar, ivar_types
112
- when gvar
113
- yield gvar, gvar_types
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
114
228
  end
115
- end
116
229
 
117
- def assert_assign(var_type:, lhs_type:, self_type:, instance_type:, class_type:)
118
- return var_type if var_type == lhs_type
230
+ assignments =
231
+ all_lvar_types
232
+ .transform_values {|types| AST::Types::Union.build(types: types) }
233
+ .reject {|var, type| self[var] == type }
119
234
 
120
- var_type = subtyping.expand_alias(var_type)
121
- lhs_type = subtyping.expand_alias(lhs_type)
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) }
122
238
 
123
- relation = Subtyping::Relation.new(sub_type: lhs_type, super_type: var_type)
124
- constraints = Subtyping::Constraints.new(unknowns: Set.new)
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)
125
243
 
126
- subtyping.check(relation, self_type: self_type, constraints: constraints, instance_type: instance_type, class_type: class_type).else do |result|
127
- yield result
244
+ hash[node] = [call, refined_type]
128
245
  end
129
246
 
130
- var_type
247
+ assign_local_variables(assignments).merge(pure_method_calls: pure_call_updates)
131
248
  end
132
249
 
133
- def merge!(original_env:, override_env:, self_type:, instance_type:, class_type:, &block)
134
- original_env.merge!(override_env) do |name, original_type, override_type|
135
- assert_annotation(
136
- name,
137
- annotated_type: override_type,
138
- original_type: original_type,
139
- self_type: self_type,
140
- instance_type: instance_type,
141
- class_type: class_type,
142
- &block
143
- )
250
+ def add_pure_call(node, call, type)
251
+ if (c, _ = pure_method_calls[node]) && c == call
252
+ return self
144
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)
145
260
  end
146
261
 
147
- def assert_annotation(name, annotated_type:, original_type:, self_type:, instance_type:, class_type:)
148
- return annotated_type if annotated_type == original_type
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
269
+ end
270
+ end
149
271
 
150
- annotated_type = subtyping.expand_alias(annotated_type)
151
- original_type = subtyping.expand_alias(original_type)
272
+ def invalidate_pure_node(node)
273
+ merge(pure_method_calls: pure_node_invalidation(invalidated_pure_nodes(node)))
274
+ end
152
275
 
153
- relation = Subtyping::Relation.new(sub_type: annotated_type, super_type: original_type)
154
- constraints = Subtyping::Constraints.new(unknowns: Set.new)
276
+ def pure_node_invalidation(invalidated_nodes)
277
+ # @type var invalidation: Hash[Parser::AST::Node, [MethodCall::Typed, AST::Types::t?]]
278
+ invalidation = {}
155
279
 
156
- subtyping.check(relation, constraints: constraints, self_type: self_type, instance_type: instance_type, class_type: class_type).else do |result|
157
- yield name, relation, result
280
+ invalidated_nodes.each do |node|
281
+ if (call, _ = pure_method_calls[node])
282
+ invalidation[node] = [call, nil]
283
+ end
158
284
  end
159
285
 
160
- annotated_type
286
+ invalidation
287
+ end
288
+
289
+ def invalidated_pure_nodes(invalidated_node)
290
+ invalidated_nodes = Set[]
291
+
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
297
+ end
298
+
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 + ">"
161
318
  end
162
319
  end
163
320
  end