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

checker: fix unset type of a pointer field with default value, when a struct contains an embed (fix #16882) (#16883)

This commit is contained in:
Delyan Angelov 2023-01-05 19:53:37 +02:00 committed by GitHub
parent c1a9f42b05
commit 43d8bc30f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 13 deletions

View File

@ -2267,6 +2267,18 @@ pub fn (expr Expr) is_literal() bool {
}
}
pub fn (e Expr) is_nil() bool {
if e is Nil {
return true
}
if e is UnsafeExpr {
if e.expr is Nil {
return true
}
}
return false
}
pub fn type_can_start_with_token(tok &token.Token) bool {
match tok.kind {
.name {

View File

@ -104,8 +104,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
&& c.type_implements(default_expr_type, field.typ, field.pos)
c.check_expected(default_expr_type, field.typ) or {
if sym.kind == .interface_ && interface_implemented {
if !default_expr_type.is_ptr() && !default_expr_type.is_pointer()
&& !c.inside_unsafe {
if !c.inside_unsafe && !default_expr_type.is_real_pointer() {
if c.table.sym(default_expr_type).kind != .interface_ {
c.mark_as_referenced(mut &node.fields[i].default_expr,
true)
@ -116,6 +115,11 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
field.default_expr.pos())
}
}
if field.default_expr.is_nil() {
if !field.typ.is_real_pointer() && c.table.sym(field.typ).kind != .function {
c.error('cannot assign `nil` to a non-pointer field', field.type_pos)
}
}
// Check for unnecessary inits like ` = 0` and ` = ''`
if field.typ.is_ptr() {
if field.default_expr is ast.IntegerLiteral {
@ -134,12 +138,6 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
}
}
}
if field.default_expr is ast.UnsafeExpr {
if field.default_expr.expr is ast.Nil && !field.typ.is_ptr()
&& c.table.sym(field.typ).kind != .function && !field.typ.is_pointer() {
c.error('cannot assign `nil` to a non-pointer field', field.type_pos)
}
}
if field.default_expr is ast.IntegerLiteral {
if field.default_expr.val == '0' {
c.warn('unnecessary default value of `0`: struct fields are zeroed by default',
@ -444,8 +442,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
expr_type_sym := c.table.sym(expr_type)
if field_type_sym.kind == .interface_ {
if c.type_implements(expr_type, field_info.typ, field.pos) {
if !expr_type.is_ptr() && !expr_type.is_pointer()
&& expr_type_sym.kind != .interface_ && !c.inside_unsafe {
if !c.inside_unsafe && expr_type_sym.kind != .interface_
&& !expr_type.is_real_pointer() {
c.mark_as_referenced(mut &field.expr, true)
}
}
@ -462,7 +460,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
field.pos)
}
} else {
if field_info.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer()
if field_info.typ.is_ptr() && !expr_type.is_real_pointer()
&& field.expr.str() != '0' {
c.error('reference field must be initialized with reference',
field.pos)
@ -516,6 +514,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
sym := c.table.sym(field.typ)
if field.name.len > 0 && field.name[0].is_capital() && sym.info is ast.Struct
&& sym.language == .v {
// struct embeds
continue
}
if field.has_default_expr {
@ -525,6 +524,10 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
if idx != 0 {
info.fields[i].default_expr_typ = ast.new_type(idx)
}
} else if field.default_expr.is_nil() {
if field.typ.is_real_pointer() {
info.fields[i].default_expr_typ = field.typ
}
} else {
if const_field := c.table.global_scope.find_const('${field.default_expr}') {
info.fields[i].default_expr_typ = const_field.typ

View File

@ -167,8 +167,8 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
continue
}
}
if field.name in inited_fields {
mut sfield := node.fields[inited_fields[field.name]]
if already_initalised_node_field_index := inited_fields[field.name] {
mut sfield := node.fields[already_initalised_node_field_index]
if sfield.typ == 0 {
continue
}

View File

@ -0,0 +1,28 @@
pub struct Embed {
foo int
}
pub interface Node {
id u32
mut:
parent &Node
}
pub struct Item {
Embed
pub:
id u32
mut:
parent &Node = unsafe { nil }
}
fn test_struct_with_both_an_embed_and_a_pointer_to_interface_value_fields__initialises_properly() {
i := Item{}
si := i.str()
assert si.contains('Item{')
assert si.contains('Embed: Embed{')
assert si.contains('foo: 0')
assert si.contains('id: 0')
assert si.contains('parent: &nil')
assert si.contains('}')
}