| 1 | import os |
| 2 | import v3.flat |
| 3 | import v3.parser |
| 4 | import v3.pref |
| 5 | import v3.ssa |
| 6 | import v3.types |
| 7 | |
| 8 | // parse_checked reads parse checked input for v3 tests. |
| 9 | fn parse_checked(name string, source string) (&flat.FlatAst, &types.TypeChecker) { |
| 10 | src := os.join_path(os.temp_dir(), 'v3_ssa_buildopts_${name}.v') |
| 11 | os.write_file(src, source) or { panic(err) } |
| 12 | prefs := pref.new_preferences() |
| 13 | mut p := parser.Parser.new(prefs) |
| 14 | mut a := p.parse_file(src) |
| 15 | mut tc := types.TypeChecker.new(a) |
| 16 | tc.collect(a) |
| 17 | tc.annotate_types() |
| 18 | assert tc.errors.len == 0 |
| 19 | return a, &tc |
| 20 | } |
| 21 | |
| 22 | // func_named converts func named data for v3 tests. |
| 23 | fn func_named(m &ssa.Module, name string) ssa.Function { |
| 24 | for f in m.funcs { |
| 25 | if f.name == name { |
| 26 | return f |
| 27 | } |
| 28 | } |
| 29 | assert false, 'function ${name} not found' |
| 30 | return ssa.Function{} |
| 31 | } |
| 32 | |
| 33 | const prog = 'fn helper() int {\n\treturn 41\n}\n\nfn other() int {\n\treturn 7\n}\n\nfn main() {\n\t_ := helper() + other()\n}\n' |
| 34 | |
| 35 | // test_module_name_is_set validates module name is set behavior in v3 tests. |
| 36 | fn test_module_name_is_set() { |
| 37 | a, tc := parse_checked('modname', prog) |
| 38 | m := ssa.build_with_used(a, map[string]bool{}, tc) |
| 39 | assert m.name == 'main' |
| 40 | } |
| 41 | |
| 42 | // test_default_build_materializes_bodies validates this v3 regression case. |
| 43 | fn test_default_build_materializes_bodies() { |
| 44 | a, tc := parse_checked('default', prog) |
| 45 | m := ssa.build_with_used(a, map[string]bool{}, tc) |
| 46 | // helper has a real body (blocks) and is not a prototype. |
| 47 | helper := func_named(m, 'helper') |
| 48 | assert helper.blocks.len > 0 |
| 49 | assert !helper.is_prototype |
| 50 | } |
| 51 | |
| 52 | // test_skip_fn_bodies_marks_prototypes validates this v3 regression case. |
| 53 | fn test_skip_fn_bodies_marks_prototypes() { |
| 54 | a, tc := parse_checked('skipbodies', prog) |
| 55 | m := ssa.build_with_options(a, map[string]bool{}, tc, ssa.BuildOptions{ |
| 56 | skip_fn_bodies: true |
| 57 | }) |
| 58 | // User functions are registered but bodyless prototypes. |
| 59 | helper := func_named(m, 'helper') |
| 60 | assert helper.blocks.len == 0 |
| 61 | assert helper.is_prototype |
| 62 | other := func_named(m, 'other') |
| 63 | assert other.is_prototype |
| 64 | } |
| 65 | |
| 66 | // test_hot_fn_builds_only_target validates hot fn builds only target behavior in v3 tests. |
| 67 | fn test_hot_fn_builds_only_target() { |
| 68 | a, tc := parse_checked('hotfn', prog) |
| 69 | m := ssa.build_with_options(a, map[string]bool{}, tc, ssa.BuildOptions{ |
| 70 | hot_fn: 'helper' |
| 71 | }) |
| 72 | helper := func_named(m, 'helper') |
| 73 | assert helper.blocks.len > 0 // hot target built |
| 74 | assert !helper.is_prototype |
| 75 | other := func_named(m, 'other') |
| 76 | assert other.blocks.len == 0 // non-target stubbed |
| 77 | assert other.is_prototype |
| 78 | } |
| 79 | |
| 80 | // test_c_externs_are_external_prototypes validates this v3 regression case. |
| 81 | fn test_c_externs_are_external_prototypes() { |
| 82 | a, tc := parse_checked('externs', prog) |
| 83 | m := ssa.build_with_used(a, map[string]bool{}, tc) |
| 84 | mut found_extern := false |
| 85 | for f in m.funcs { |
| 86 | if f.is_c_extern { |
| 87 | found_extern = true |
| 88 | assert f.is_prototype |
| 89 | assert f.linkage == .external |
| 90 | } |
| 91 | } |
| 92 | assert found_extern |
| 93 | } |
| 94 | |