diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 17b9d9981c..92a768e370 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -4,8 +4,8 @@ module builtin __global ( - g_m2_buf byteptr - g_m2_ptr byteptr + g_m2_buf byteptr + g_m2_ptr byteptr ) // isnil returns true if an object is nil (only for C objects). @@ -29,14 +29,31 @@ pub fn print_backtrace() { print_backtrace_skipping_top_frames(2) } +struct VCastTypeIndexName { + tindex int + tname string +} + __global ( - total_m = i64(0) - nr_mallocs = int(0) + total_m = i64(0) + nr_mallocs = int(0) + // will be filled in cgen + as_cast_type_indexes []VCastTypeIndexName ) fn __as_cast(obj voidptr, obj_type int, expected_type int) voidptr { if obj_type != expected_type { - panic('as cast: cannot cast $obj_type to $expected_type') + mut obj_name := as_cast_type_indexes[0].tname + mut expected_name := as_cast_type_indexes[0].tname + for x in as_cast_type_indexes { + if x.tindex == obj_type { + obj_name = x.tname + } + if x.tindex == expected_type { + expected_name = x.tname + } + } + panic('as cast: cannot cast `$obj_name` to `$expected_name`') } return obj } @@ -55,15 +72,15 @@ pub: lvalue string // the stringified *actual value* of the left side of a failed assertion rvalue string // the stringified *actual value* of the right side of a failed assertion } + fn __print_assert_failure(i &VAssertMetaInfo) { - eprintln('${i.fpath}:${i.line_nr+1}: FAIL: fn ${i.fn_name}: assert ${i.src}') + eprintln('$i.fpath:${i.line_nr + 1}: FAIL: fn $i.fn_name: assert $i.src') if i.op.len > 0 && i.op != 'call' { - eprintln(' left value: ${i.llabel} = ${i.lvalue}') + eprintln(' left value: $i.llabel = $i.lvalue') if i.rlabel == i.rvalue { eprintln(' right value: $i.rlabel') - } - else { - eprintln(' right value: ${i.rlabel} = ${i.rvalue}') + } else { + eprintln(' right value: $i.rlabel = $i.rvalue') } } } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 207f02110a..a891a2d014 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -146,6 +146,7 @@ mut: branch_parent_pos int // used in BranchStmt (continue/break) for autofree stop position timers &util.Timers = util.new_timers(false) force_main_console bool // true when [console] used on fn main() + as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast) } pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string { @@ -201,7 +202,6 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string } g.init() g.timers.show('cgen init') - // mut tests_inited := false mut autofree_used := false for file in files { @@ -258,7 +258,6 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string g.definitions.writeln('int _v_type_idx_${typ.cname}() { return $idx; };') } } - // g.write_str_definitions() // v files are finished, what remains is pure C code g.gen_vlines_reset() if g.pref.build_mode != .build_module { @@ -4984,6 +4983,12 @@ fn (mut g Gen) write_init_function() { g.writeln('g_m2_buf = malloc(50 * 1000 * 1000);') g.writeln('g_m2_ptr = g_m2_buf;') } + // NB: the as_cast table should be *before* the other constant initialize calls, + // because it may be needed during const initialization of builtin and during + // calling module init functions too, just in case they do fail... + g.write('\tas_cast_type_indexes = ') + g.writeln(g.as_cast_name_table()) + // g.writeln('\tbuiltin_init();') g.writeln('\tvinit_string_literals();') // @@ -4999,7 +5004,6 @@ fn (mut g Gen) write_init_function() { } } } - // g.writeln('}') if g.pref.printfn_list.len > 0 && '_vinit' in g.pref.printfn_list { println(g.out.after(fn_vinit_start_pos)) @@ -5014,6 +5018,7 @@ fn (mut g Gen) write_init_function() { g.writeln(g.cleanups[mod_name].str()) } // g.writeln('\tfree(g_str_buf);') + g.writeln('\tarray_free(&as_cast_type_indexes);') g.writeln('}') if g.pref.printfn_list.len > 0 && '_vcleanup' in g.pref.printfn_list { println(g.out.after(fn_vcleanup_start_pos)) @@ -5848,22 +5853,50 @@ fn (mut g Gen) as_cast(node ast.AsCast) { styp := g.typ(node.typ) sym := g.table.get_type_symbol(node.typ) expr_type_sym := g.table.get_type_symbol(node.expr_type) - if expr_type_sym.kind == .sum_type { + if expr_type_sym.info is table.SumType { dot := if node.expr_type.is_ptr() { '->' } else { '.' } - g.write('/* as */ *($styp*)__as_cast((') + g.write('/* as */ *($styp*)__as_cast(') + g.write('(') g.expr(node.expr) g.write(')') g.write(dot) - g.write('_$sym.cname, (') + g.write('_$sym.cname,') + g.write('(') g.expr(node.expr) g.write(')') g.write(dot) // g.write('typ, /*expected:*/$node.typ)') sidx := g.type_sidx(node.typ) - g.write('typ, /*expected:*/$sidx)') + expected_sym := g.table.get_type_symbol(node.typ) + g.write('typ, $sidx) /*expected idx: $sidx, name: $expected_sym.name */ ') + + // fill as cast name table + for variant in expr_type_sym.info.variants { + idx := variant.str() + if idx in g.as_cast_type_names { + continue + } + variant_sym := g.table.get_type_symbol(variant) + g.as_cast_type_names[idx] = variant_sym.name + } } } +fn (g Gen) as_cast_name_table() string { + if g.as_cast_type_names.len == 0 { + return 'new_array_from_c_array(1, 1, sizeof(VCastTypeIndexName), _MOV((VCastTypeIndexName[1]){(VCastTypeIndexName){.tindex = 0,.tname = _SLIT("unknown")}}));' + } + mut name_table := strings.new_builder(1024) + casts_len := g.as_cast_type_names.len + 1 + name_table.writeln('new_array_from_c_array($casts_len, $casts_len, sizeof(VCastTypeIndexName), _MOV((VCastTypeIndexName[$casts_len]){') + name_table.writeln('\t\t (VCastTypeIndexName){.tindex = 0, .tname = _SLIT("unknown")}') + for key, value in g.as_cast_type_names { + name_table.writeln('\t\t, (VCastTypeIndexName){.tindex = $key, .tname = _SLIT("$value")}') + } + name_table.writeln('\t}));') + return name_table.str() +} + fn (mut g Gen) is_expr(node ast.InfixExpr) { eq := if node.op == .key_is { '==' } else { '!=' } g.write('(') diff --git a/vlib/v/tests/inout/bad_st_as.out b/vlib/v/tests/inout/bad_st_as.out index a1baab65af..0282290301 100644 --- a/vlib/v/tests/inout/bad_st_as.out +++ b/vlib/v/tests/inout/bad_st_as.out @@ -2,4 +2,4 @@ Foo ================ V panic ================ module: builtin function: __as_cast() - message: as cast: cannot cast + message: as cast: cannot cast `main.Struct` to `main.Interface`