diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index cc7c3c3e4f..dae5ae955b 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -384,18 +384,18 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name) fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) { /* gen_str_for_interface */') for typ in info.types { - subtype := g.table.sym(typ) + sub_sym := g.table.sym(ast.mktyp(typ)) mut func_name := g.get_str_fn(typ) - sym_has_str_method, str_method_expects_ptr, _ := subtype.str_method_info() - if should_use_indent_func(subtype.kind) && !sym_has_str_method { + sym_has_str_method, str_method_expects_ptr, _ := sub_sym.str_method_info() + if should_use_indent_func(sub_sym.kind) && !sym_has_str_method { func_name = 'indent_$func_name' } // str_intp deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' } if typ == ast.string_type { - mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname' - if should_use_indent_func(subtype.kind) && !sym_has_str_method { + mut val := '${func_name}(${deref}($sub_sym.cname*)x._$sub_sym.cname' + if should_use_indent_func(sub_sym.kind) && !sym_has_str_method { val += ', indent_count' } val += ')' @@ -403,11 +403,11 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam {_SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, {_SLIT("\')"), 0, {.d_c = 0 }} }))' - fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)') + fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string(' return $res;') } else { - mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname' - if should_use_indent_func(subtype.kind) && !sym_has_str_method { + mut val := '${func_name}(${deref}($sub_sym.cname*)x._$sub_sym.cname' + if should_use_indent_func(sub_sym.kind) && !sym_has_str_method { val += ', indent_count' } val += ')' @@ -415,7 +415,7 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam {_SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}}, {_SLIT(")"), 0, {.d_c = 0 }} }))' - fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)') + fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string(' return $res;\n') } } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index e0e6bf8cbb..f349bb51db 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -859,16 +859,16 @@ pub fn (mut g Gen) write_typeof_functions() { g.definitions.writeln('static char * v_typeof_interface_${sym.cname}(int sidx);') g.writeln('static char * v_typeof_interface_${sym.cname}(int sidx) { /* $sym.name */ ') for t in inter_info.types { - subtype := g.table.sym(t) - g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return "${util.strip_main_name(subtype.name)}";') + sub_sym := g.table.sym(ast.mktyp(t)) + g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return "${util.strip_main_name(sub_sym.name)}";') } g.writeln('\treturn "unknown ${util.strip_main_name(sym.name)}";') g.writeln('}') g.writeln('') g.writeln('static int v_typeof_interface_idx_${sym.cname}(int sidx) { /* $sym.name */ ') for t in inter_info.types { - subtype := g.table.sym(t) - g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return ${int(t)};') + sub_sym := g.table.sym(ast.mktyp(t)) + g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return ${int(t)};') } g.writeln('\treturn ${int(ityp)};') g.writeln('}') @@ -1319,7 +1319,11 @@ pub fn (mut g Gen) write_interface_typesymbol_declaration(sym ast.TypeSymbol) { g.type_definitions.writeln('\tunion {') g.type_definitions.writeln('\t\tvoid* _object;') for variant in info.types { - vcname := g.table.sym(variant).cname + mk_typ := ast.mktyp(variant) + if mk_typ != variant && mk_typ in info.types { + continue + } + vcname := g.table.sym(mk_typ).cname g.type_definitions.writeln('\t\t$vcname* _$vcname;') } g.type_definitions.writeln('\t};') @@ -2085,11 +2089,11 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ g.expr(expr) return } - if exp_sym.info is ast.Interface && got_type_raw.idx() != expected_type.idx() + if exp_sym.info is ast.Interface && got_type.idx() != expected_type.idx() && !expected_type.has_flag(.optional) { if expr is ast.StructInit && !got_type.is_ptr() { g.inside_cast_in_heap++ - got_styp := g.cc_type(got_type_raw.ref(), true) + got_styp := g.cc_type(got_type.ref(), true) // TODO: why does cc_type even add this in the first place? exp_styp := exp_sym.cname mut fname := 'I_${got_styp}_to_Interface_$exp_styp' @@ -2100,7 +2104,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ got_styp) g.inside_cast_in_heap-- } else { - got_styp := g.cc_type(got_type_raw, true) + got_styp := g.cc_type(got_type, true) got_is_shared := got_type.has_flag(.shared_f) exp_styp := if got_is_shared { '__shared__$exp_sym.cname' } else { exp_sym.cname } // If it's shared, we need to use the other caster: @@ -5334,10 +5338,10 @@ fn (mut g Gen) interface_table() string { iinidx_minimum_base := 1000 // Note: NOT 0, to avoid map entries set to 0 later, so `if already_generated_mwrappers[name] > 0 {` works. mut current_iinidx := iinidx_minimum_base for st in inter_info.types { - st_sym := g.table.sym(st) + st_sym := g.table.sym(ast.mktyp(st)) // cctype is the Cleaned Concrete Type name, *without ptr*, // i.e. cctype is always just Cat, not Cat_ptr: - cctype := g.cc_type(st, true) + cctype := g.cc_type(ast.mktyp(st), true) $if debug_interface_table ? { eprintln('>> interface name: $isym.name | concrete type: $st.debug() | st symname: $st_sym.name') } diff --git a/vlib/v/tests/cast_to_empty_interface_test.v b/vlib/v/tests/cast_to_empty_interface_test.v new file mode 100644 index 0000000000..ac8963c14a --- /dev/null +++ b/vlib/v/tests/cast_to_empty_interface_test.v @@ -0,0 +1,29 @@ +interface Any {} + +fn thing(any Any) string { + return match any { + int { 'int${*any:17}' } + f64 { 'f64${*any:20}' } + else { 'literal type tag?${any:10}' } + } +} + +fn test_cast_to_empty_interface() { + mut ret_strings := []string{} + mut arr := [Any(int(11)), int(22), Any(8888), 9999, Any(f64(1.11)), f64(2.22), Any(8.88), 9.99] + + for i in arr { + println(thing(i)) + ret_strings << thing(i) + } + + assert ret_strings.len == 8 + assert ret_strings[0] == 'int 11' + assert ret_strings[1] == 'int 22' + assert ret_strings[2] == 'int 8888' + assert ret_strings[3] == 'int 9999' + assert ret_strings[4] == 'f64 1.110' + assert ret_strings[5] == 'f64 2.220' + assert ret_strings[6] == 'f64 8.880' + assert ret_strings[7] == 'f64 9.990' +}