gen: panic with correct type names (#8355)
							parent
							
								
									849bc6c3d8
								
							
						
					
					
						commit
						2cadb3e4d8
					
				|  | @ -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') | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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('(') | ||||
|  |  | |||
|  | @ -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` | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue