Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checker: fix and cleanup uninitialized checks for container elements when has len(fix #20272) #20279

Merged
merged 2 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 32 additions & 40 deletions vlib/v/checker/containers.v
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import v.token

fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
mut elem_type := ast.void_type
unwrap_elem_type := c.unwrap_generic(node.elem_type)
// `x := []string{}` (the type was set in the parser)
if node.typ != ast.void_type {
if node.elem_type != 0 {
Expand Down Expand Up @@ -76,14 +77,13 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
if len_typ.has_flag(.option) {
c.error('cannot use unwrapped Option as length', node.len_expr.pos())
}
if node.has_len && !node.has_init {
elem_type_sym := c.table.sym(node.elem_type)
if elem_type_sym.kind == .interface_ {
c.error('cannot instantiate an array of interfaces without also giving a default `init:` value',
node.len_expr.pos())
// check &int{}, interface, sum_type initialized
if !node.has_init {
c.check_elements_initialized(unwrap_elem_type) or {
c.warn('${err.msg()}, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)',
node.pos)
}
}
c.ensure_sumtype_array_has_default_value(node)
}
if node.has_cap {
cap_typ := c.check_expr_opt_call(node.cap_expr, c.expr(mut node.cap_expr))
Expand All @@ -97,26 +97,21 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
c.error('generic struct cannot be used in non-generic function', node.pos)
}

// `&int{}` check
if node.has_len && !c.check_elements_ref_containers_initialized(node.elem_type) {
c.warn('arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`)',
node.pos)
}
// `&Struct{} check
if node.has_len {
c.check_elements_ref_fields_initialized(node.elem_type, node.pos)
c.check_elements_ref_fields_initialized(unwrap_elem_type, node.pos)
}
return node.typ
}

if node.is_fixed {
c.ensure_sumtype_array_has_default_value(node)
c.ensure_type_exists(node.elem_type, node.elem_type_pos)
if !c.is_builtin_mod && !c.check_elements_ref_containers_initialized(node.elem_type) {
c.warn('fixed arrays of references need to be initialized right away (unless inside `unsafe`)',
node.pos)
if !c.is_builtin_mod {
c.check_elements_initialized(unwrap_elem_type) or {
c.warn('fixed ${err.msg()} (unless inside `unsafe`)', node.pos)
}
}
c.check_elements_ref_fields_initialized(node.elem_type, node.pos)
c.check_elements_ref_fields_initialized(unwrap_elem_type, node.pos)
}
// `a = []`
if node.exprs.len == 0 {
Expand Down Expand Up @@ -351,13 +346,6 @@ fn (mut c Checker) check_array_init_para_type(para string, mut expr ast.Expr, po
}
}

fn (mut c Checker) ensure_sumtype_array_has_default_value(node ast.ArrayInit) {
sym := c.table.sym(node.elem_type)
if sym.kind == .sum_type && !node.has_init {
c.error('cannot initialize sum type array without default value', node.pos)
}
}

fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
// `map = {}`
if node.keys.len == 0 && node.vals.len == 0 && node.typ == 0 {
Expand Down Expand Up @@ -574,42 +562,46 @@ fn (mut c Checker) do_check_elements_ref_fields_initialized(sym &ast.TypeSymbol,
}
}

// check the element, and its children for ref uninitialized containers
fn (mut c Checker) check_elements_ref_containers_initialized(typ ast.Type) bool {
const err_ref_uninitialized = error('arrays of references need to be initialized right away')
const err_interface_uninitialized = error('arrays of interfaces need to be initialized right away')
const err_sumtype_uninitialized = error('arrays of sumtypes need to be initialized right away')

// check the element, and its children for `ref/interface/sumtype` initialized
fn (mut c Checker) check_elements_initialized(typ ast.Type) ! {
if typ == 0 || c.inside_unsafe {
return true
return
}
if typ.is_any_kind_of_pointer() {
return false
return checker.err_ref_uninitialized
}
sym := c.table.sym(typ)
if sym.kind == .interface_ {
return checker.err_interface_uninitialized
} else if sym.kind == .sum_type {
return checker.err_sumtype_uninitialized
}

match sym.info {
ast.Array {
elem_type := sym.info.elem_type
if elem_type.is_any_kind_of_pointer() {
return false
}
return c.check_elements_ref_containers_initialized(elem_type)
return c.check_elements_initialized(elem_type)
}
ast.ArrayFixed {
elem_type := sym.info.elem_type
if elem_type.is_any_kind_of_pointer() && !c.is_builtin_mod {
return false
if !c.is_builtin_mod {
return c.check_elements_initialized(elem_type)
}
return c.check_elements_ref_containers_initialized(elem_type)
}
ast.Map {
value_type := sym.info.value_type
if value_type.is_any_kind_of_pointer() && !c.is_builtin_mod {
return false
if !c.is_builtin_mod {
return c.check_elements_initialized(value_type)
}
return c.check_elements_ref_containers_initialized(value_type)
}
ast.Alias {
parent_type := sym.info.parent_type
return c.check_elements_ref_containers_initialized(parent_type)
return c.check_elements_initialized(parent_type)
}
else {}
}
return true
}

This file was deleted.

This file was deleted.

70 changes: 70 additions & 0 deletions vlib/v/checker/tests/array_init_without_init_value_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
vlib/v/checker/tests/array_init_without_init_value_err.vv:5:7: warning: arrays of sumtypes need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
3 |
4 | fn main_sum_type() {
5 | a := []Foo{len: 10}
| ~~~~~~
6 | println(a)
7 | fixed_a := [10]Foo{}
vlib/v/checker/tests/array_init_without_init_value_err.vv:7:13: warning: fixed arrays of sumtypes need to be initialized right away (unless inside `unsafe`)
5 | a := []Foo{len: 10}
6 | println(a)
7 | fixed_a := [10]Foo{}
| ~~~~~~~~~
8 | println(fixed_a)
9 | }
vlib/v/checker/tests/array_init_without_init_value_err.vv:20:11: warning: arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
18 | // test references uninitialized.
19 | fn main_ref() {
20 | println(*[]&int{len: 1}[0])
| ~~~~~~~
21 | println([1]&int{})
22 | _ = [][1]&int{len: 1}[0][0]
vlib/v/checker/tests/array_init_without_init_value_err.vv:21:10: warning: fixed arrays of references need to be initialized right away (unless inside `unsafe`)
19 | fn main_ref() {
20 | println(*[]&int{len: 1}[0])
21 | println([1]&int{})
| ~~~~~~~~~
22 | _ = [][1]&int{len: 1}[0][0]
23 | _ = []map[int]&int{len: 1}
vlib/v/checker/tests/array_init_without_init_value_err.vv:22:6: warning: arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
20 | println(*[]&int{len: 1}[0])
21 | println([1]&int{})
22 | _ = [][1]&int{len: 1}[0][0]
| ~~~~~~~~~~
23 | _ = []map[int]&int{len: 1}
24 | }
vlib/v/checker/tests/array_init_without_init_value_err.vv:23:6: warning: arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
21 | println([1]&int{})
22 | _ = [][1]&int{len: 1}[0][0]
23 | _ = []map[int]&int{len: 1}
| ~~~~~~~~~~~~~~~
24 | }
25 |
vlib/v/checker/tests/array_init_without_init_value_err.vv:40:22: warning: arrays of interfaces need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
38 |
39 | fn main_interface() {
40 | mut parsed_lines := []MObject{len: 9}
| ~~~~~~~~~~
41 | println(parsed_lines)
42 | }
vlib/v/checker/tests/array_init_without_init_value_err.vv:12:7: warning: arrays of sumtypes need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
10 |
11 | fn main_sum_type_2[T]() {
12 | a := []T{len: 10}
| ~~~~
13 | println(a)
14 | fixed_a := [10]T{}
vlib/v/checker/tests/array_init_without_init_value_err.vv:14:13: warning: fixed arrays of sumtypes need to be initialized right away (unless inside `unsafe`)
12 | a := []T{len: 10}
13 | println(a)
14 | fixed_a := [10]T{}
| ~~~~~~~
15 | println(fixed_a)
16 | }
vlib/v/checker/tests/array_init_without_init_value_err.vv:45:22: warning: arrays of interfaces need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
43 |
44 | fn main_interface_2[T]() {
45 | mut parsed_lines := []T{len: 9}
| ~~~~
46 | println(parsed_lines)
47 | }
57 changes: 57 additions & 0 deletions vlib/v/checker/tests/array_init_without_init_value_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// test sum_types uninitialized.
type Foo = int | string

fn main_sum_type() {
a := []Foo{len: 10}
println(a)
fixed_a := [10]Foo{}
println(fixed_a)
}

fn main_sum_type_2[T]() {
a := []T{len: 10}
println(a)
fixed_a := [10]T{}
println(fixed_a)
}

// test references uninitialized.
fn main_ref() {
println(*[]&int{len: 1}[0])
println([1]&int{})
_ = [][1]&int{len: 1}[0][0]
_ = []map[int]&int{len: 1}
}

// test interfaces uninitialized.
interface MObject {
give_string() string
}

struct LeStruct {
le_string string
}

fn (a LeStruct) give_string() string {
return 'V'
}

fn main_interface() {
mut parsed_lines := []MObject{len: 9}
println(parsed_lines)
}

fn main_interface_2[T]() {
mut parsed_lines := []T{len: 9}
println(parsed_lines)
}

fn main() {
main_sum_type()
main_sum_type_2[Foo]()

main_ref()

main_interface()
main_interface_2[MObject]()
}

This file was deleted.

16 changes: 0 additions & 16 deletions vlib/v/checker/tests/array_of_interfaces_with_len_without_init.vv

This file was deleted.

27 changes: 0 additions & 27 deletions vlib/v/checker/tests/ptr_array_init.out

This file was deleted.

6 changes: 0 additions & 6 deletions vlib/v/checker/tests/ptr_array_init.vv

This file was deleted.

2 changes: 1 addition & 1 deletion vlib/v/checker/tests/shared_element_lock.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vlib/v/checker/tests/shared_element_lock.vv:43:11: warning: arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`)
vlib/v/checker/tests/shared_element_lock.vv:43:11: warning: arrays of references need to be initialized right away, therefore `len:` cannot be used (unless inside `unsafe`, or if you also use `init:`)
41 | shared g := Pro{}
42 | g.pers.age = 42
43 | mut h := []shared Pro{len: 3}
Expand Down
Loading