From 48c256bf3b81c171389e65c441d6512f41c3cf91 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Mon, 5 Jun 2023 19:14:55 +0530 Subject: [PATCH] checker: allow casted `enum val` and `const` as fixed array size (#18321) --- vlib/v/ast/table.v | 37 +++++++++++++++++++ vlib/v/checker/comptime.v | 7 ++-- vlib/v/checker/containers.v | 28 ++++++++++++++ ...d_enum_val_as_size_for_fixed_array_err.out | 13 +++++++ ...ed_enum_val_as_size_for_fixed_array_err.vv | 14 +++++++ ...wrong_type_casted_fixed_array_size_err.out | 13 +++++++ .../wrong_type_casted_fixed_array_size_err.vv | 14 +++++++ vlib/v/tests/array_test.v | 23 ++++++++++++ 8 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.out create mode 100644 vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv create mode 100644 vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.out create mode 100644 vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 770ab6585b..1211625623 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -372,6 +372,43 @@ pub fn (t &Table) find_method_with_embeds(sym &TypeSymbol, method_name string) ! } } +// find_enum_field_val finds the int value from the enum name and enum field +pub fn (t &Table) find_enum_field_val(name string, field_ string) i64 { + mut val := i64(0) + enum_decl := t.enum_decls[name] + mut enum_vals := []i64{} + for field in enum_decl.fields { + if field.name == field_ { + if field.has_expr { + if field.expr is IntegerLiteral { + val = field.expr.val.i64() + break + } + } else { + if enum_vals.len > 0 { + val = enum_vals.last() + 1 + } else { + val = 0 + } + break + } + } else { + if field.has_expr { + if field.expr is IntegerLiteral { + enum_vals << field.expr.val.i64() + } + } else { + if enum_vals.len > 0 { + enum_vals << enum_vals.last() + 1 + } else { + enum_vals << 0 + } + } + } + } + return val +} + pub fn (t &Table) get_embed_methods(sym &TypeSymbol) []Fn { mut methods := []Fn{} if sym.info is Struct { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index e8f95aa410..94c2b17b88 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -270,10 +270,9 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp ast.ParExpr { return c.eval_comptime_const_expr(expr.expr, nlevel + 1) } - // ast.EnumVal { - // c.note('>>>>>>>> expr: $expr', expr.pos) - // return expr.val.i64() - // } + ast.EnumVal { + return c.table.find_enum_field_val(expr.enum_name, expr.val) + } ast.SizeOf { s, _ := c.table.type_size(expr.typ) return s diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index 52f8b588b9..404da53783 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -241,8 +241,36 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { ast.IntegerLiteral { fixed_size = init_expr.val.int() } + ast.CastExpr { + if !init_expr.typ.is_pure_int() { + c.error('only integer types are allowed', init_expr.pos) + } + match init_expr.expr { + ast.IntegerLiteral { + fixed_size = init_expr.expr.val.int() + } + ast.EnumVal { + fixed_size = c.table.find_enum_field_val(init_expr.expr.enum_name, + init_expr.expr.val) + } + else {} + } + } + ast.EnumVal { + c.error('${init_expr.enum_name}.${init_expr.val} has to be casted to integer to be used as size', + init_expr.pos) + } ast.Ident { if init_expr.obj is ast.ConstField { + if init_expr.obj.expr is ast.EnumVal { + c.error('${init_expr.obj.expr.enum_name}.${init_expr.obj.expr.val} has to be casted to integer to be used as size', + init_expr.pos) + } + if init_expr.obj.expr is ast.CastExpr { + if !init_expr.obj.expr.typ.is_pure_int() { + c.error('only integer types are allowed', init_expr.pos) + } + } if comptime_value := c.eval_comptime_const_expr(init_expr.obj.expr, 0) { diff --git a/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.out b/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.out new file mode 100644 index 0000000000..177bfd6429 --- /dev/null +++ b/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv:10:7: error: Foo.first has to be casted to integer to be used as size + 8 | } + 9 | + 10 | a := [b]int{} + | ^ + 11 | println(a) + 12 | +vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv:13:7: error: Foo.second has to be casted to integer to be used as size + 11 | println(a) + 12 | + 13 | c := [Foo.second]int{} + | ~~~~~~~~~~ + 14 | println(c) diff --git a/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv b/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv new file mode 100644 index 0000000000..b15cba67d9 --- /dev/null +++ b/vlib/v/checker/tests/uncasted_enum_val_as_size_for_fixed_array_err.vv @@ -0,0 +1,14 @@ +const b = Foo.first + +enum Foo { + first = 5 + second + + _end = 9 +} + +a := [b]int{} +println(a) + +c := [Foo.second]int{} +println(c) diff --git a/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.out b/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.out new file mode 100644 index 0000000000..68b4b0c9bc --- /dev/null +++ b/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.out @@ -0,0 +1,13 @@ +vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv:10:7: error: only integer types are allowed + 8 | } + 9 | + 10 | a := [b]int{} + | ^ + 11 | println(a) + 12 | +vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv:13:7: error: only integer types are allowed + 11 | println(a) + 12 | + 13 | c := [f32(Foo.first)]int{} + | ~~~~~~~~~~~~~~ + 14 | println(c) diff --git a/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv b/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv new file mode 100644 index 0000000000..728c7c131a --- /dev/null +++ b/vlib/v/checker/tests/wrong_type_casted_fixed_array_size_err.vv @@ -0,0 +1,14 @@ +const b = f32(3) + +enum Foo { + first = 5 + second + + _end = 9 +} + +a := [b]int{} +println(a) + +c := [f32(Foo.first)]int{} +println(c) diff --git a/vlib/v/tests/array_test.v b/vlib/v/tests/array_test.v index 0fb01fcf01..c1a795735c 100644 --- a/vlib/v/tests/array_test.v +++ b/vlib/v/tests/array_test.v @@ -1,3 +1,26 @@ +enum Foo { + zero + first = 1 + third = 3 + fourth +} + +const enum_size = int(Foo.third) + +fn test_enum_val_as_fixed_array_size() { + arr1 := [int(Foo.first)]int{} + assert arr1 == [0]! + + // TODO check why it fails on MSVC + $if !msvc { + arr2 := [enum_size]int{} + assert arr2 == [0, 0, 0]! + } + + arr3 := [int(Foo.fourth)]int{} + assert arr3 == [0, 0, 0, 0]! +} + fn test_for_in_array_named_array() { mut array := [1] for elem in array {