v / vlib / v2 / ssa / build_expr_stmt_from_flat_test.v
141 lines · 133 sloc · 3.82 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 s182: `build_expr_stmt_from_flat` (seventh per-kind
7// port inside the s175 seam) must dispatch the wrapped expr the same way
8// the legacy `build_expr_stmt` does. The flat path walks UnsafeExpr's
9// inner stmts via cursors (no `ast.Stmt` rehydration on that branch);
10// non-unsafe / non-if exprs still decode via `decode_expr` since
11// `build_expr` consumes legacy AST today.
12module ssa
13
14import v2.ast
15import v2.types
16
17// Two fixtures cover the two ports inside build_expr_stmt:
18// - Plain expr (BasicLiteral) — exercises the fallback `build_expr` branch
19// - UnsafeExpr containing a ReturnStmt — exercises the cursor-walk branch
20// that dispatches each inner stmt through `build_stmt_from_flat`.
21fn make_expr_stmt_plain_fixture() []ast.File {
22 return [
23 ast.File{
24 name: 'main.v'
25 mod: 'main'
26 stmts: [
27 ast.Stmt(ast.ModuleStmt{
28 name: 'main'
29 }),
30 ast.Stmt(ast.FnDecl{
31 name: 'do_expr'
32 typ: ast.FnType{}
33 stmts: [
34 ast.Stmt(ast.ExprStmt{
35 expr: ast.Expr(ast.BasicLiteral{
36 kind: .number
37 value: '42'
38 })
39 }),
40 ]
41 }),
42 ]
43 },
44 ]
45}
46
47fn make_expr_stmt_unsafe_fixture() []ast.File {
48 return [
49 ast.File{
50 name: 'main.v'
51 mod: 'main'
52 stmts: [
53 ast.Stmt(ast.ModuleStmt{
54 name: 'main'
55 }),
56 ast.Stmt(ast.FnDecl{
57 name: 'do_unsafe'
58 typ: ast.FnType{
59 return_type: ast.Expr(ast.Ident{
60 name: 'int'
61 })
62 }
63 stmts: [
64 ast.Stmt(ast.ExprStmt{
65 expr: ast.Expr(ast.UnsafeExpr{
66 stmts: [
67 ast.Stmt(ast.ReturnStmt{
68 exprs: [
69 ast.Expr(ast.BasicLiteral{
70 kind: .number
71 value: '11'
72 }),
73 ]
74 }),
75 ]
76 })
77 }),
78 ]
79 }),
80 ]
81 },
82 ]
83}
84
85fn build_via_legacy_es(files []ast.File, env &types.Environment, name string) &Module {
86 mut mod := Module.new(name)
87 mut b := Builder.new_with_env(mod, env)
88 b.register_fn_signatures(files[0])
89 b.build_fn_bodies(files[0])
90 return mod
91}
92
93fn build_via_flat_es(files []ast.File, env &types.Environment, name string) &Module {
94 flat := ast.flatten_files(files)
95 mut mod := Module.new(name)
96 mut b := Builder.new_with_env(mod, env)
97 b.register_fn_signatures_from_flat(flat.file_cursor(0))
98 stmts := flat.file_cursor(0).stmts()
99 for si in 0 .. stmts.len() {
100 c := stmts.at(si)
101 if c.kind() != .stmt_fn_decl {
102 continue
103 }
104 decl := c.fn_decl_signature()
105 fn_name := b.mangle_fn_name(decl)
106 func_idx := b.fn_index[fn_name] or { continue }
107 b.cur_func = func_idx
108 b.label_blocks = map[string]BlockID{}
109 entry := mod.add_block(func_idx, 'entry')
110 b.cur_block = entry
111 body := c.list_at(3)
112 b.build_stmts_from_flat(body)
113 if !b.block_has_terminator(b.cur_block) {
114 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
115 }
116 }
117 return mod
118}
119
120fn assert_same_es(mod_legacy &Module, mod_flat &Module) {
121 assert mod_legacy.funcs.len == mod_flat.funcs.len
122 assert mod_legacy.blocks.len == mod_flat.blocks.len
123 assert mod_legacy.instrs.len == mod_flat.instrs.len
124 assert mod_legacy.values.len == mod_flat.values.len
125}
126
127fn test_build_expr_stmt_from_flat_plain_matches_legacy() {
128 files := make_expr_stmt_plain_fixture()
129 env := types.Environment.new()
130 mod_legacy := build_via_legacy_es(files, env, 'es_plain_legacy')
131 mod_flat := build_via_flat_es(files, env, 'es_plain_flat')
132 assert_same_es(mod_legacy, mod_flat)
133}
134
135fn test_build_expr_stmt_from_flat_unsafe_matches_legacy() {
136 files := make_expr_stmt_unsafe_fixture()
137 env := types.Environment.new()
138 mod_legacy := build_via_legacy_es(files, env, 'es_unsafe_legacy')
139 mod_flat := build_via_flat_es(files, env, 'es_unsafe_flat')
140 assert_same_es(mod_legacy, mod_flat)
141}
142