From e736ecaadde94cb5b7d69714c018e0a9a5d7cb27 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Tue, 7 Nov 2023 16:30:58 -0300 Subject: [PATCH] checker: avoid nil assign to option var (#19746) --- vlib/v/checker/assign.v | 7 ++++ vlib/v/checker/struct.v | 3 ++ vlib/v/checker/tests/nil_to_option_err.out | 34 +++++++++++++++++++ vlib/v/checker/tests/nil_to_option_err.vv | 12 +++++++ .../comptime_for_in_fields_FieldData_test.v | 6 ++-- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/nil_to_option_err.out create mode 100644 vlib/v/checker/tests/nil_to_option_err.vv diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index ac40e3fcf818d5..c58853a5b565a6 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -386,6 +386,10 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { c.error('duplicate of an import symbol `${left.name}`', left.pos) } } + if node.op == .assign && left_type.has_flag(.option) && right is ast.UnsafeExpr + && right.expr.is_nil() { + c.error('cannot assign `nil` to option value', right.pos()) + } } } ast.PrefixExpr { @@ -424,6 +428,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } } } + if left_type.has_flag(.option) && right is ast.UnsafeExpr && right.expr.is_nil() { + c.error('cannot assign `nil` to option value', right.pos()) + } } else { if mut left is ast.IndexExpr { diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 02e12e19c4c36e..86065137aea494 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -205,6 +205,9 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { c.warn('unnecessary default value of `none`: struct fields are zeroed by default', field.default_expr.pos) } + if field.typ.has_flag(.option) && field.default_expr.is_nil() { + c.error('cannot assign `nil` to option value', field.default_expr.pos()) + } continue } if field.typ in ast.unsigned_integer_type_idxs { diff --git a/vlib/v/checker/tests/nil_to_option_err.out b/vlib/v/checker/tests/nil_to_option_err.out new file mode 100644 index 00000000000000..218d40a754f917 --- /dev/null +++ b/vlib/v/checker/tests/nil_to_option_err.out @@ -0,0 +1,34 @@ +vlib/v/checker/tests/nil_to_option_err.vv:8:7: warning: cannot assign a reference to a value (this will be an error soon) left=int false right=nil true ptr=false + 6 | fn main() { + 7 | mut a := ?int(none) + 8 | a = unsafe { nil } + | ^ + 9 | + 10 | mut b := Test{} +vlib/v/checker/tests/nil_to_option_err.vv:7:9: warning: unused variable: `a` + 5 | + 6 | fn main() { + 7 | mut a := ?int(none) + | ^ + 8 | a = unsafe { nil } + 9 | +vlib/v/checker/tests/nil_to_option_err.vv:3:7: error: cannot assign `nil` to a non-pointer field + 1 | struct Test { + 2 | mut: + 3 | a ?int = unsafe { nil } + | ~~~~ + 4 | } + 5 | +vlib/v/checker/tests/nil_to_option_err.vv:8:9: error: cannot assign `nil` to option value + 6 | fn main() { + 7 | mut a := ?int(none) + 8 | a = unsafe { nil } + | ~~~~~~ + 9 | + 10 | mut b := Test{} +vlib/v/checker/tests/nil_to_option_err.vv:11:11: error: cannot assign `nil` to option value + 9 | + 10 | mut b := Test{} + 11 | b.a = unsafe { nil } + | ~~~~~~ + 12 | } diff --git a/vlib/v/checker/tests/nil_to_option_err.vv b/vlib/v/checker/tests/nil_to_option_err.vv new file mode 100644 index 00000000000000..e84e7e5509a22f --- /dev/null +++ b/vlib/v/checker/tests/nil_to_option_err.vv @@ -0,0 +1,12 @@ +struct Test { +mut: + a ?int = unsafe { nil } +} + +fn main() { + mut a := ?int(none) + a = unsafe { nil } + + mut b := Test{} + b.a = unsafe { nil } +} \ No newline at end of file diff --git a/vlib/v/tests/comptime_for_in_fields_FieldData_test.v b/vlib/v/tests/comptime_for_in_fields_FieldData_test.v index 8c9451db6c0723..f0d6f3baf88b86 100644 --- a/vlib/v/tests/comptime_for_in_fields_FieldData_test.v +++ b/vlib/v/tests/comptime_for_in_fields_FieldData_test.v @@ -33,9 +33,9 @@ struct Complex { o_ch_i ?chan int = chan int{cap: 10} o_my_alias ?MyInt = 123 // o_atomic_i ?atomic int // TODO: cgen error, but should be probably a checker one, since option atomics do not make sense - o_pointer1_i ?&int = unsafe { nil } - o_pointer2_i ?&&int = unsafe { nil } - o_pointer3_i ?&&&int = unsafe { nil } + o_pointer1_i ?&int + o_pointer2_i ?&&int + o_pointer3_i ?&&&int // o_array_i ?[]int o_map_i ?map[int]int