1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check nested struct field with required attr (fix #10913) (#17277)

This commit is contained in:
yuyi 2023-02-11 17:22:31 +08:00 committed by GitHub
parent 03be525c82
commit 90591eb813
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 63 additions and 12 deletions

View File

@ -71,7 +71,7 @@ fn todo_del() {}
[typedef] [typedef]
struct C.XSelectionRequestEvent { struct C.XSelectionRequestEvent {
mut: mut:
display &C.Display // Display the event was read from display &C.Display = unsafe { nil } // Display the event was read from
owner Window owner Window
requestor Window requestor Window
selection Atom selection Atom
@ -84,7 +84,7 @@ mut:
struct C.XSelectionEvent { struct C.XSelectionEvent {
mut: mut:
@type int @type int
display &C.Display // Display the event was read from display &C.Display = unsafe { nil } // Display the event was read from
requestor Window requestor Window
selection Atom selection Atom
target Atom target Atom

View File

@ -6,7 +6,6 @@ module http
import strings import strings
// Header represents the key-value pairs in an HTTP header // Header represents the key-value pairs in an HTTP header
[noinit]
pub struct Header { pub struct Header {
mut: mut:
data map[string][]string data map[string][]string

View File

@ -2638,7 +2638,7 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
if node.unresolved { if node.unresolved {
return c.expr(ast.resolve_init(node, c.unwrap_generic(node.typ), c.table)) return c.expr(ast.resolve_init(node, c.unwrap_generic(node.typ), c.table))
} }
return c.struct_init(mut node) return c.struct_init(mut node, false)
} }
ast.TypeNode { ast.TypeNode {
if !c.inside_x_is_type && node.typ.has_flag(.generic) && unsafe { c.table.cur_fn != 0 } if !c.inside_x_is_type && node.typ.has_flag(.generic) && unsafe { c.table.cur_fn != 0 }

View File

@ -254,7 +254,7 @@ fn minify_sort_fn(a &ast.StructField, b &ast.StructField) int {
} }
} }
fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_init bool) ast.Type {
util.timing_start(@METHOD) util.timing_start(@METHOD)
defer { defer {
util.timing_measure_cumulative(@METHOD) util.timing_measure_cumulative(@METHOD)
@ -327,7 +327,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 { if c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0 {
c.table.unwrap_generic_type(node.typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types) c.table.unwrap_generic_type(node.typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types)
} }
if !is_field_zero_struct_init {
c.ensure_type_exists(node.typ, node.pos) or {} c.ensure_type_exists(node.typ, node.pos) or {}
}
type_sym := c.table.sym(node.typ) type_sym := c.table.sym(node.typ)
if !c.inside_unsafe && type_sym.kind == .sum_type { if !c.inside_unsafe && type_sym.kind == .sum_type {
c.note('direct sum type init (`x := SumType{}`) will be removed soon', node.pos) c.note('direct sum type init (`x := SumType{}`) will be removed soon', node.pos)
@ -361,7 +363,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
// allow init structs from generic if they're private except the type is from builtin module // allow init structs from generic if they're private except the type is from builtin module
if !node.has_update_expr && !type_sym.is_pub && type_sym.kind != .placeholder if !node.has_update_expr && !type_sym.is_pub && type_sym.kind != .placeholder
&& type_sym.language != .c && (type_sym.mod != c.mod && !(node.typ.has_flag(.generic) && type_sym.language != .c && (type_sym.mod != c.mod && !(node.typ.has_flag(.generic)
&& type_sym.mod != 'builtin')) { && type_sym.mod != 'builtin')) && !is_field_zero_struct_init {
c.error('type `${type_sym.name}` is private', node.pos) c.error('type `${type_sym.name}` is private', node.pos)
} }
if type_sym.kind == .struct_ { if type_sym.kind == .struct_ {
@ -627,6 +629,14 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
node.pos) node.pos)
} }
} }
if !field.has_default_expr && field.name !in inited_fields && !field.typ.is_ptr()
&& c.table.final_sym(field.typ).kind == .struct_ {
mut zero_struct_init := ast.StructInit{
pos: node.pos
typ: field.typ
}
c.struct_init(mut zero_struct_init, true)
}
} }
// println('>> checked_types.len: $checked_types.len | checked_types: $checked_types | type_sym: $type_sym.name ') // println('>> checked_types.len: $checked_types.len | checked_types: $checked_types | type_sym: $type_sym.name ')
} }

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/nested_struct_with_required_attr_err.vv:13:7: error: field `Egg.name` must be initialized
11 |
12 | fn main() {
13 | f := Foo{}
| ~~~~~
14 | println(f)
15 | }

View File

@ -0,0 +1,15 @@
struct Foo {
bar Bar
}
struct Bar {
egg Egg
}
struct Egg {
name string [required]
}
fn main() {
f := Foo{}
println(f)
}

View File

@ -5,3 +5,9 @@ vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv:9:7: error:
| ~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~
10 | } 10 | }
11 | 11 |
vlib/v/checker/tests/struct_field_generic_struct_unknown_type_err.vv:13:9: error: unknown type `UnknownType`
11 |
12 | fn main() {
13 | _ = MyType {}
| ~~~~~~~~~
14 | }

View File

@ -5,6 +5,13 @@ vlib/v/checker/tests/struct_field_reference_type_err.vv:12:16: warning: referenc
| ~~~~~~~ | ~~~~~~~
13 | ageee: 20 13 | ageee: 20
14 | } 14 | }
vlib/v/checker/tests/struct_field_reference_type_err.vv:12:16: warning: reference field `Duck.age` must be initialized
10 |
11 | fn main() {
12 | mut animal := Animal{
| ~~~~~~~
13 | ageee: 20
14 | }
vlib/v/checker/tests/struct_field_reference_type_err.vv:17:3: error: reference field must be initialized with reference vlib/v/checker/tests/struct_field_reference_type_err.vv:17:3: error: reference field must be initialized with reference
15 | 15 |
16 | animal.duck = Duck{ 16 | animal.duck = Duck{

View File

@ -5,6 +5,13 @@ vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: warning: refer
| ~~~~~~~ | ~~~~~~~
26 | _ := Struct{} 26 | _ := Struct{}
27 | } 27 | }
vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: warning: reference field `ContainsRef.b` must be initialized
23 |
24 | fn main() {
25 | _ := Outer{}
| ~~~~~~~
26 | _ := Struct{}
27 | }
vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: warning: reference field `Outer.c2.b` must be initialized (part of struct `ContainsRef`) vlib/v/checker/tests/struct_ref_fields_uninitialized_err.vv:25:7: warning: reference field `Outer.c2.b` must be initialized (part of struct `ContainsRef`)
23 | 23 |
24 | fn main() { 24 | fn main() {

View File

@ -21,7 +21,7 @@ fn (mut app App) index() vweb.Result {
fn test_send_a_request_to_homepage_expecting_a_csrf_cookie() { fn test_send_a_request_to_homepage_expecting_a_csrf_cookie() {
spawn vweb.run_at(&App{}, vweb.RunParams{ port: sport }) spawn vweb.run_at(&App{}, vweb.RunParams{ port: sport })
time.sleep(500 * time.millisecond) time.sleep(500 * time.millisecond)
res := http.get('http://localhost:${sport}/')? res := http.get('http://localhost:${sport}/')!
if res.header.str().contains('__Host-Csrf-Token') { if res.header.str().contains('__Host-Csrf-Token') {
assert true assert true
} else { } else {