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:
parent
c1a9f42b05
commit
43d8bc30f9
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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('}')
|
||||
}
|
Loading…
Reference in New Issue
Block a user