v / vlib / v2 / ssa / build_flow_control_from_flat_test.v
120 lines · 114 sloc · 3.31 KB · d358576851079d4716834cc86627307d28acd1ae
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// vtest build: macos
5//
6// Bit-equality pin for s177: `build_flow_control_from_flat` (second per-
7// kind port inside the s175 seam) must emit the same SSA jumps as the
8// legacy `build_flow_control`. The flat path reads `op` from `c.aux()`
9// and `label` from `c.name()` — no FlowControlStmt struct decode and no
10// Stmt sum-type boxing.
11module ssa
12
13import v2.ast
14import v2.token
15import v2.types
16
17// Fixture: a fn with a labelled goto inside an unsafe forever-loop-then-
18// break shape. Going through build_fn_bodies exercises both the goto
19// branch (top of build_flow_control) and the break branch (loop exit).
20fn make_flow_control_fixture() []ast.File {
21 return [
22 ast.File{
23 name: 'main.v'
24 mod: 'main'
25 stmts: [
26 ast.Stmt(ast.ModuleStmt{
27 name: 'main'
28 }),
29 ast.Stmt(ast.FnDecl{
30 name: 'do_break'
31 typ: ast.FnType{}
32 stmts: [
33 ast.Stmt(ast.ForStmt{
34 stmts: [
35 ast.Stmt(ast.FlowControlStmt{
36 op: token.Token.key_break
37 }),
38 ]
39 }),
40 ]
41 }),
42 ast.Stmt(ast.FnDecl{
43 name: 'do_continue'
44 typ: ast.FnType{}
45 stmts: [
46 ast.Stmt(ast.ForStmt{
47 stmts: [
48 ast.Stmt(ast.FlowControlStmt{
49 op: token.Token.key_continue
50 }),
51 ]
52 }),
53 ]
54 }),
55 ast.Stmt(ast.FnDecl{
56 name: 'do_goto'
57 typ: ast.FnType{}
58 stmts: [
59 ast.Stmt(ast.LabelStmt{
60 name: 'top'
61 }),
62 ast.Stmt(ast.FlowControlStmt{
63 op: token.Token.key_goto
64 label: 'top'
65 }),
66 ]
67 }),
68 ]
69 },
70 ]
71}
72
73fn build_via_legacy_fc(files []ast.File, env &types.Environment, name string) &Module {
74 mut mod := Module.new(name)
75 mut b := Builder.new_with_env(mod, env)
76 b.register_fn_signatures(files[0])
77 b.build_fn_bodies(files[0])
78 return mod
79}
80
81fn build_via_flat_fc(files []ast.File, env &types.Environment, name string) &Module {
82 flat := ast.flatten_files(files)
83 mut mod := Module.new(name)
84 mut b := Builder.new_with_env(mod, env)
85 b.register_fn_signatures_from_flat(flat.file_cursor(0))
86 // Run fn bodies through build_stmts_from_flat (s175 seam). Each fn's
87 // FlowControlStmt now dispatches through build_flow_control_from_flat.
88 stmts := flat.file_cursor(0).stmts()
89 for si in 0 .. stmts.len() {
90 c := stmts.at(si)
91 if c.kind() != .stmt_fn_decl {
92 continue
93 }
94 decl := c.fn_decl_signature()
95 fn_name := b.mangle_fn_name(decl)
96 func_idx := b.fn_index[fn_name] or { continue }
97 b.cur_func = func_idx
98 entry := mod.add_block(func_idx, 'entry')
99 b.cur_block = entry
100 body := c.list_at(3)
101 b.build_stmts_from_flat(body)
102 if !b.block_has_terminator(b.cur_block) {
103 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
104 }
105 }
106 return mod
107}
108
109fn test_build_flow_control_from_flat_matches_legacy_for_break_continue_goto() {
110 files := make_flow_control_fixture()
111 env := types.Environment.new()
112 mod_legacy := build_via_legacy_fc(files, env, 'fc_legacy')
113 mod_flat := build_via_flat_fc(files, env, 'fc_flat')
114
115 assert mod_legacy.funcs.len == mod_flat.funcs.len
116 assert mod_legacy.funcs.len == 3
117 assert mod_legacy.blocks.len == mod_flat.blocks.len
118 assert mod_legacy.instrs.len == mod_flat.instrs.len
119 assert mod_legacy.values.len == mod_flat.values.len
120}
121