gen: panic with correct type names (#8355)

pull/8450/head
Daniel Däschle 2021-01-30 17:54:05 +01:00 committed by GitHub
parent 849bc6c3d8
commit 2cadb3e4d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 18 deletions

View File

@ -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')
}
}
}

View File

@ -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('(')

View File

@ -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`