From 65f12f32178ed534219188fb122f6df332386b4b Mon Sep 17 00:00:00 2001 From: spaceface Date: Wed, 15 Dec 2021 15:58:25 +0100 Subject: [PATCH] checker: fix invalid cast warning for flag enums (#12848) --- vlib/v/checker/checker.v | 32 ++++++++++++++++++------------ vlib/v/checker/tests/enum_cast.out | 31 ++++++++++++++++++++++++----- vlib/v/checker/tests/enum_cast.vv | 10 +++++++++- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index d3ff5ed1c3..7232b045bb 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3592,24 +3592,30 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { if enum_decl := c.table.enum_decls[to_type_sym.name] { mut in_range := false - mut enum_val := 0 + if enum_decl.is_flag { + // if a flag enum has 4 variants, the maximum possible value would have all 4 flags set (0b1111) + max_val := (1 << enum_decl.fields.len) - 1 + in_range = node_val >= 0 && node_val <= max_val + } else { + mut enum_val := 0 - for enum_field in enum_decl.fields { - // check if the field of the enum value is an integer literal - if enum_field.expr is ast.IntegerLiteral { - enum_val = enum_field.expr.val.int() + for enum_field in enum_decl.fields { + // check if the field of the enum value is an integer literal + if enum_field.expr is ast.IntegerLiteral { + enum_val = enum_field.expr.val.int() + } + + if node_val == enum_val { + in_range = true + break + } + + enum_val += 1 } - - if node_val == enum_val { - in_range = true - break - } - - enum_val += 1 } if !in_range { - c.warn('$node_val does not represents a value of enum $enum_typ_name', + c.warn('$node_val does not represent a value of enum $enum_typ_name', node.pos) } } diff --git a/vlib/v/checker/tests/enum_cast.out b/vlib/v/checker/tests/enum_cast.out index 053fe1b470..c71c4acf08 100644 --- a/vlib/v/checker/tests/enum_cast.out +++ b/vlib/v/checker/tests/enum_cast.out @@ -1,6 +1,27 @@ -vlib/v/checker/tests/enum_cast.vv:6:13: error: 12 does not represents a value of enum Color - 4 | println(Color(0)) - 5 | println(Color(10)) - 6 | println(Color(12)) +vlib/v/checker/tests/enum_cast.vv:9:13: error: 12 does not represent a value of enum Color + 7 | println(Color(0)) + 8 | println(Color(10)) + 9 | println(Color(12)) | ~~~~~~~~~ - 7 | } + 10 | println(Color(-10)) + 11 | +vlib/v/checker/tests/enum_cast.vv:10:13: error: -10 does not represent a value of enum Color + 8 | println(Color(10)) + 9 | println(Color(12)) + 10 | println(Color(-10)) + | ~~~~~~~~~~ + 11 | + 12 | println(Permissions(0b101)) +vlib/v/checker/tests/enum_cast.vv:13:13: error: 10 does not represent a value of enum Permissions + 11 | + 12 | println(Permissions(0b101)) + 13 | println(Permissions(0b1010)) + | ~~~~~~~~~~~~~~~~~~~ + 14 | println(Permissions(-1)) + 15 | } +vlib/v/checker/tests/enum_cast.vv:14:13: error: -1 does not represent a value of enum Permissions + 12 | println(Permissions(0b101)) + 13 | println(Permissions(0b1010)) + 14 | println(Permissions(-1)) + | ~~~~~~~~~~~~~~~ + 15 | } diff --git a/vlib/v/checker/tests/enum_cast.vv b/vlib/v/checker/tests/enum_cast.vv index 40e9ec7e84..056d5bd9ee 100644 --- a/vlib/v/checker/tests/enum_cast.vv +++ b/vlib/v/checker/tests/enum_cast.vv @@ -1,7 +1,15 @@ enum Color { red green = 10 blue } +[flag] +enum Permissions { read write execute } + fn main() { println(Color(0)) println(Color(10)) println(Color(12)) -} \ No newline at end of file + println(Color(-10)) + + println(Permissions(0b101)) + println(Permissions(0b1010)) + println(Permissions(-1)) +}