From 36fbd3c4fa0e69ccdc85a133b38e149e27f9f643 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 7 Dec 2021 06:31:47 +0800 Subject: [PATCH] checker: check sumtype as mismatched type (#12743) --- vlib/v/ast/table.v | 6 +++--- vlib/v/checker/check_types.v | 2 +- vlib/v/checker/checker.v | 8 +++++--- vlib/v/checker/tests/sumtype_as_mismatched_type.out | 7 +++++++ vlib/v/checker/tests/sumtype_as_mismatched_type.vv | 8 ++++++++ vlib/v/gen/c/cgen.v | 2 +- 6 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 vlib/v/checker/tests/sumtype_as_mismatched_type.out create mode 100644 vlib/v/checker/tests/sumtype_as_mismatched_type.vv diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 2c2483d1aedc21..d045fa8b9847e4 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1121,7 +1121,7 @@ pub fn (mut t Table) register_fn_concrete_types(fn_name string, types []Type) bo // TODO: there is a bug when casting sumtype the other way if its pointer // so until fixed at least show v (not C) error `x(variant) = y(SumType*)` -pub fn (t &Table) sumtype_has_variant(parent Type, variant Type) bool { +pub fn (t &Table) sumtype_has_variant(parent Type, variant Type, is_as bool) bool { parent_sym := t.get_type_symbol(parent) if parent_sym.kind == .sum_type { parent_info := parent_sym.info as SumType @@ -1129,14 +1129,14 @@ pub fn (t &Table) sumtype_has_variant(parent Type, variant Type) bool { if var_sym.kind == .aggregate { var_info := var_sym.info as Aggregate for var_type in var_info.types { - if !t.sumtype_has_variant(parent, var_type) { + if !t.sumtype_has_variant(parent, var_type, is_as) { return false } } return true } else { for v in parent_info.variants { - if v.idx() == variant.idx() { + if v.idx() == variant.idx() && (!is_as || v.nr_muls() == variant.nr_muls()) { return true } } diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 3e121eab0dd9ac..f1ab66b0f3a268 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -117,7 +117,7 @@ pub fn (mut c Checker) check_basic(got ast.Type, expected ast.Type) bool { return true } // sum type - if c.table.sumtype_has_variant(expected, c.table.mktyp(got)) { + if c.table.sumtype_has_variant(expected, c.table.mktyp(got), false) { return true } // type alias diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 47bea7ebf0f05d..433a15d166ebbe 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5421,8 +5421,10 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type { type_sym := c.table.get_type_symbol(node.typ) if expr_type_sym.kind == .sum_type { c.ensure_type_exists(node.typ, node.pos) or {} - if !c.table.sumtype_has_variant(node.expr_type, node.typ) { - c.error('cannot cast `$expr_type_sym.name` to `$type_sym.name`', node.pos) + if !c.table.sumtype_has_variant(node.expr_type, node.typ, true) { + addr := '&'.repeat(node.typ.nr_muls()) + c.error('cannot cast `$expr_type_sym.name` to `$addr$type_sym.name`', + node.pos) } } else if expr_type_sym.kind == .interface_ && type_sym.kind == .interface_ { c.ensure_type_exists(node.typ, node.pos) or {} @@ -5734,7 +5736,7 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { node.expr_type = c.promote_num(node.expr_type, xx) from_type = node.expr_type } - if !c.table.sumtype_has_variant(to_type, from_type) && !to_type.has_flag(.optional) { + if !c.table.sumtype_has_variant(to_type, from_type, false) && !to_type.has_flag(.optional) { c.error('cannot cast `$from_type_sym.name` to `$to_type_sym.name`', node.pos) } } else if mut to_type_sym.info is ast.Alias { diff --git a/vlib/v/checker/tests/sumtype_as_mismatched_type.out b/vlib/v/checker/tests/sumtype_as_mismatched_type.out new file mode 100644 index 00000000000000..589574de34bbc2 --- /dev/null +++ b/vlib/v/checker/tests/sumtype_as_mismatched_type.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/sumtype_as_mismatched_type.vv:5:9: error: cannot cast `Type` to `&int` + 3 | fn main() { + 4 | mut t := Type(123) + 5 | v := t as &int + | ~~ + 6 | t = 456 + 7 | println(v) diff --git a/vlib/v/checker/tests/sumtype_as_mismatched_type.vv b/vlib/v/checker/tests/sumtype_as_mismatched_type.vv new file mode 100644 index 00000000000000..f295b9b44c0b3b --- /dev/null +++ b/vlib/v/checker/tests/sumtype_as_mismatched_type.vv @@ -0,0 +1,8 @@ +type Type = bool | int | string + +fn main() { + mut t := Type(123) + v := t as &int + t = 456 + println(v) +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 198b4a9f709769..c4c90c5e4579e7 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2364,7 +2364,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ unwrapped_expected_type } got_deref_type := if got_is_ptr { unwrapped_got_type.deref() } else { unwrapped_got_type } - if g.table.sumtype_has_variant(expected_deref_type, got_deref_type) { + if g.table.sumtype_has_variant(expected_deref_type, got_deref_type, false) { mut is_already_sum_type := false scope := g.file.scope.innermost(expr.position().pos) if expr is ast.Ident {