| 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 the third flat-aware post_pass port (s153): |
| 7 | // `inject_generated_fns_to_flat` must produce a FlatAst whose |
| 8 | // `signature()` matches what `inject_generated_fns_to_files` (the |
| 9 | // extracted legacy splice) + `flatten_files` produces. Each bucket |
| 10 | // (core_fns / module_fns[mod] / user_fns) is exercised in isolation |
| 11 | // against a single-file fixture — the multi-file intern-order quirk |
| 12 | // (same as s151/s152) makes multi-file signature comparison brittle, so |
| 13 | // we test the routing fallbacks of each bucket independently. |
| 14 | module transformer |
| 15 | |
| 16 | import v2.ast |
| 17 | import v2.pref as vpref |
| 18 | import v2.types |
| 19 | |
| 20 | // Local helper — `v test` compiles each `_test.v` file in isolation, so |
| 21 | // `create_test_transformer` from `transformer_test.v` is not visible here. |
| 22 | fn create_generated_fns_to_flat_test_transformer() &Transformer { |
| 23 | env := &types.Environment{} |
| 24 | return &Transformer{ |
| 25 | pref: &vpref.Preferences{} |
| 26 | env: unsafe { env } |
| 27 | needed_clone_fns: map[string]string{} |
| 28 | needed_array_contains_fns: map[string]ArrayMethodInfo{} |
| 29 | needed_array_index_fns: map[string]ArrayMethodInfo{} |
| 30 | needed_array_last_index_fns: map[string]ArrayMethodInfo{} |
| 31 | local_decl_types: map[string]types.Type{} |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | fn make_file_for_mod(mod string) ast.File { |
| 36 | return ast.File{ |
| 37 | name: '${mod}_min.v' |
| 38 | mod: mod |
| 39 | stmts: [ |
| 40 | ast.Stmt(ast.ModuleStmt{ |
| 41 | name: mod |
| 42 | }), |
| 43 | ] |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | fn make_fn_decl(name string) ast.Stmt { |
| 48 | return ast.Stmt(ast.FnDecl{ |
| 49 | name: name |
| 50 | }) |
| 51 | } |
| 52 | |
| 53 | // Bucket 1: core_fns → builtin file. |
| 54 | fn test_inject_generated_fns_to_flat_core_fns_into_builtin() { |
| 55 | parts := GeneratedFnsParts{ |
| 56 | core_fns: [make_fn_decl('int_str'), make_fn_decl('f64_str')] |
| 57 | module_fns: map[string][]ast.Stmt{} |
| 58 | user_fns: []ast.Stmt{} |
| 59 | } |
| 60 | mut ref_files := [make_file_for_mod('builtin')] |
| 61 | inject_generated_fns_to_files(mut ref_files, parts) |
| 62 | ref_sig := ast.flatten_files(ref_files).signature() |
| 63 | |
| 64 | mut b := ast.new_flat_builder() |
| 65 | b.append_file(make_file_for_mod('builtin')) |
| 66 | mut t := create_generated_fns_to_flat_test_transformer() |
| 67 | t.inject_generated_fns_to_flat(mut b, parts) |
| 68 | assert b.flat.signature() == ref_sig |
| 69 | } |
| 70 | |
| 71 | // Bucket 2: module_fns[mod] → mod file. |
| 72 | fn test_inject_generated_fns_to_flat_module_fns_into_mod() { |
| 73 | mut module_fns := map[string][]ast.Stmt{} |
| 74 | module_fns['time'] = [make_fn_decl('time__FormatDate__str')] |
| 75 | parts := GeneratedFnsParts{ |
| 76 | core_fns: []ast.Stmt{} |
| 77 | module_fns: module_fns |
| 78 | user_fns: []ast.Stmt{} |
| 79 | } |
| 80 | mut ref_files := [make_file_for_mod('time')] |
| 81 | inject_generated_fns_to_files(mut ref_files, parts) |
| 82 | ref_sig := ast.flatten_files(ref_files).signature() |
| 83 | |
| 84 | mut b := ast.new_flat_builder() |
| 85 | b.append_file(make_file_for_mod('time')) |
| 86 | mut t := create_generated_fns_to_flat_test_transformer() |
| 87 | t.inject_generated_fns_to_flat(mut b, parts) |
| 88 | assert b.flat.signature() == ref_sig |
| 89 | } |
| 90 | |
| 91 | // Bucket 3: user_fns → main file. |
| 92 | fn test_inject_generated_fns_to_flat_user_fns_into_main() { |
| 93 | parts := GeneratedFnsParts{ |
| 94 | core_fns: []ast.Stmt{} |
| 95 | module_fns: map[string][]ast.Stmt{} |
| 96 | user_fns: [make_fn_decl('Array_Test2_str'), make_fn_decl('Map_int_string_str')] |
| 97 | } |
| 98 | mut ref_files := [make_file_for_mod('main')] |
| 99 | inject_generated_fns_to_files(mut ref_files, parts) |
| 100 | ref_sig := ast.flatten_files(ref_files).signature() |
| 101 | |
| 102 | mut b := ast.new_flat_builder() |
| 103 | b.append_file(make_file_for_mod('main')) |
| 104 | mut t := create_generated_fns_to_flat_test_transformer() |
| 105 | t.inject_generated_fns_to_flat(mut b, parts) |
| 106 | assert b.flat.signature() == ref_sig |
| 107 | } |
| 108 | |
| 109 | // Fallback: core_fns lands in user_fns when no builtin file exists. |
| 110 | // With a single main file, user_fns → main → both legacy and flat-aware |
| 111 | // should splice core_fns into main via the user_fns route. |
| 112 | fn test_inject_generated_fns_to_flat_core_fns_fallback_no_builtin() { |
| 113 | parts := GeneratedFnsParts{ |
| 114 | core_fns: [make_fn_decl('int_str')] |
| 115 | module_fns: map[string][]ast.Stmt{} |
| 116 | user_fns: []ast.Stmt{} |
| 117 | } |
| 118 | mut ref_files := [make_file_for_mod('main')] |
| 119 | inject_generated_fns_to_files(mut ref_files, parts) |
| 120 | ref_sig := ast.flatten_files(ref_files).signature() |
| 121 | |
| 122 | mut b := ast.new_flat_builder() |
| 123 | b.append_file(make_file_for_mod('main')) |
| 124 | mut t := create_generated_fns_to_flat_test_transformer() |
| 125 | t.inject_generated_fns_to_flat(mut b, parts) |
| 126 | assert b.flat.signature() == ref_sig |
| 127 | } |
| 128 | |