v / vlib / v2 / ssa / build_for_from_flat_test.v
136 lines · 128 sloc · 3.74 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 s183: `build_for_from_flat` (eighth per-kind port
7// inside the s175 seam) must build the same for_cond / for_body /
8// for_exit block scaffold + br/jmp wiring as the legacy `build_for`. The
9// flat path walks body stmts directly via `c.edge(i)` and uses
10// `.stmt_empty` / `.expr_empty` cursor sentinels to detect missing
11// init/cond/post — no ForStmt struct decode.
12module ssa
13
14import v2.ast
15import v2.token
16import v2.types
17
18// Two fixtures cover the no-cond / has-cond branches of build_for:
19// - `do_infinite`: `for { break }` — has_cond=false, infinite-loop jmp
20// - `do_conditioned`: `for true { break }` — has_cond=true, br on cond
21// Both leave init/post empty so the EmptyStmt sentinel branch is exercised.
22fn make_for_infinite_fixture() []ast.File {
23 return [
24 ast.File{
25 name: 'main.v'
26 mod: 'main'
27 stmts: [
28 ast.Stmt(ast.ModuleStmt{
29 name: 'main'
30 }),
31 ast.Stmt(ast.FnDecl{
32 name: 'do_infinite'
33 typ: ast.FnType{}
34 stmts: [
35 ast.Stmt(ast.ForStmt{
36 stmts: [
37 ast.Stmt(ast.FlowControlStmt{
38 op: token.Token.key_break
39 }),
40 ]
41 }),
42 ]
43 }),
44 ]
45 },
46 ]
47}
48
49fn make_for_conditioned_fixture() []ast.File {
50 return [
51 ast.File{
52 name: 'main.v'
53 mod: 'main'
54 stmts: [
55 ast.Stmt(ast.ModuleStmt{
56 name: 'main'
57 }),
58 ast.Stmt(ast.FnDecl{
59 name: 'do_conditioned'
60 typ: ast.FnType{}
61 stmts: [
62 ast.Stmt(ast.ForStmt{
63 cond: ast.Expr(ast.BasicLiteral{
64 kind: .key_true
65 value: 'true'
66 })
67 stmts: [
68 ast.Stmt(ast.FlowControlStmt{
69 op: token.Token.key_break
70 }),
71 ]
72 }),
73 ]
74 }),
75 ]
76 },
77 ]
78}
79
80fn build_via_legacy_for(files []ast.File, env &types.Environment, name string) &Module {
81 mut mod := Module.new(name)
82 mut b := Builder.new_with_env(mod, env)
83 b.register_fn_signatures(files[0])
84 b.build_fn_bodies(files[0])
85 return mod
86}
87
88fn build_via_flat_for(files []ast.File, env &types.Environment, name string) &Module {
89 flat := ast.flatten_files(files)
90 mut mod := Module.new(name)
91 mut b := Builder.new_with_env(mod, env)
92 b.register_fn_signatures_from_flat(flat.file_cursor(0))
93 stmts := flat.file_cursor(0).stmts()
94 for si in 0 .. stmts.len() {
95 c := stmts.at(si)
96 if c.kind() != .stmt_fn_decl {
97 continue
98 }
99 decl := c.fn_decl_signature()
100 fn_name := b.mangle_fn_name(decl)
101 func_idx := b.fn_index[fn_name] or { continue }
102 b.cur_func = func_idx
103 b.label_blocks = map[string]BlockID{}
104 entry := mod.add_block(func_idx, 'entry')
105 b.cur_block = entry
106 body := c.list_at(3)
107 b.build_stmts_from_flat(body)
108 if !b.block_has_terminator(b.cur_block) {
109 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
110 }
111 }
112 return mod
113}
114
115fn assert_same_for(mod_legacy &Module, mod_flat &Module) {
116 assert mod_legacy.funcs.len == mod_flat.funcs.len
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
122fn test_build_for_from_flat_infinite_matches_legacy() {
123 files := make_for_infinite_fixture()
124 env := types.Environment.new()
125 mod_legacy := build_via_legacy_for(files, env, 'for_inf_legacy')
126 mod_flat := build_via_flat_for(files, env, 'for_inf_flat')
127 assert_same_for(mod_legacy, mod_flat)
128}
129
130fn test_build_for_from_flat_conditioned_matches_legacy() {
131 files := make_for_conditioned_fixture()
132 env := types.Environment.new()
133 mod_legacy := build_via_legacy_for(files, env, 'for_cond_legacy')
134 mod_flat := build_via_flat_for(files, env, 'for_cond_flat')
135 assert_same_for(mod_legacy, mod_flat)
136}
137