Skip to content

Commit 9335a84

Browse files
authored
parser, checker: check generic struct fields and initialisation (fix #26433) (fix #26436) (#26450)
1 parent a47fb6a commit 9335a84

15 files changed

Lines changed: 58 additions & 23 deletions

File tree

‎vlib/builtin/js/promise.js.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn JS.Promise.race(JS.Array) JS.Promise
1414

1515
// Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
1616
pub struct Promise[T] {
17-
mut:
17+
pub mut:
1818
promise JS.Promise @[noinit]
1919
}
2020

‎vlib/datatypes/doubly_linked_list.v‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ mut:
2121
// of the list while iterating. TODO: use an option
2222
// instead of a pointer to determine it is initialized.
2323
iter &DoublyListIter[T] = unsafe { 0 }
24-
len int
24+
pub mut:
25+
len int
2526
}
2627

2728
// is_empty checks if the linked list is empty

‎vlib/v/checker/checker.v‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ mut:
138138
inside_decl_rhs bool
139139
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
140140
inside_assign bool
141+
is_js_backend bool
141142
// doing_line_info int // a quick single file run when called with v -line-info (contains line nr to inspect)
142143
// doing_line_path string // same, but stores the path being parsed
143144
is_index_assign bool
@@ -185,6 +186,7 @@ pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker {
185186
checker.checker_transformer.skip_array_transform = true
186187
checker.type_resolver = type_resolver.TypeResolver.new(table, checker)
187188
checker.comptime = &checker.type_resolver.info
189+
checker.is_js_backend = checker.pref.backend.is_js()
188190
return checker
189191
}
190192

@@ -2815,7 +2817,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
28152817
c.warn('inline assembly goto is not supported, it will most likely not work',
28162818
stmt.pos)
28172819
}
2818-
if c.pref.backend.is_js() {
2820+
if c.is_js_backend {
28192821
c.error('inline assembly is not supported in the js backend', stmt.pos)
28202822
}
28212823
mut aliases := c.asm_ios(mut stmt.output, mut stmt.scope, true)
@@ -2914,7 +2916,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
29142916
if c.ct_cond_stack.len > 0 {
29152917
node.ct_conds = c.ct_cond_stack.clone()
29162918
}
2917-
if c.pref.backend.is_js() || c.pref.backend == .golang {
2919+
if c.pref.backend == .golang || c.is_js_backend {
29182920
// consider the best way to handle the .go.vv files
29192921
if !c.file.path.ends_with('.js.v') && !c.file.path.ends_with('.go.v')
29202922
&& !c.file.path.ends_with('.go.vv') {
@@ -3729,7 +3731,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
37293731
}
37303732
c.check_any_type(to_type, to_sym, node.pos)
37313733

3732-
if c.pref.backend.is_js() {
3734+
if c.is_js_backend {
37333735
if (to_sym.is_number() && from_sym.name == 'JS.Number')
37343736
|| (to_sym.is_number() && from_sym.name == 'JS.BigInt')
37353737
|| (to_sym.is_string() && from_sym.name == 'JS.String')

‎vlib/v/checker/fn.v‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,7 +1536,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
15361536
}
15371537
}
15381538
c.set_node_expected_arg_types(mut node, func)
1539-
if !c.pref.backend.is_js() && args_len > 0 && func.params.len == 0 {
1539+
if !c.is_js_backend && args_len > 0 && func.params.len == 0 {
15401540
c.error('too many arguments in call to `${func.name}` (non-js backend: ${c.pref.backend})',
15411541
node.pos)
15421542
}
@@ -1925,7 +1925,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
19251925
&& arg_typ !in [ast.voidptr_type, ast.nil_type] && arg_typ.nr_muls() == 0
19261926
&& func.name !in ['isnil', 'ptr_str'] && !func.name.starts_with('json.')
19271927
&& arg_typ_sym.kind !in [.float_literal, .int_literal, .charptr, .function]
1928-
&& !c.pref.backend.is_js() {
1928+
&& !c.is_js_backend {
19291929
c.warn('automatic ${arg_typ_sym.name} referencing/dereferencing into voidptr is deprecated and will be removed soon; use `foo(&x)` instead of `foo(x)`',
19301930
call_arg.pos)
19311931
}
@@ -2209,7 +2209,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
22092209
&& !(left_sym.kind == .alias && left_sym.has_method(method_name)) {
22102210
unaliased_left_type := c.table.unaliased_type(left_type)
22112211
return c.map_builtin_method_call(mut node, unaliased_left_type)
2212-
} else if c.pref.backend.is_js() && left_sym.name.starts_with('Promise[') && node.kind == .wait {
2212+
} else if c.is_js_backend && left_sym.name.starts_with('Promise[') && node.kind == .wait {
22132213
info := left_sym.info as ast.Struct
22142214
if node.args.len > 0 {
22152215
c.error('wait() does not have any arguments', node.args[0].pos)
@@ -2903,7 +2903,7 @@ fn (mut c Checker) spawn_expr(mut node ast.SpawnExpr) ast.Type {
29032903
node.call_expr.left.pos())
29042904
}
29052905

2906-
if c.pref.backend.is_js() {
2906+
if c.is_js_backend {
29072907
return c.table.find_or_register_promise(c.unwrap_generic(ret_type))
29082908
} else {
29092909
return c.table.find_or_register_thread(c.unwrap_generic(ret_type))
@@ -2930,7 +2930,7 @@ fn (mut c Checker) go_expr(mut node ast.GoExpr) ast.Type {
29302930
node.call_expr.left.pos())
29312931
}
29322932

2933-
if c.pref.backend.is_js() {
2933+
if c.is_js_backend {
29342934
return c.table.find_or_register_promise(c.unwrap_generic(ret_type))
29352935
} else {
29362936
return c.table.find_or_register_thread(c.unwrap_generic(ret_type))

‎vlib/v/checker/struct.v‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,6 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
10651065
fn (mut c Checker) check_uninitialized_struct_fields_and_embeds(node ast.StructInit, type_sym ast.TypeSymbol, mut info ast.Struct, mut inited_fields []string) {
10661066
mut fields := c.table.struct_fields(type_sym)
10671067
mut checked_types := []ast.Type{}
1068-
10691068
for i, mut field in fields {
10701069
if field.name in inited_fields {
10711070
if c.mod != type_sym.mod {
@@ -1078,7 +1077,8 @@ fn (mut c Checker) check_uninitialized_struct_fields_and_embeds(node ast.StructI
10781077
} else {
10791078
parts.last()
10801079
}
1081-
if !c.inside_unsafe {
1080+
if !c.inside_unsafe && !(c.is_js_backend
1081+
&& mod_type.starts_with('Promise')) {
10821082
c.error('cannot access private field `${field.name}` on `${mod_type}`',
10831083
init_field.pos)
10841084

‎vlib/v/checker/tests/amod/amod.v‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ pub struct Bcg {
99
x int
1010
}
1111

12+
pub struct Bcg2[T] {
13+
x int
14+
}
15+
1216
@[params]
1317
pub struct FooParams {
1418
bar string
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
vlib/v/checker/tests/modules/module_struct_noinit/src/main.v:9:9: error: struct `mod.Foo` is declared with a `@[noinit]` attribute, so it cannot be initialized with `mod.Foo{}`
2-
7 |
3-
8 | fn default_value[T]() T {
4-
9 | return T{}
1+
vlib/v/checker/tests/modules/module_struct_noinit/src/main.v:12:9: error: struct `mod.Foo` is declared with a `@[noinit]` attribute, so it cannot be initialized with `mod.Foo{}`
2+
10 |
3+
11 | fn default_value[T]() T {
4+
12 | return T{}
55
| ~~~
6-
10 | }
6+
13 | }
7+
vlib/v/checker/tests/modules/module_struct_noinit/src/main.v:12:9: error: struct `mod.Foo2[int]` is declared with a `@[noinit]` attribute, so it cannot be initialized with `mod.Foo2[int]{}`
8+
10 |
9+
11 | fn default_value[T]() T {
10+
12 | return T{}
11+
| ~~~
12+
13 | }

‎vlib/v/checker/tests/modules/module_struct_noinit/src/main.v‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import mod
33
fn main() {
44
dump(default_value[mod.Foo]())
55
println(default_value[mod.Foo]())
6+
7+
dump(default_value[mod.Foo2[int]]())
8+
println(default_value[mod.Foo2[int]]())
69
}
710

811
fn default_value[T]() T {

‎vlib/v/checker/tests/modules/module_struct_noinit/src/mod.v‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ module mod
33
@[noinit]
44
pub struct Foo {
55
}
6+
7+
@[noinit]
8+
pub struct Foo2[T] {
9+
}

‎vlib/v/checker/tests/struct_field_private_err.out‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@ vlib/v/checker/tests/struct_field_private_err.vv:8:2: error: cannot access priva
55
| ~~~~
66
9 | }
77
10 |
8-
vlib/v/checker/tests/struct_field_private_err.vv:11:10: error: cannot access private field `bar` on `amod.FooParams`
9-
9 | }
8+
vlib/v/checker/tests/struct_field_private_err.vv:12:2: error: cannot access private field `x` on `amod.Bcg2[int]`
109
10 |
11-
11 | amod.foo(bar: 'bar')
10+
11 | _ := amod.Bcg2[int]{
11+
12 | x: 0
12+
| ~~~~
13+
13 | }
14+
14 |
15+
vlib/v/checker/tests/struct_field_private_err.vv:15:10: error: cannot access private field `bar` on `amod.FooParams`
16+
13 | }
17+
14 |
18+
15 | amod.foo(bar: 'bar')
1219
| ~~~~~~~~~~

0 commit comments

Comments
 (0)