From e0963381ec2032dba6d276112f8aff94e392c71f Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 22 Apr 2022 16:02:51 +0800 Subject: [PATCH] checker, cgen: fix generic empty interface to multi struct (#14132) --- vlib/v/checker/if.v | 7 ++--- vlib/v/checker/return.v | 9 +++++- vlib/v/gen/c/cgen.v | 2 +- vlib/v/gen/c/fn.v | 4 +-- vlib/v/gen/c/str_intp.v | 2 +- ...ric_empty_interface_to_multi_struct_test.v | 30 +++++++++++++++++++ 6 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 vlib/v/tests/generic_empty_interface_to_multi_struct_test.v diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 5f813803a6..608abd5c9e 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -296,7 +296,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) { c.smartcast_if_conds(node.right, mut scope) } else if node.op == .key_is { right_expr := node.right - mut right_type := match right_expr { + right_type := match right_expr { ast.TypeNode { right_expr.typ } @@ -308,11 +308,10 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) { ast.Type(0) } } - right_type = c.unwrap_generic(right_type) if right_type != ast.Type(0) { left_sym := c.table.sym(node.left_type) right_sym := c.table.sym(right_type) - mut expr_type := c.unwrap_generic(c.expr(node.left)) + mut expr_type := c.expr(node.left) if left_sym.kind == .aggregate { expr_type = (left_sym.info as ast.Aggregate).sum_type } @@ -322,7 +321,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) { } else { return } - } else if !c.check_types(right_type, expr_type) { + } else if !c.check_types(right_type, expr_type) && left_sym.kind != .sum_type { expect_str := c.table.type_to_str(right_type) expr_str := c.table.type_to_str(expr_type) c.error('cannot use type `$expect_str` as type `$expr_str`', node.pos) diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index a545dfe54d..f442826d95 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -34,7 +34,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { mut got_types := []ast.Type{} mut expr_idxs := []int{} for i, expr in node.exprs { - typ := c.expr(expr) + mut typ := c.expr(expr) if typ == ast.void_type { c.error('`$expr` used as value', node.pos) } @@ -46,6 +46,13 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { expr_idxs << i } } else { + if expr is ast.Ident { + if expr.obj is ast.Var { + if expr.obj.smartcasts.len > 0 { + typ = c.unwrap_generic(expr.obj.smartcasts.last()) + } + } + } got_types << typ expr_idxs << i } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 1468a135f8..3fa4d7a5c0 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3286,7 +3286,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { if field_sym.kind == .sum_type { g.write('*') } - cast_sym := g.table.sym(typ) + cast_sym := g.table.sym(g.unwrap_generic(typ)) if i != 0 { dot := if field.typ.is_ptr() { '->' } else { '.' } sum_type_deref_field += ')$dot' diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 7e6a2cd03f..72ef19b5b0 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -941,7 +941,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.gen_expr_to_string(node.left, rec_type) return } else if node.left.obj.smartcasts.len > 0 { - rec_type = node.left.obj.smartcasts.last() + rec_type = g.unwrap_generic(node.left.obj.smartcasts.last()) cast_sym := g.table.sym(rec_type) if cast_sym.info is ast.Aggregate { rec_type = cast_sym.info.types[g.aggregate_type_idx] @@ -1331,7 +1331,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { if expr.obj is ast.Var { typ = expr.obj.typ if expr.obj.smartcasts.len > 0 { - typ = expr.obj.smartcasts.last() + typ = g.unwrap_generic(expr.obj.smartcasts.last()) cast_sym := g.table.sym(typ) if cast_sym.info is ast.Aggregate { typ = cast_sym.info.types[g.aggregate_type_idx] diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index cdbebb6ebb..663fe05bd1 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -156,7 +156,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) { if g.comptime_var_type_map.len > 0 || g.comptime_for_method.len > 0 { exp_typ = expr.obj.typ } else if expr.obj.smartcasts.len > 0 { - exp_typ = expr.obj.smartcasts.last() + exp_typ = g.unwrap_generic(expr.obj.smartcasts.last()) cast_sym := g.table.sym(exp_typ) if cast_sym.info is ast.Aggregate { exp_typ = cast_sym.info.types[g.aggregate_type_idx] diff --git a/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v b/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v new file mode 100644 index 0000000000..1dd408b15d --- /dev/null +++ b/vlib/v/tests/generic_empty_interface_to_multi_struct_test.v @@ -0,0 +1,30 @@ +interface Any {} + +struct ConcreteA { + a int +} + +struct ConcreteB { + b int +} + +struct Container { + concrete_a Any + concrete_b Any +} + +fn cast_struct(any_struct Any) &T { + if any_struct is T { + return any_struct + } + panic('cannot cast') +} + +fn test_generic_empty_interface_to_multi_struct() { + concrete_a := cast_struct(ConcreteA{12345}) + concrete_b := cast_struct(ConcreteB{54321}) + println(concrete_a.a) + println(concrete_b.b) + assert concrete_a.a == 12345 + assert concrete_b.b == 54321 +}