v / vlib / v2 / ssa / build_label_from_flat_test.v
105 lines · 99 sloc · 3.01 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 s178: `build_label_from_flat` (third per-kind port
7// inside the s175 seam) must emit the same SSA jumps + label-block
8// fall-through as the legacy `build_label`. The flat path reads `name`
9// from `c.name()` — no LabelStmt struct decode and no `Stmt(LabelStmt{...})`
10// sum-type boxing.
11module ssa
12
13import v2.ast
14import v2.token
15import v2.types
16
17// Fixture: two fns — `do_label` with a bare LabelStmt 'top' (exercises
18// the fall-through + label_block creation), and `do_label_goto` with the
19// same label followed by a goto back to it (exercises label-block reuse
20// across LabelStmt + FlowControlStmt(goto)). Both arms go through
21// build_stmts_from_flat which now dispatches LabelStmt to
22// build_label_from_flat directly.
23fn make_label_fixture() []ast.File {
24 return [
25 ast.File{
26 name: 'main.v'
27 mod: 'main'
28 stmts: [
29 ast.Stmt(ast.ModuleStmt{
30 name: 'main'
31 }),
32 ast.Stmt(ast.FnDecl{
33 name: 'do_label'
34 typ: ast.FnType{}
35 stmts: [
36 ast.Stmt(ast.LabelStmt{
37 name: 'top'
38 }),
39 ]
40 }),
41 ast.Stmt(ast.FnDecl{
42 name: 'do_label_goto'
43 typ: ast.FnType{}
44 stmts: [
45 ast.Stmt(ast.LabelStmt{
46 name: 'top'
47 }),
48 ast.Stmt(ast.FlowControlStmt{
49 op: token.Token.key_goto
50 label: 'top'
51 }),
52 ]
53 }),
54 ]
55 },
56 ]
57}
58
59fn build_via_legacy_label(files []ast.File, env &types.Environment, name string) &Module {
60 mut mod := Module.new(name)
61 mut b := Builder.new_with_env(mod, env)
62 b.register_fn_signatures(files[0])
63 b.build_fn_bodies(files[0])
64 return mod
65}
66
67fn build_via_flat_label(files []ast.File, env &types.Environment, name string) &Module {
68 flat := ast.flatten_files(files)
69 mut mod := Module.new(name)
70 mut b := Builder.new_with_env(mod, env)
71 b.register_fn_signatures_from_flat(flat.file_cursor(0))
72 stmts := flat.file_cursor(0).stmts()
73 for si in 0 .. stmts.len() {
74 c := stmts.at(si)
75 if c.kind() != .stmt_fn_decl {
76 continue
77 }
78 decl := c.fn_decl_signature()
79 fn_name := b.mangle_fn_name(decl)
80 func_idx := b.fn_index[fn_name] or { continue }
81 b.cur_func = func_idx
82 b.label_blocks = map[string]BlockID{}
83 entry := mod.add_block(func_idx, 'entry')
84 b.cur_block = entry
85 body := c.list_at(3)
86 b.build_stmts_from_flat(body)
87 if !b.block_has_terminator(b.cur_block) {
88 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
89 }
90 }
91 return mod
92}
93
94fn test_build_label_from_flat_matches_legacy() {
95 files := make_label_fixture()
96 env := types.Environment.new()
97 mod_legacy := build_via_legacy_label(files, env, 'label_legacy')
98 mod_flat := build_via_flat_label(files, env, 'label_flat')
99
100 assert mod_legacy.funcs.len == mod_flat.funcs.len
101 assert mod_legacy.funcs.len == 2
102 assert mod_legacy.blocks.len == mod_flat.blocks.len
103 assert mod_legacy.instrs.len == mod_flat.instrs.len
104 assert mod_legacy.values.len == mod_flat.values.len
105}
106