v / vlib / v2 / ssa / build_ident_from_flat_test.v
123 lines · 117 sloc · 3.44 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 s187: `build_ident_from_flat` is the second per-kind
7// arm inside `build_expr_from_flat` (after BasicLiteral). The cursor port
8// reads `name` from `c.name()` and `pos` from `c.pos()` — Ident has no aux,
9// no extra, no edges. Pos preservation keeps the type-checker hit hot.
10module ssa
11
12import v2.ast
13import v2.token
14import v2.types
15
16// Fixture: `mut c := 7; return c`. The ReturnStmt's expr is an Ident
17// pointing at the local var. Routing the Ident through build_expr_from_flat
18// must build the same SSA as the legacy path.
19fn make_ident_fixture() []ast.File {
20 return [
21 ast.File{
22 name: 'main.v'
23 mod: 'main'
24 stmts: [
25 ast.Stmt(ast.ModuleStmt{
26 name: 'main'
27 }),
28 ast.Stmt(ast.FnDecl{
29 name: 'get_c'
30 typ: ast.FnType{
31 return_type: ast.Expr(ast.Ident{
32 name: 'int'
33 })
34 }
35 stmts: [
36 ast.Stmt(ast.AssignStmt{
37 lhs: [
38 ast.Expr(ast.Ident{
39 name: 'c'
40 }),
41 ]
42 rhs: [
43 ast.Expr(ast.BasicLiteral{
44 kind: .number
45 value: '7'
46 }),
47 ]
48 op: token.Token.decl_assign
49 }),
50 ast.Stmt(ast.ReturnStmt{
51 exprs: [
52 ast.Expr(ast.Ident{
53 name: 'c'
54 }),
55 ]
56 }),
57 ]
58 }),
59 ]
60 },
61 ]
62}
63
64fn build_via_legacy_ident(files []ast.File, env &types.Environment, name string) &Module {
65 mut mod := Module.new(name)
66 mut b := Builder.new_with_env(mod, env)
67 b.register_fn_signatures(files[0])
68 b.build_fn_bodies(files[0])
69 return mod
70}
71
72// Flat-side helper: walks fn bodies; for ReturnStmt, dispatches the 0th edge
73// (the Ident) through build_expr_from_flat instead of decode_expr +
74// build_expr. Everything else goes through build_stmt_from_flat.
75fn build_via_flat_ident(files []ast.File, env &types.Environment, name string) &Module {
76 flat := ast.flatten_files(files)
77 mut mod := Module.new(name)
78 mut b := Builder.new_with_env(mod, env)
79 b.register_fn_signatures_from_flat(flat.file_cursor(0))
80 stmts := flat.file_cursor(0).stmts()
81 for si in 0 .. stmts.len() {
82 c := stmts.at(si)
83 if c.kind() != .stmt_fn_decl {
84 continue
85 }
86 decl := c.fn_decl_signature()
87 fn_name := b.mangle_fn_name(decl)
88 func_idx := b.fn_index[fn_name] or { continue }
89 b.cur_func = func_idx
90 b.label_blocks = map[string]BlockID{}
91 b.vars = map[string]ValueID{}
92 entry := mod.add_block(func_idx, 'entry')
93 b.cur_block = entry
94 body := c.list_at(3)
95 for bi in 0 .. body.len() {
96 stmt_c := body.at(bi)
97 if stmt_c.kind() == .stmt_return {
98 ret_expr_c := stmt_c.edge(0)
99 val := b.build_expr_from_flat(ret_expr_c)
100 mod.add_instr(.ret, b.cur_block, 0, [val])
101 } else {
102 b.build_stmt_from_flat(stmt_c)
103 }
104 }
105 if !b.block_has_terminator(b.cur_block) {
106 mod.add_instr(.ret, b.cur_block, 0, []ValueID{})
107 }
108 }
109 return mod
110}
111
112fn test_build_ident_from_flat_local_var_matches_legacy() {
113 files := make_ident_fixture()
114 env := types.Environment.new()
115 mod_legacy := build_via_legacy_ident(files, env, 'id_legacy')
116 mod_flat := build_via_flat_ident(files, env, 'id_flat')
117
118 assert mod_legacy.funcs.len == mod_flat.funcs.len
119 assert mod_legacy.funcs.len == 1
120 assert mod_legacy.blocks.len == mod_flat.blocks.len
121 assert mod_legacy.instrs.len == mod_flat.instrs.len
122 assert mod_legacy.values.len == mod_flat.values.len
123}
124