Skip to content

Commit

Permalink
checker: add support for deprecation messages for structs and struct …
Browse files Browse the repository at this point in the history
…fields (#21017)
  • Loading branch information
ttytm committed Mar 14, 2024
1 parent 0a9d1f9 commit 9a0435d
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 12 deletions.
43 changes: 36 additions & 7 deletions vlib/v/checker/struct.v
Expand Up @@ -483,10 +483,20 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
&& type_sym.mod != 'builtin')) && !is_field_zero_struct_init {
c.error('type `${type_sym.name}` is private', node.pos)
}
if type_sym.info is ast.Struct && type_sym.mod != c.mod
&& type_sym.info.attrs.contains('noinit') {
c.error('struct `${type_sym.name}` is declared with a `@[noinit]` attribute, so ' +
'it cannot be initialized with `${type_sym.name}{}`', node.pos)
if type_sym.info is ast.Struct && type_sym.mod != c.mod {
for attr in type_sym.info.attrs {
match attr.name {
'noinit' {
c.error(
'struct `${type_sym.name}` is declared with a `@[noinit]` attribute, so ' +
'it cannot be initialized with `${type_sym.name}{}`', node.pos)
}
'deprecated' {
c.deprecate('struct', type_sym.name, type_sym.info.attrs, node.pos)
}
else {}
}
}
}
if type_sym.name.len == 1 && c.table.cur_fn != unsafe { nil }
&& c.table.cur_fn.generic_names.len == 0 {
Expand All @@ -506,9 +516,20 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
sym := c.table.sym(c.unwrap_generic(node.typ))
if sym.info is ast.Struct {
if sym.mod != c.mod && sym.info.attrs.contains('noinit') {
c.error('struct `${sym.name}` is declared with a `@[noinit]` attribute, so ' +
'it cannot be initialized with `${sym.name}{}`', node.pos)
if sym.mod != c.mod {
for attr in sym.info.attrs {
match attr.name {
'noinit' {
c.error(
'struct `${sym.name}` is declared with a `@[noinit]` attribute, so ' +
'it cannot be initialized with `${sym.name}{}`', node.pos)
}
'deprecated' {
c.deprecate('struct', sym.name, sym.info.attrs, node.pos)
}
else {}
}
}
}
if node.no_keys && node.init_fields.len != sym.info.fields.len {
fname := if sym.info.fields.len != 1 { 'fields' } else { 'field' }
Expand Down Expand Up @@ -742,6 +763,14 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',

for i, mut field in fields {
if field.name in inited_fields {
if c.mod != type_sym.mod && field.is_deprecated {
for init_field in node.init_fields {
if field.name == init_field.name {
c.deprecate('field', field.name, field.attrs, init_field.pos)
break
}
}
}
continue
}
sym := c.table.sym(field.typ)
Expand Down
3 changes: 0 additions & 3 deletions vlib/v/checker/tests/.gitignore
@@ -1,5 +1,2 @@
*.v
*.c
require_or_block_sumtype_map.err
!*_test.v
!modules/**/*.v
2 changes: 1 addition & 1 deletion vlib/v/checker/tests/field_deprecations.vv
@@ -1,4 +1,4 @@
import v.checker.tests.module_with_structs_with_deprecated_fields as m
import v.checker.tests.module_with_deprecated_structs as m

struct Abc {
mut:
Expand Down
@@ -1,4 +1,4 @@
module module_with_structs_with_deprecated_fields
module module_with_deprecated_structs

pub struct Xyz {
pub mut:
Expand All @@ -8,14 +8,26 @@ pub mut:
d int @[deprecated: 'd use Xyz.a instead'; deprecated_after: '2999-03-01']
}

@[deprecated: 'use New instead']
@[deprecated_after: '2021-03-01']
pub struct Old {}

@[deprecated: 'use Future instead']
@[deprecated_after: '2999-03-01']
pub struct Present {}

fn some_internal_function() {
mut x := Xyz{} // initialisation; no error
mut o := Old{}
mut p := Present{}

// reads:
dump(x.a) // no error
dump(x.b) // no error internally
dump(x.c) // no error internally
dump(x.d) // no error internally
dump(o) // no error internally
dump(p) // no error internally

// writes:
x.a = 1 // no error
Expand Down
35 changes: 35 additions & 0 deletions vlib/v/checker/tests/struct_init_deprecations.out
@@ -0,0 +1,35 @@
vlib/v/checker/tests/struct_init_deprecations.vv:5:9: notice: struct `v.checker.tests.module_with_deprecated_structs.Present` will be deprecated after 2999-03-01, and will become an error after 2999-08-28; use Future instead
3 | fn init_deprecated_structs() {
4 | o := m.Old{}
5 | p := m.Present{}
| ~~~~~~~~~
6 | dump(o)
7 | dump(p)
vlib/v/checker/tests/struct_init_deprecations.vv:15:3: notice: field `d` will be deprecated after 2999-03-01, and will become an error after 2999-08-28; d use Xyz.a instead
13 | b: 1
14 | c: 2
15 | d: 3
| ~~~~
16 | }
17 | dump(x)
vlib/v/checker/tests/struct_init_deprecations.vv:13:3: warning: field `b` has been deprecated
11 | x := m.Xyz{
12 | a: 0
13 | b: 1
| ~~~~
14 | c: 2
15 | d: 3
vlib/v/checker/tests/struct_init_deprecations.vv:4:9: error: struct `v.checker.tests.module_with_deprecated_structs.Old` has been deprecated since 2021-03-01; use New instead
2 |
3 | fn init_deprecated_structs() {
4 | o := m.Old{}
| ~~~~~
5 | p := m.Present{}
6 | dump(o)
vlib/v/checker/tests/struct_init_deprecations.vv:14:3: error: field `c` has been deprecated since 2021-03-01; c use Xyz.a instead
12 | a: 0
13 | b: 1
14 | c: 2
| ~~~~
15 | d: 3
16 | }
23 changes: 23 additions & 0 deletions vlib/v/checker/tests/struct_init_deprecations.vv
@@ -0,0 +1,23 @@
import v.checker.tests.module_with_deprecated_structs as m

fn init_deprecated_structs() {
o := m.Old{}
p := m.Present{}
dump(o)
dump(p)
}

fn init_deprecated_fields() {
x := m.Xyz{
a: 0
b: 1
c: 2
d: 3
}
dump(x)
}

fn main() {
init_deprecated_structs()
init_deprecated_fields()
}

0 comments on commit 9a0435d

Please sign in to comment.