@@ -95,6 +95,162 @@ def get_keyword_arg(genv, changes, name)
9595 end
9696 end
9797
98+ class ForwardingArguments
99+ def initialize ( req_positionals , opt_positionals , opt_positional_elems , rest_positionals , post_positionals , req_keyword_pairs , opt_keyword_pairs , rest_keywords , block )
100+ @req_positionals = req_positionals
101+ @opt_positionals = opt_positionals
102+ @opt_positional_elems = opt_positional_elems
103+ @rest_positionals = rest_positionals
104+ @post_positionals = post_positionals
105+ @req_keyword_pairs = req_keyword_pairs
106+ @opt_keyword_pairs = opt_keyword_pairs
107+ @rest_keywords = rest_keywords
108+ @block = block
109+ end
110+
111+ attr_reader :block
112+
113+ def to_actual_arguments ( genv , changes , node )
114+ positionals = @req_positionals . dup
115+ splat_flags = ::Array . new ( positionals . size , false )
116+
117+ @opt_positionals . each do |arg |
118+ positionals << arg
119+ splat_flags << true
120+ end
121+
122+ if @rest_positionals
123+ positionals << @rest_positionals
124+ splat_flags << true
125+ end
126+
127+ @post_positionals . each do |arg |
128+ positionals << arg
129+ splat_flags << false
130+ end
131+
132+ keywords = build_keyword_args ( genv , changes , node )
133+ ActualArguments . new ( positionals , splat_flags , keywords , @block )
134+ end
135+
136+ def accept_actual_arguments ( genv , changes , a_args )
137+ if a_args . splat_flags . any?
138+ start_rest = [ a_args . splat_flags . index ( true ) , @req_positionals . size + @opt_positionals . size ] . min
139+ end_rest = [ a_args . splat_flags . rindex ( true ) + 1 , a_args . positionals . size - @post_positionals . size ] . max
140+ rest_vtxs = a_args . get_rest_args ( genv , changes , start_rest , end_rest )
141+
142+ @req_positionals . each_with_index do |f_vtx , i |
143+ if i < start_rest
144+ changes . add_edge ( genv , a_args . positionals [ i ] , f_vtx )
145+ else
146+ rest_vtxs . each do |vtx |
147+ changes . add_edge ( genv , vtx , f_vtx )
148+ end
149+ end
150+ end
151+
152+ @opt_positional_elems . each_with_index do |elem_vtx , i |
153+ i += @req_positionals . size
154+ if i < start_rest
155+ changes . add_edge ( genv , a_args . positionals [ i ] , elem_vtx )
156+ else
157+ rest_vtxs . each do |vtx |
158+ changes . add_edge ( genv , vtx , elem_vtx )
159+ end
160+ end
161+ end
162+
163+ @post_positionals . each_with_index do |f_vtx , i |
164+ i += a_args . positionals . size - @post_positionals . size
165+ if end_rest <= i
166+ changes . add_edge ( genv , a_args . positionals [ i ] , f_vtx )
167+ else
168+ rest_vtxs . each do |vtx |
169+ changes . add_edge ( genv , vtx , f_vtx )
170+ end
171+ end
172+ end
173+
174+ else
175+ @req_positionals . each_with_index do |f_vtx , i |
176+ changes . add_edge ( genv , a_args . positionals [ i ] , f_vtx )
177+ end
178+
179+ @post_positionals . each_with_index do |f_vtx , i |
180+ i -= @post_positionals . size
181+ changes . add_edge ( genv , a_args . positionals [ i ] , f_vtx )
182+ end
183+
184+ start_rest = @req_positionals . size
185+ end_rest = a_args . positionals . size - @post_positionals . size
186+ i = 0
187+ while i < @opt_positional_elems . size && start_rest < end_rest
188+ changes . add_edge ( genv , a_args . positionals [ start_rest ] , @opt_positional_elems [ i ] )
189+ i += 1
190+ start_rest += 1
191+ end
192+ end
193+
194+ changes . add_edge ( genv , a_args . block , @block ) if @block && a_args . block
195+
196+ return unless a_args . keywords
197+
198+ @req_keyword_pairs . each do |name , f_vtx |
199+ changes . add_edge ( genv , a_args . get_keyword_arg ( genv , changes , name ) , f_vtx )
200+ end
201+
202+ @opt_keyword_pairs . each do |name , f_vtx |
203+ changes . add_edge ( genv , a_args . get_keyword_arg ( genv , changes , name ) , f_vtx )
204+ end
205+
206+ if @rest_keywords
207+ named_keys = @req_keyword_pairs . map ( &:first ) + @opt_keyword_pairs . map ( &:first )
208+ a_args . keywords . each_type do |kw_ty |
209+ case kw_ty
210+ when Type ::Record
211+ rest_fields = kw_ty . fields . reject { |key , _ | named_keys . include? ( key ) }
212+ base = kw_ty . base_type ( genv )
213+ rest_record = Type ::Record . new ( genv , rest_fields , base )
214+ changes . add_edge ( genv , Source . new ( rest_record ) , @rest_keywords )
215+ when Type ::Hash , Type ::Instance
216+ changes . add_edge ( genv , Source . new ( kw_ty ) , @rest_keywords )
217+ end
218+ end
219+ end
220+ end
221+
222+ private
223+
224+ def build_keyword_args ( genv , changes , node )
225+ return nil if @req_keyword_pairs . empty? && @opt_keyword_pairs . empty? && !@rest_keywords
226+ return @rest_keywords if @req_keyword_pairs . empty? && @opt_keyword_pairs . empty?
227+
228+ unified_key = Vertex . new ( node )
229+ unified_val = Vertex . new ( node )
230+ literal_pairs = { }
231+
232+ @req_keyword_pairs . each do |name , vtx |
233+ changes . add_edge ( genv , Source . new ( Type ::Symbol . new ( genv , name ) ) , unified_key )
234+ changes . add_edge ( genv , vtx , unified_val )
235+ literal_pairs [ name ] = vtx
236+ end
237+
238+ @opt_keyword_pairs . each do |name , vtx |
239+ changes . add_edge ( genv , Source . new ( Type ::Symbol . new ( genv , name ) ) , unified_key )
240+ changes . add_edge ( genv , vtx , unified_val )
241+ end
242+
243+ base_hash_type = genv . gen_hash_type ( unified_key , unified_val )
244+ changes . add_hash_splat_box ( genv , @rest_keywords , unified_key , unified_val ) if @rest_keywords
245+
246+ if literal_pairs . empty?
247+ Source . new ( base_hash_type )
248+ else
249+ Source . new ( Type ::Record . new ( genv , literal_pairs , base_hash_type ) )
250+ end
251+ end
252+ end
253+
98254 class Block
99255 #: (AST::CallBaseNode, Vertex, Array[Vertex], Array[EscapeBox]) -> void
100256 def initialize ( node , f_ary_arg , f_args , next_boxes )
0 commit comments