Skip to content

Commit

Permalink
checker: avoid nil assign to option var (vlang#19746)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Nov 7, 2023
1 parent 09f3e1e commit e736eca
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 3 deletions.
7 changes: 7 additions & 0 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/checker/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
34 changes: 34 additions & 0 deletions vlib/v/checker/tests/nil_to_option_err.out
Original file line number Diff line number Diff line change
@@ -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 | }
12 changes: 12 additions & 0 deletions vlib/v/checker/tests/nil_to_option_err.vv
Original file line number Diff line number Diff line change
@@ -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 }
}
6 changes: 3 additions & 3 deletions vlib/v/tests/comptime_for_in_fields_FieldData_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e736eca

Please sign in to comment.