v / vlib / v2 / ssa / build_fn_from_flat_test.v
146 lines · 140 sloc · 3.72 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 s185: `build_fn_from_flat` (the s185 wiring step)
7// must build the same SSA bodies as the legacy `build_fn`. This is the
8// first session where `build_fn_bodies_from_flat` no longer decodes the
9// FnDecl body — instead `Cursor.fn_decl_signature()` returns a body-less
10// FnDecl, and `build_fn_from_flat` walks the body stmts directly via
11// `c.list_at(3)` cursors. Pin covers plain fn / fn with params / extern
12// (body_len==0) / multi-body fn branches.
13module ssa
14
15import v2.ast
16import v2.token
17import v2.types
18
19// Fixture exercises every branch of the new build_fn_from_flat:
20// - `answer`: plain fn returning a literal (single-stmt body)
21// - `add`: fn with two params + decl_assign + return (param setup + body)
22// - `noop`: extern-style fn with no body (body_len==0 branch)
23// - `loop_break`: fn with a for-loop containing break (heavyweight stmt arms)
24fn make_build_fn_from_flat_fixture() []ast.File {
25 return [
26 ast.File{
27 name: 'main.v'
28 mod: 'main'
29 stmts: [
30 ast.Stmt(ast.ModuleStmt{
31 name: 'main'
32 }),
33 ast.Stmt(ast.FnDecl{
34 name: 'answer'
35 typ: ast.FnType{
36 return_type: ast.Expr(ast.Ident{
37 name: 'int'
38 })
39 }
40 stmts: [
41 ast.Stmt(ast.ReturnStmt{
42 exprs: [
43 ast.Expr(ast.BasicLiteral{
44 kind: .number
45 value: '42'
46 }),
47 ]
48 }),
49 ]
50 }),
51 ast.Stmt(ast.FnDecl{
52 name: 'add'
53 typ: ast.FnType{
54 params: [
55 ast.Parameter{
56 name: 'a'
57 typ: ast.Expr(ast.Ident{
58 name: 'int'
59 })
60 },
61 ast.Parameter{
62 name: 'b'
63 typ: ast.Expr(ast.Ident{
64 name: 'int'
65 })
66 },
67 ]
68 return_type: ast.Expr(ast.Ident{
69 name: 'int'
70 })
71 }
72 stmts: [
73 ast.Stmt(ast.AssignStmt{
74 lhs: [
75 ast.Expr(ast.Ident{
76 name: 'c'
77 }),
78 ]
79 rhs: [
80 ast.Expr(ast.BasicLiteral{
81 kind: .number
82 value: '0'
83 }),
84 ]
85 op: token.Token.decl_assign
86 }),
87 ast.Stmt(ast.ReturnStmt{
88 exprs: [
89 ast.Expr(ast.Ident{
90 name: 'c'
91 }),
92 ]
93 }),
94 ]
95 }),
96 ast.Stmt(ast.FnDecl{
97 name: 'noop'
98 typ: ast.FnType{}
99 }),
100 ast.Stmt(ast.FnDecl{
101 name: 'loop_break'
102 typ: ast.FnType{}
103 stmts: [
104 ast.Stmt(ast.ForStmt{
105 stmts: [
106 ast.Stmt(ast.FlowControlStmt{
107 op: token.Token.key_break
108 }),
109 ]
110 }),
111 ]
112 }),
113 ]
114 },
115 ]
116}
117
118fn build_via_legacy_fn_bodies(files []ast.File, env &types.Environment, name string) &Module {
119 mut mod := Module.new(name)
120 mut b := Builder.new_with_env(mod, env)
121 b.register_fn_signatures(files[0])
122 b.build_fn_bodies(files[0])
123 return mod
124}
125
126fn build_via_flat_fn_bodies(files []ast.File, env &types.Environment, name string) &Module {
127 flat := ast.flatten_files(files)
128 mut mod := Module.new(name)
129 mut b := Builder.new_with_env(mod, env)
130 b.register_fn_signatures_from_flat(flat.file_cursor(0))
131 b.build_fn_bodies_from_flat(flat.file_cursor(0))
132 return mod
133}
134
135fn test_build_fn_from_flat_matches_legacy() {
136 files := make_build_fn_from_flat_fixture()
137 env := types.Environment.new()
138 mod_legacy := build_via_legacy_fn_bodies(files, env, 'bf_legacy')
139 mod_flat := build_via_flat_fn_bodies(files, env, 'bf_flat')
140
141 assert mod_legacy.funcs.len == mod_flat.funcs.len
142 assert mod_legacy.funcs.len == 4
143 assert mod_legacy.blocks.len == mod_flat.blocks.len
144 assert mod_legacy.instrs.len == mod_flat.instrs.len
145 assert mod_legacy.values.len == mod_flat.values.len
146}
147