all: make 0 => unsafe { nil } an error, not a notice

This commit is contained in:
Alexander Medvednikov 2024-10-07 01:54:19 +03:00
parent a2d385aee3
commit 2b52153c14
15 changed files with 26 additions and 33 deletions

View File

@ -6707,16 +6707,16 @@ struct Node {
} }
// Reference fields must be initialized unless an initial value is declared. // Reference fields must be initialized unless an initial value is declared.
// Zero (0) is OK but use with caution, it's a nil pointer. // Nil is OK but use with caution, it's a nil pointer.
foo := Node{ foo := Node{
a: 0 a: unsafe { nil }
} }
bar := Node{ bar := Node{
a: &foo a: &foo
} }
baz := Node{ baz := Node{
a: 0 a: unsafe { nil }
b: 0 b: unsafe { nil }
} }
qux := Node{ qux := Node{
a: &foo a: &foo

View File

@ -51,7 +51,7 @@ and a new scope is created:
import v.ast import v.ast
scope := ast.Scope{ scope := ast.Scope{
parent: 0 parent: unsafe { nil }
} }
``` ```
after that, you can parse your files. after that, you can parse your files.

View File

@ -760,7 +760,7 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
&& !got_type.is_any_kind_of_pointer() && !exp_type.has_flag(.option) && !got_type.is_any_kind_of_pointer() && !exp_type.has_flag(.option)
&& !(init_field.expr is ast.UnsafeExpr && init_field.expr.expr.str() == '0') { && !(init_field.expr is ast.UnsafeExpr && init_field.expr.expr.str() == '0') {
if init_field.expr.str() == '0' { if init_field.expr.str() == '0' {
c.note('assigning `0` to a reference field is only allowed in `unsafe` blocks', c.error('assigning `0` to a reference field is only allowed in `unsafe` blocks',
init_field.pos) init_field.pos)
} else { } else {
c.error('reference field must be initialized with reference', c.error('reference field must be initialized with reference',

View File

@ -1,11 +1,11 @@
vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:6:10: notice: assigning `0` to a reference field is only allowed in `unsafe` blocks vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:6:10: error: assigning `0` to a reference field is only allowed in `unsafe` blocks
4 | 4 |
5 | fn main() { 5 | fn main() {
6 | _ = Foo{0} 6 | _ = Foo{0}
| ^ | ^
7 | _ = Foo{ 7 | _ = Foo{
8 | foo: 0 8 | foo: 0
vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:8:3: notice: assigning `0` to a reference field is only allowed in `unsafe` blocks vlib/v/checker/tests/struct_ref_fields_init_0_err.vv:8:3: error: assigning `0` to a reference field is only allowed in `unsafe` blocks
6 | _ = Foo{0} 6 | _ = Foo{0}
7 | _ = Foo{ 7 | _ = Foo{
8 | foo: 0 8 | foo: 0

View File

@ -3,10 +3,10 @@ vlib/v/parser/tests/invalid_struct_decl_script_err.vv:1:1: notice: script mode s
| ~~~~~ | ~~~~~
2 | 2 |
3 | struct Abc { 3 | struct Abc {
vlib/v/parser/tests/invalid_struct_decl_script_err.vv:3:1: error: all definitions must occur before code in script mode vlib/v/parser/tests/invalid_struct_decl_script_err.vv:3:8: error: all definitions must occur before code in script mode
1 | mynum := 10 1 | mynum := 10
2 | 2 |
3 | struct Abc { 3 | struct Abc {
| ~~~~~~ | ~~~
4 | x int 4 | x int
5 | } 5 | }

View File

@ -41,7 +41,7 @@ fn test_eval() {
vpref := &pref.Preferences{} vpref := &pref.Preferences{}
mut scope := &ast.Scope{ mut scope := &ast.Scope{
start_pos: 0 start_pos: 0
parent: 0 parent: unsafe { nil }
} }
mut stmts := []ast.Stmt{} mut stmts := []ast.Stmt{}
for input in inputs { for input in inputs {

View File

@ -209,7 +209,7 @@ fn test_struct_with_struct_pointer() {
} }
fn test_struct_with_nil() { fn test_struct_with_nil() {
w := Wrapper4{0} w := Wrapper4{unsafe { nil }}
assert '${w}' == 'Wrapper4{\n foo: &nil\n}' assert '${w}' == 'Wrapper4{\n foo: &nil\n}'
assert w.str() == 'Wrapper4{\n foo: &nil\n}' assert w.str() == 'Wrapper4{\n foo: &nil\n}'
} }

View File

@ -60,14 +60,14 @@ mut:
} }
fn test_stack_circular_elem_auto_str() { fn test_stack_circular_elem_auto_str() {
mut elem := Circular{0} mut elem := Circular{unsafe { nil }}
elem.next = &elem elem.next = &elem
s := '${elem}'.replace('\n', '|') s := '${elem}'.replace('\n', '|')
assert s == 'Circular{| next: &<circular>|}' assert s == 'Circular{| next: &<circular>|}'
} }
fn test_heap_circular_elem_auto_str() { fn test_heap_circular_elem_auto_str() {
mut elem := &Circular{0} mut elem := &Circular{unsafe { nil }}
elem.next = elem elem.next = elem
s := '${elem}'.replace('\n', '|') s := '${elem}'.replace('\n', '|')
assert s == '&Circular{| next: &<circular>|}' assert s == '&Circular{| next: &<circular>|}'

View File

@ -1,13 +1,7 @@
struct Node { struct Node {
val int val int
left &Node left &Node = unsafe { nil }
right &Node right &Node = unsafe { nil }
}
fn test_string_ref_struct() {
n := Node{123, 0, 0}
println(n.left)
assert '${n.left}' == '&nil'
} }
fn test_string_ref_struct_with_nil_instead_of_0() { fn test_string_ref_struct_with_nil_instead_of_0() {

View File

@ -38,7 +38,7 @@ fn new[T]() &Node[T] {
} }
fn (mut n Node[T]) add(val T) { fn (mut n Node[T]) add(val T) {
node := &Node[T]{val, 0} node := &Node[T]{val, unsafe { nil }}
n.next = node n.next = node
} }

View File

@ -14,8 +14,8 @@ pub fn list_new[T]() List[T] {
} }
pub fn (mut l List[T]) add(value T) { pub fn (mut l List[T]) add(value T) {
mut node := &ListNode[T]{value, 0} mut node := &ListNode[T]{value, unsafe { nil }}
if unsafe { l.head == 0 } { if unsafe { l.head == nil } {
l.head = node l.head = node
} else { } else {
node.next = l.head node.next = l.head

View File

@ -136,8 +136,8 @@ fn (mut node ListNode[T]) test() &ListNode[T] {
} }
fn test_generics_return_generic_struct_field() { fn test_generics_return_generic_struct_field() {
mut node1 := &ListNode[int]{100, 0} mut node1 := &ListNode[int]{100, unsafe { nil }}
mut node2 := &ListNode[int]{200, 0} mut node2 := &ListNode[int]{200, unsafe { nil }}
node1.next = node2 node1.next = node2
ret := node1.test() ret := node1.test()
println(ret) println(ret)

View File

@ -1,13 +1,12 @@
struct Node[T] { struct Node[T] {
mut: mut:
val T val T
next &Node[T] next &Node[T] = unsafe { nil }
} }
fn make_node[T](val []T) Node[T] { fn make_node[T](val []T) Node[T] {
return Node[T]{ return Node[T]{
val: val[0] val: val[0]
next: 0
} }
} }

View File

@ -15,7 +15,7 @@ fn create[T](arr []T) &List[T] {
assert arr.len > 0 assert arr.len > 0
mut n := &ListNode[T]{ mut n := &ListNode[T]{
val: arr[0] val: arr[0]
next: 0 next: unsafe { nil }
} }
mut l := &List[T]{ mut l := &List[T]{
first: n first: n

View File

@ -50,7 +50,7 @@ fn test_sum_type_match() {
baz: &IntAndStr{ baz: &IntAndStr{
foo: 3 foo: 3
bar: 'hello' bar: 'hello'
baz: 0 baz: unsafe { nil }
} }
}) == 'This is the string representation of "5_hi_hello"' }) == 'This is the string representation of "5_hi_hello"'
assert as_string(true) == 'This is the string representation of "true"' assert as_string(true) == 'This is the string representation of "true"'
@ -532,7 +532,7 @@ fn sumtype_match_with_string_interpolation(code int) string {
baz: &IntAndStr{ baz: &IntAndStr{
foo: 3 foo: 3
bar: 'hello' bar: 'hello'
baz: 0 baz: unsafe { nil }
} }
}) })
match bar { match bar {