v4 / vlib / v / gen / c / closure_context_codegen_test.v
894 lines · 793 sloc · 27.17 KB · 1a2d0e5b70d6dd1baaa60290f2446e9ece4324bf
Raw
1import os
2
3const test_vexe = os.quoted_path(@VEXE)
4
5fn bounded_window(text string, marker string, before int, after int) string {
6 pos := text.index(marker) or {
7 assert false, 'missing marker: ${marker}'
8 return ''
9 }
10 start := if pos > before { pos - before } else { 0 }
11 end_limit := pos + marker.len + after
12 end := if end_limit < text.len { end_limit } else { text.len }
13 return text[start..end]
14}
15
16fn function_window(text string, marker string) string {
17 pos := text.index(marker) or {
18 assert false, 'missing marker: ${marker}'
19 return ''
20 }
21 rest := text[pos + marker.len..]
22 end_offset := rest.index('\nVV_LOC ') or { rest.len }
23 return text[pos..pos + marker.len + end_offset]
24}
25
26fn function_window_containing(text string, marker string) string {
27 pos := text.index(marker) or {
28 assert false, 'missing marker: ${marker}'
29 return ''
30 }
31 prefix := text[..pos]
32 start := prefix.last_index('\nVV_LOC ') or { 0 }
33 rest := text[start + 1..]
34 end_offset := rest.index('\nVV_LOC ') or { rest.len }
35 return rest[..end_offset]
36}
37
38fn test_closure_context_codegen_uses_collectable_memdup_and_ownership() {
39 workdir := os.join_path(os.vtmp_dir(), 'closure_context_codegen_${os.getpid()}')
40 os.mkdir_all(workdir)!
41 defer {
42 os.rmdir_all(workdir) or {}
43 }
44 source_path := os.join_path(workdir, 'main.v')
45 exe_path := os.join_path(workdir, 'main')
46 os.write_file(source_path, 'module main
47
48struct Receiver {
49mut:
50 value int
51}
52
53@[heap]
54struct PointerReceiver {
55mut:
56 value int
57}
58
59type IntCallback = fn (int) int
60
61type ZeroCallback = fn () int
62
63type ResultRequestHandler = fn (int) !
64
65__global global_cb = fn (x int) int {
66 return x
67}
68
69struct CallbackBox {
70mut:
71 cb IntCallback = unsafe { nil }
72}
73
74fn make_closure(seed int) fn () int {
75 return fn [seed] () int {
76 return seed + 1
77 }
78}
79
80fn (r Receiver) read() int {
81 return r.value
82}
83
84fn (mut r PointerReceiver) bump() int {
85 r.value++
86 return r.value
87}
88
89fn local_direct_closure() {
90 big := []int{len: 200, init: index}
91 h := fn [big] (x int) int {
92 return big[x % big.len]
93 }
94 _ = h(11)
95}
96
97fn local_escaped_closure(mut callbacks []IntCallback) {
98 big := []int{len: 200, init: index}
99 h := fn [big] (x int) int {
100 return big[x % big.len]
101 }
102 callbacks << h
103}
104
105fn local_return_fn_value(n int) IntCallback {
106 big := []int{len: 200, init: index + n}
107 h := fn [big] (x int) int {
108 return big[x % big.len]
109 }
110 return h
111}
112
113fn local_copy_closure(n int) int {
114 big := []int{len: 200, init: index + n}
115 h := fn [big] (x int) int {
116 return big[x % big.len]
117 }
118 k := h
119 return k(n % 200)
120}
121
122fn takes_cb(cb IntCallback, n int) int {
123 return cb(n % 200)
124}
125
126fn local_arg_closure(n int) int {
127 big := []int{len: 200, init: index + n}
128 h := fn [big] (x int) int {
129 return big[x % big.len]
130 }
131 return takes_cb(h, n)
132}
133
134fn local_struct_init_closure(n int) int {
135 big := []int{len: 200, init: index + n}
136 h := fn [big] (x int) int {
137 return big[x % big.len]
138 }
139 box := CallbackBox{
140 cb: h
141 }
142 return box.cb(n % 200)
143}
144
145fn local_struct_assign_closure(n int) int {
146 big := []int{len: 200, init: index + n}
147 h := fn [big] (x int) int {
148 return big[x % big.len]
149 }
150 mut box := CallbackBox{}
151 box.cb = h
152 return box.cb(n % 200)
153}
154
155fn local_global_assign_closure(n int) int {
156 big := []int{len: 200, init: index + n}
157 h := fn [big] (x int) int {
158 return big[x % big.len]
159 }
160 global_cb = h
161 return global_cb(n % 200)
162}
163
164fn local_defer_closure() {
165 big := []int{len: 200, init: index}
166 h := fn [big] (x int) int {
167 return big[x % big.len]
168 }
169 defer {
170 _ = h(0)
171 }
172}
173
174fn local_return_closure(n int) int {
175 big := []int{len: 200, init: index + n}
176 h := fn [big] (x int) int {
177 return big[x % big.len]
178 }
179 if n >= 0 {
180 return h(n % 200)
181 }
182 return 0
183}
184
185fn local_call_then_return_closure(n int) int {
186 big := []int{len: 200, init: index + n}
187 h := fn [big] (x int) int {
188 return big[x % big.len]
189 }
190 _ = h(n % 200)
191 return 0
192}
193
194fn maybe_int(n int) ?int {
195 if n < 0 {
196 return none
197 }
198 return n
199}
200
201fn result_int(n int) !int {
202 if n < 0 {
203 return error("negative")
204 }
205 return n
206}
207
208fn maybe_request(request int) ! {
209 if request < 0 {
210 return error("negative request")
211 }
212}
213
214fn local_option_propagation_cleanup(n int) ?int {
215 big := []int{len: 200, init: index + n}
216 h := fn [big] (x int) int {
217 return big[x % big.len]
218 }
219 value := maybe_int(n)?
220 return h(value % 200)
221}
222
223fn local_result_propagation_cleanup(n int) !int {
224 big := []int{len: 200, init: index + n}
225 h := fn [big] (x int) int {
226 return big[x % big.len]
227 }
228 value := result_int(n)!
229 return h(value % 200)
230}
231
232fn local_result_handler_cast_closure_boundary() {
233 offset := 1
234 handle_request := fn [offset] (request int) ! {
235 maybe_request(request)!
236 _ = offset
237 }
238 _ = ResultRequestHandler(handle_request)
239}
240
241fn local_for_c_init_closure(n int) int {
242 big := []int{len: 200, init: index + n}
243 h := fn [big] (x int) int {
244 return big[x % big.len]
245 }
246 for i := takes_cb(h, n); i < 1; i++ {
247 return i
248 }
249 return 0
250}
251
252fn local_for_c_cond_closure(n int) int {
253 big := []int{len: 200, init: index + n}
254 h := fn [big] (x int) int {
255 return big[x % big.len]
256 }
257 mut result := 0
258 for i := 0; i < 1 && takes_cb(h, n) >= 0; i++ {
259 result += i
260 }
261 return result
262}
263
264fn local_for_c_inc_closure(n int) int {
265 big := []int{len: 200, init: index + n}
266 h := fn [big] (x int) int {
267 return big[x % big.len]
268 }
269 mut result := 0
270 for i := 0; i < 1; i += takes_cb(h, n) + 1 {
271 result += i
272 }
273 return result
274}
275
276fn local_for_c_init_closure_body_tail(n int) int {
277 big := []int{len: 200, init: index + n}
278 mut i := 0
279 mut result := 0
280 for h := fn [big] (x int) int {
281 return big[x % big.len]
282 }; i < 2; i++ {
283 result += h(i)
284 }
285 return result
286}
287
288fn local_for_c_init_closure_continue(n int) int {
289 big := []int{len: 200, init: index + n}
290 mut i := 0
291 mut result := 0
292 for h := fn [big] (x int) int {
293 return big[x % big.len]
294 }; i < 2; i++ {
295 if i == 0 {
296 continue
297 }
298 result += h(i)
299 }
300 return result
301}
302
303fn local_multi_for_c_init_closure_body_tail(n int) int {
304 big := []int{len: 200, init: index + n}
305 mut result := 0
306 for h, i := fn [big] (x int) int {
307 return big[x % big.len]
308 }, 0; i < 2; i++ {
309 result += h(i)
310 }
311 return result
312}
313
314fn local_for_c_body_closure_continue_cleanup(n int) int {
315 mut i := 0
316 for ; i < 1; i++ {
317 big := []int{len: 200, init: index + n}
318 h := fn [big] (x int) int {
319 return big[x % big.len]
320 }
321 _ = h(n % 200)
322 continue
323 }
324 return 0
325}
326
327fn local_for_c_init_closure_return_cleanup(n int) int {
328 big := []int{len: 200, init: index + n}
329 mut i := 0
330 for h := fn [big] (x int) int {
331 return big[x % big.len]
332 }; i < 1; i++ {
333 return h(n % 200)
334 }
335 return -1
336}
337
338fn local_for_c_init_closure_labeled_break_cleanup(n int) int {
339 big := []int{len: 200, init: index + n}
340 mut i := 0
341 mut result := 0
342 closure_init_break: for h := fn [big] (x int) int {
343 return big[x % big.len]
344 }; i < 1; i++ {
345 result += h(n % 200)
346 break closure_init_break
347 }
348 return result
349}
350
351fn local_for_c_init_escaped_closure(mut callbacks []ZeroCallback, n int) {
352 big := []int{len: 200, init: index + n}
353 mut i := 0
354 for h := fn [big, n] () int {
355 return big[n % big.len]
356 }; i < 1; i++ {
357 callbacks << h
358 }
359}
360
361fn local_nested_for_c_init_closure_continue_outer(n int) int {
362 outer_big := []int{len: 200, init: index + n}
363 mut i := 0
364 mut result := 0
365 nested_continue_outer: for outer_h := fn [outer_big] (x int) int {
366 return outer_big[x % outer_big.len]
367 }; i < 2; i++ {
368 inner_big := []int{len: 200, init: index + n + 10}
369 mut j := 0
370 for inner_h := fn [inner_big] (x int) int {
371 return inner_big[x % inner_big.len]
372 }; j < 1; j++ {
373 result += outer_h(i) + inner_h(j)
374 continue nested_continue_outer
375 }
376 }
377 return result
378}
379
380fn local_nested_for_c_init_closure_break_outer(n int) int {
381 outer_big := []int{len: 200, init: index + n}
382 mut i := 0
383 mut result := 0
384 nested_break_outer: for outer_h := fn [outer_big] (x int) int {
385 return outer_big[x % outer_big.len]
386 }; i < 2; i++ {
387 inner_big := []int{len: 200, init: index + n + 20}
388 mut j := 0
389 for inner_h := fn [inner_big] (x int) int {
390 return inner_big[x % inner_big.len]
391 }; j < 1; j++ {
392 result += outer_h(i) + inner_h(j)
393 break nested_break_outer
394 }
395 }
396 return result
397}
398
399fn local_for_cond_closure(n int) int {
400 big := []int{len: 200, init: index + n}
401 h := fn [big] (x int) int {
402 return big[x % big.len]
403 }
404 mut result := 0
405 for result < 1 && takes_cb(h, n) >= 0 {
406 break
407 }
408 return result
409}
410
411fn local_for_in_cond_closure(n int) int {
412 big := []int{len: 200, init: index + n}
413 h := fn [big] (x int) int {
414 return big[x % big.len]
415 }
416 for value in []int{len: 1, init: takes_cb(h, n)} {
417 return value
418 }
419 return 0
420}
421
422fn local_for_in_high_closure(n int) int {
423 big := []int{len: 200, init: index + n}
424 h := fn [big] (x int) int {
425 return big[x % big.len]
426 }
427 mut result := 0
428 for i in 0 .. takes_cb(h, n) {
429 result += i
430 }
431 return result
432}
433
434fn local_array_init_closure(n int) int {
435 big := []int{len: 200, init: index + n}
436 h := fn [big] (x int) int {
437 return big[x % big.len]
438 }
439 values := []int{len: 1, init: takes_cb(h, n)}
440 return values[0]
441}
442
443fn local_if_else_condition_closure(n int) int {
444 big := []int{len: 200, init: index + n}
445 h := fn [big] (x int) int {
446 return big[x % big.len]
447 }
448 if n < 0 {
449 return n
450 } else if takes_cb(h, n) >= 0 {
451 return 0
452 }
453 return n
454}
455
456fn local_nested_returning_closure(n int) ZeroCallback {
457 big := []int{len: 200, init: index + n}
458 h := fn [big] (x int) int {
459 return big[x % big.len]
460 }
461 nested := fn [h, n] () int {
462 return h(n % 200)
463 }
464 return nested
465}
466
467fn local_nested_stored_closure(mut callbacks []ZeroCallback, n int) {
468 big := []int{len: 200, init: index + n}
469 h := fn [big] (x int) int {
470 return big[x % big.len]
471 }
472 nested := fn [h, n] () int {
473 return h(n % 200)
474 }
475 callbacks << nested
476}
477
478fn local_keyword_closure() {
479 big := []int{len: 200, init: index}
480 free := fn [big] (x int) int {
481 return big[x % big.len]
482 }
483}
484
485fn local_labeled_break_closure(n int) int {
486 mut value := 0
487 closure_break: for {
488 big := []int{len: 200, init: index + n}
489 h := fn [big] (x int) int {
490 return big[x % big.len]
491 }
492 value = h(n % 200)
493 break closure_break
494 }
495 return value
496}
497
498fn local_labeled_continue_closure(n int) int {
499 mut value := 0
500 closure_continue: for _ in 0 .. 1 {
501 big := []int{len: 200, init: index + n}
502 h := fn [big] (x int) int {
503 return big[x % big.len]
504 }
505 value = h(n % 200)
506 continue closure_continue
507 }
508 return value
509}
510
511fn local_spawn_closure() {
512 big := []int{len: 200, init: index}
513 h := fn [big] () {
514 _ = big[0]
515 }
516 t := spawn h()
517 t.wait()
518}
519
520fn local_go_closure() {
521 big := []int{len: 200, init: index}
522 h := fn [big] () {
523 _ = big[0]
524 }
525 t := go h()
526 t.wait()
527}
528
529fn main() {
530 receiver := Receiver{
531 value: 10
532 }
533 mut pointer_receiver := &PointerReceiver{
534 value: 10
535 }
536 anon_cb := make_closure(5)
537 value_cb := receiver.read
538 pointer_cb := pointer_receiver.bump
539 local_direct_closure()
540 mut callbacks := []IntCallback{}
541 local_escaped_closure(mut callbacks)
542 local_spawn_closure()
543 local_go_closure()
544 local_defer_closure()
545 local_result_handler_cast_closure_boundary()
546 opt_cleanup := local_option_propagation_cleanup(-1) or { 0 }
547 res_cleanup := local_result_propagation_cleanup(-1) or { 0 }
548 returned_cb := local_return_fn_value(0)
549 returned_nested := local_nested_returning_closure(0)
550 mut zero_callbacks := []ZeroCallback{}
551 local_nested_stored_closure(mut zero_callbacks, 0)
552 local_keyword_closure()
553 mut escaped_for_c_callbacks := []ZeroCallback{}
554 local_for_c_init_escaped_closure(mut escaped_for_c_callbacks, 0)
555 mut total := anon_cb() + value_cb() + pointer_cb() + local_return_closure(0)
556 total += local_call_then_return_closure(0) + opt_cleanup + res_cleanup
557 total += local_for_c_init_closure(0) + local_for_c_cond_closure(0) + local_for_c_inc_closure(0)
558 total += local_for_c_init_closure_body_tail(0) + local_for_c_init_closure_continue(0)
559 total += local_multi_for_c_init_closure_body_tail(0) + local_for_c_body_closure_continue_cleanup(0)
560 total += local_for_c_init_closure_return_cleanup(0) + local_for_c_init_closure_labeled_break_cleanup(0)
561 total += escaped_for_c_callbacks[0]()
562 total += local_nested_for_c_init_closure_continue_outer(0) + local_nested_for_c_init_closure_break_outer(0)
563 total += local_for_cond_closure(0) + local_for_in_cond_closure(0) + local_for_in_high_closure(0)
564 total += local_array_init_closure(0) + local_if_else_condition_closure(0) + returned_nested()
565 total += zero_callbacks[0]() + local_labeled_break_closure(0) + local_labeled_continue_closure(0)
566 total += returned_cb(0) + local_copy_closure(0) + local_arg_closure(0)
567 total += local_struct_init_closure(0) + local_struct_assign_closure(0) + local_global_assign_closure(0)
568 println(total)
569}
570')!
571
572 c_cmd := '${test_vexe} -enable-globals -gc boehm -skip-unused -o - ${os.quoted_path(source_path)}'
573 c_res := os.execute(c_cmd)
574 assert c_res.exit_code == 0, '${c_cmd}\n${c_res.output}'
575 generated := c_res.output.replace('\r\n', '\n')
576 assert !generated.contains('builtin__memdup_uncollectable')
577 assert generated.contains('sizeof(builtin__closure__ClosureLiveInfo)')
578 assert !generated.contains('new_map_noscan_value(sizeof(voidptr), sizeof(builtin__closure__ClosureLiveInfo)')
579 assert !generated.contains('new_map_noscan_key_value(sizeof(voidptr), sizeof(builtin__closure__ClosureLiveInfo)')
580
581 anon_window := bounded_window(generated, 'VV_LOC anon_fn___int main__make_closure(int seed) {',
582 0, 900)
583 assert anon_window.contains('builtin__closure__closure_create_with_data(')
584 assert anon_window.contains('builtin__memdup(&(')
585 assert anon_window.contains(', true)')
586
587 value_method_call := bounded_window(generated,
588 'builtin__closure__closure_create_with_data(_V_closure_main__Receiver_read_', 0, 300)
589 assert value_method_call.contains('builtin__memdup(')
590 assert value_method_call.contains(', true)')
591
592 pointer_method_call := bounded_window(generated,
593 'builtin__closure__closure_create_with_data(_V_closure_main__PointerReceiver_bump_', 0, 300)
594 assert !pointer_method_call.contains('builtin__memdup(')
595 assert pointer_method_call.contains(', false)')
596
597 direct_fn := function_window(generated, 'void main__local_direct_closure(void) {')
598 assert direct_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
599
600 escaped_fn := function_window(generated, 'void main__local_escaped_closure')
601 assert !escaped_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
602
603 return_value_fn := function_window(generated, 'main__IntCallback main__local_return_fn_value')
604 assert !return_value_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
605
606 copy_fn := function_window(generated, 'int main__local_copy_closure(int n) {')
607 assert !copy_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
608
609 arg_fn := function_window(generated, 'int main__local_arg_closure(int n) {')
610 assert !arg_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
611
612 struct_init_fn := function_window(generated, 'int main__local_struct_init_closure(int n) {')
613 assert !struct_init_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
614
615 struct_assign_fn := function_window(generated, 'int main__local_struct_assign_closure(int n) {')
616 assert !struct_assign_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
617
618 global_assign_fn := function_window(generated, 'int main__local_global_assign_closure(int n) {')
619 assert !global_assign_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
620
621 defer_fn := function_window(generated, 'void main__local_defer_closure(void) {')
622 assert !defer_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
623
624 return_fn := function_window(generated, 'int main__local_return_closure(int n) {')
625 return_cleanup_pos := return_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
626 assert false, return_fn
627 return
628 }
629 return_tmp_pos := return_fn.index(' = h(') or {
630 assert false, return_fn
631 return
632 }
633 assert return_tmp_pos < return_cleanup_pos
634 assert return_fn[return_cleanup_pos..].contains('return _')
635
636 call_return_fn := function_window(generated,
637 'int main__local_call_then_return_closure(int n) {')
638 assert call_return_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
639
640 option_propagation_fn := function_window(generated,
641 'main__local_option_propagation_cleanup(int n) {')
642 option_call_pos := option_propagation_fn.index('main__maybe_int(n)') or {
643 assert false, option_propagation_fn
644 return
645 }
646 option_after_call := option_propagation_fn[option_call_pos..]
647 option_value_pos := option_after_call.index('int value = ') or {
648 assert false, option_propagation_fn
649 return
650 }
651 option_fail_branch := option_after_call[..option_value_pos]
652 option_cleanup_pos := option_fail_branch.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
653 assert false, option_propagation_fn
654 return
655 }
656 option_hidden_return_pos := option_fail_branch.index('\treturn ') or {
657 assert false, option_propagation_fn
658 return
659 }
660 assert option_cleanup_pos < option_hidden_return_pos
661
662 result_propagation_fn := function_window(generated,
663 'main__local_result_propagation_cleanup(int n) {')
664 result_call_pos := result_propagation_fn.index('main__result_int(n)') or {
665 assert false, result_propagation_fn
666 return
667 }
668 result_after_call := result_propagation_fn[result_call_pos..]
669 result_value_pos := result_after_call.index('int value = ') or {
670 assert false, result_propagation_fn
671 return
672 }
673 result_fail_branch := result_after_call[..result_value_pos]
674 result_cleanup_pos := result_fail_branch.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
675 assert false, result_propagation_fn
676 return
677 }
678 result_hidden_return_pos := result_fail_branch.index('\treturn ') or {
679 assert false, result_propagation_fn
680 return
681 }
682 assert result_cleanup_pos < result_hidden_return_pos
683
684 result_handler_anon_fn := function_window_containing(generated, 'main__maybe_request(request)')
685 assert !result_handler_anon_fn.contains('builtin__closure__closure_try_destroy((voidptr)handle_request);')
686
687 for_c_init_fn := function_window(generated, 'int main__local_for_c_init_closure(int n) {')
688 assert !for_c_init_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
689
690 for_c_cond_fn := function_window(generated, 'int main__local_for_c_cond_closure(int n) {')
691 assert !for_c_cond_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
692
693 for_c_inc_fn := function_window(generated, 'int main__local_for_c_inc_closure(int n) {')
694 assert !for_c_inc_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
695
696 for_c_init_body_tail_fn := function_window(generated,
697 'int main__local_for_c_init_closure_body_tail(int n) {')
698 assert for_c_init_body_tail_fn.contains('for (;')
699 for_c_init_body_tail_call_pos := for_c_init_body_tail_fn.index('result += h(') or {
700 assert false, for_c_init_body_tail_fn
701 return
702 }
703 for_c_init_body_tail_cleanup_pos := for_c_init_body_tail_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
704 assert false, for_c_init_body_tail_fn
705 return
706 }
707 for_c_init_body_tail_return_pos := for_c_init_body_tail_fn.index('return result;') or {
708 assert false, for_c_init_body_tail_fn
709 return
710 }
711 assert for_c_init_body_tail_call_pos < for_c_init_body_tail_cleanup_pos
712 assert for_c_init_body_tail_cleanup_pos < for_c_init_body_tail_return_pos
713
714 for_c_init_continue_fn := function_window(generated,
715 'int main__local_for_c_init_closure_continue(int n) {')
716 assert for_c_init_continue_fn.contains('for (;')
717 for_c_init_continue_pos := for_c_init_continue_fn.index('continue;') or {
718 assert false, for_c_init_continue_fn
719 return
720 }
721 for_c_init_continue_cleanup_pos := for_c_init_continue_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
722 assert false, for_c_init_continue_fn
723 return
724 }
725 for_c_init_continue_return_pos := for_c_init_continue_fn.index('return result;') or {
726 assert false, for_c_init_continue_fn
727 return
728 }
729 assert for_c_init_continue_pos < for_c_init_continue_cleanup_pos
730 assert for_c_init_continue_cleanup_pos < for_c_init_continue_return_pos
731
732 multi_for_c_init_body_tail_fn := function_window(generated,
733 'int main__local_multi_for_c_init_closure_body_tail(int n) {')
734 assert multi_for_c_init_body_tail_fn.contains('while (true)')
735 assert multi_for_c_init_body_tail_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
736
737 for_c_body_continue_fn := function_window(generated,
738 'int main__local_for_c_body_closure_continue_cleanup(int n) {')
739 for_c_body_continue_cleanup_pos := for_c_body_continue_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
740 assert false, for_c_body_continue_fn
741 return
742 }
743 for_c_body_continue_pos := for_c_body_continue_fn.index('continue;') or {
744 assert false, for_c_body_continue_fn
745 return
746 }
747 assert for_c_body_continue_cleanup_pos < for_c_body_continue_pos
748
749 for_c_init_return_fn := function_window(generated,
750 'int main__local_for_c_init_closure_return_cleanup(int n) {')
751 for_c_init_return_call_pos := for_c_init_return_fn.index(' = h(') or {
752 assert false, for_c_init_return_fn
753 return
754 }
755 for_c_init_return_cleanup_pos := for_c_init_return_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
756 assert false, for_c_init_return_fn
757 return
758 }
759 for_c_init_return_pos := for_c_init_return_fn.index('\treturn ') or {
760 assert false, for_c_init_return_fn
761 return
762 }
763 assert for_c_init_return_call_pos < for_c_init_return_cleanup_pos
764 assert for_c_init_return_cleanup_pos < for_c_init_return_pos
765
766 for_c_init_labeled_break_fn := function_window(generated,
767 'int main__local_for_c_init_closure_labeled_break_cleanup(int n) {')
768 for_c_init_labeled_break_goto_pos := for_c_init_labeled_break_fn.index('goto closure_init_break__break;') or {
769 assert false, for_c_init_labeled_break_fn
770 return
771 }
772 for_c_init_labeled_break_label_pos := for_c_init_labeled_break_fn.index('closure_init_break__break: {}') or {
773 assert false, for_c_init_labeled_break_fn
774 return
775 }
776 for_c_init_labeled_break_cleanup_pos := for_c_init_labeled_break_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
777 assert false, for_c_init_labeled_break_fn
778 return
779 }
780 assert for_c_init_labeled_break_goto_pos < for_c_init_labeled_break_label_pos
781 assert for_c_init_labeled_break_label_pos < for_c_init_labeled_break_cleanup_pos
782
783 for_c_init_escaped_fn := function_window(generated,
784 'void main__local_for_c_init_escaped_closure')
785 assert !for_c_init_escaped_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
786
787 nested_continue_fn := function_window(generated,
788 'int main__local_nested_for_c_init_closure_continue_outer(int n) {')
789 nested_continue_inner_cleanup_pos := nested_continue_fn.index('builtin__closure__closure_try_destroy((voidptr)inner_h);') or {
790 assert false, nested_continue_fn
791 return
792 }
793 nested_continue_goto_pos := nested_continue_fn.index('goto nested_continue_outer__continue_entry;') or {
794 assert false, nested_continue_fn
795 return
796 }
797 nested_continue_outer_cleanup_pos := nested_continue_fn.index('builtin__closure__closure_try_destroy((voidptr)outer_h);') or {
798 assert false, nested_continue_fn
799 return
800 }
801 assert nested_continue_inner_cleanup_pos < nested_continue_goto_pos
802 assert nested_continue_goto_pos < nested_continue_outer_cleanup_pos
803
804 nested_break_fn := function_window(generated,
805 'int main__local_nested_for_c_init_closure_break_outer(int n) {')
806 nested_break_inner_cleanup_pos := nested_break_fn.index('builtin__closure__closure_try_destroy((voidptr)inner_h);') or {
807 assert false, nested_break_fn
808 return
809 }
810 nested_break_goto_pos := nested_break_fn.index('goto nested_break_outer__break;') or {
811 assert false, nested_break_fn
812 return
813 }
814 nested_break_label_pos := nested_break_fn.index('nested_break_outer__break: {}') or {
815 assert false, nested_break_fn
816 return
817 }
818 nested_break_outer_cleanup_pos := nested_break_fn.index('builtin__closure__closure_try_destroy((voidptr)outer_h);') or {
819 assert false, nested_break_fn
820 return
821 }
822 assert nested_break_inner_cleanup_pos < nested_break_goto_pos
823 assert nested_break_goto_pos < nested_break_label_pos
824 assert nested_break_label_pos < nested_break_outer_cleanup_pos
825
826 for_cond_fn := function_window(generated, 'int main__local_for_cond_closure(int n) {')
827 assert !for_cond_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
828
829 for_in_cond_fn := function_window(generated, 'int main__local_for_in_cond_closure(int n) {')
830 assert !for_in_cond_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
831
832 for_in_high_fn := function_window(generated, 'int main__local_for_in_high_closure(int n) {')
833 assert !for_in_high_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
834
835 array_init_fn := function_window(generated, 'int main__local_array_init_closure(int n) {')
836 assert !array_init_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
837
838 if_condition_fn := function_window(generated,
839 'int main__local_if_else_condition_closure(int n) {')
840 assert !if_condition_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
841
842 nested_returning_fn := function_window(generated,
843 'main__ZeroCallback main__local_nested_returning_closure(int n) {')
844 assert !nested_returning_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
845 assert !nested_returning_fn.contains('builtin__closure__closure_try_destroy((voidptr)nested);')
846
847 nested_stored_fn := function_window(generated, 'void main__local_nested_stored_closure')
848 assert !nested_stored_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
849 assert !nested_stored_fn.contains('builtin__closure__closure_try_destroy((voidptr)nested);')
850
851 keyword_fn := function_window(generated, 'void main__local_keyword_closure(void) {')
852 assert keyword_fn.contains('(*_v_free)')
853 assert keyword_fn.contains('builtin__closure__closure_try_destroy((voidptr)_v_free);')
854 assert !keyword_fn.contains('builtin__closure__closure_try_destroy((voidptr)__v_free);')
855 assert !keyword_fn.contains('builtin__closure__closure_try_destroy((voidptr)free);')
856
857 labeled_break_fn := function_window(generated, 'int main__local_labeled_break_closure(int n) {')
858 labeled_break_cleanup_pos := labeled_break_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
859 assert false, labeled_break_fn
860 return
861 }
862 labeled_break_goto_pos := labeled_break_fn.index('goto closure_break__break;') or {
863 assert false, labeled_break_fn
864 return
865 }
866 assert labeled_break_cleanup_pos < labeled_break_goto_pos
867
868 labeled_continue_fn := function_window(generated,
869 'int main__local_labeled_continue_closure(int n) {')
870 labeled_continue_cleanup_pos := labeled_continue_fn.index('builtin__closure__closure_try_destroy((voidptr)h);') or {
871 assert false, labeled_continue_fn
872 return
873 }
874 labeled_continue_goto_pos := labeled_continue_fn.index('goto closure_continue__continue_entry;') or {
875 assert false, labeled_continue_fn
876 return
877 }
878 assert labeled_continue_cleanup_pos < labeled_continue_goto_pos
879
880 spawn_fn := function_window(generated, 'void main__local_spawn_closure(void) {')
881 assert spawn_fn.contains('/*spawn (thread) */')
882 assert !spawn_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
883
884 go_fn := function_window(generated, 'void main__local_go_closure(void) {')
885 assert go_fn.contains('/*spawn (thread) */') || go_fn.contains('/*go (coroutine) */')
886 assert !go_fn.contains('builtin__closure__closure_try_destroy((voidptr)h);')
887
888 compile_cmd := '${test_vexe} -enable-globals -gc none -skip-unused -o ${os.quoted_path(exe_path)} ${os.quoted_path(source_path)}'
889 compile_res := os.execute(compile_cmd)
890 assert compile_res.exit_code == 0, '${compile_cmd}\n${compile_res.output}'
891 run_res := os.execute(os.quoted_path(exe_path))
892 assert run_res.exit_code == 0, run_res.output
893 assert run_res.output.trim_space() == '71'
894}
895