mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
parent
95f53a3308
commit
1ba80211c2
6 changed files with 84 additions and 1 deletions
|
@ -199,6 +199,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
c.inside_decl_rhs = is_decl
|
c.inside_decl_rhs = is_decl
|
||||||
mut expr := node.right[i]
|
mut expr := node.right[i]
|
||||||
|
if left is ast.Ident && left.is_mut() && expr is ast.StructInit && expr.is_anon {
|
||||||
|
c.anon_struct_should_be_mut = true
|
||||||
|
defer {
|
||||||
|
c.anon_struct_should_be_mut = false
|
||||||
|
}
|
||||||
|
}
|
||||||
right_type := c.expr(mut expr)
|
right_type := c.expr(mut expr)
|
||||||
c.inside_decl_rhs = false
|
c.inside_decl_rhs = false
|
||||||
c.inside_ref_lit = old_inside_ref_lit
|
c.inside_ref_lit = old_inside_ref_lit
|
||||||
|
|
|
@ -89,6 +89,7 @@ pub mut:
|
||||||
inside_fn_arg bool // `a`, `b` in `a.f(b)`
|
inside_fn_arg bool // `a`, `b` in `a.f(b)`
|
||||||
inside_ct_attr bool // true inside `[if expr]`
|
inside_ct_attr bool // true inside `[if expr]`
|
||||||
inside_x_is_type bool // true inside the Type expression of `if x is Type {`
|
inside_x_is_type bool // true inside the Type expression of `if x is Type {`
|
||||||
|
anon_struct_should_be_mut bool // true when `mut var := struct { ... }` is used
|
||||||
inside_generic_struct_init bool
|
inside_generic_struct_init bool
|
||||||
inside_integer_literal_cast bool // true inside `int(123)`
|
inside_integer_literal_cast bool // true inside `int(123)`
|
||||||
cur_struct_generic_types []ast.Type
|
cur_struct_generic_types []ast.Type
|
||||||
|
|
|
@ -1659,6 +1659,11 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
} else if param_typ_sym.info is ast.Struct && arg_typ_sym.info is ast.Struct
|
||||||
|
&& param_typ_sym.info.is_anon {
|
||||||
|
if c.is_anon_struct_compatible(param_typ_sym.info, arg_typ_sym.info) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if c.pref.translated || c.file.is_translated {
|
if c.pref.translated || c.file.is_translated {
|
||||||
// in case of variadic make sure to use array elem type for checks
|
// in case of variadic make sure to use array elem type for checks
|
||||||
|
|
|
@ -534,7 +534,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
|
||||||
&& c.table.cur_concrete_types.len == 0 {
|
&& c.table.cur_concrete_types.len == 0 {
|
||||||
pos := type_sym.name.last_index_u8(`.`)
|
pos := type_sym.name.last_index_u8(`.`)
|
||||||
first_letter := type_sym.name[pos + 1]
|
first_letter := type_sym.name[pos + 1]
|
||||||
if !first_letter.is_capital()
|
if !first_letter.is_capital() && type_sym.kind != .none
|
||||||
&& (type_sym.kind != .struct || !(type_sym.info is ast.Struct && type_sym.info.is_anon))
|
&& (type_sym.kind != .struct || !(type_sym.info is ast.Struct && type_sym.info.is_anon))
|
||||||
&& type_sym.kind != .placeholder {
|
&& type_sym.kind != .placeholder {
|
||||||
c.error('cannot initialize builtin type `${type_sym.name}`', node.pos)
|
c.error('cannot initialize builtin type `${type_sym.name}`', node.pos)
|
||||||
|
@ -850,6 +850,35 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
|
||||||
inited_fields)
|
inited_fields)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.none {
|
||||||
|
// var := struct { name: "" }
|
||||||
|
mut init_fields := []ast.StructField{}
|
||||||
|
for init_field in node.init_fields {
|
||||||
|
mut expr := unsafe { init_field }
|
||||||
|
init_fields << ast.StructField{
|
||||||
|
name: init_field.name
|
||||||
|
typ: c.expr(mut expr.expr)
|
||||||
|
is_mut: c.anon_struct_should_be_mut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.table.anon_struct_counter++
|
||||||
|
name := '_VAnonStruct${c.table.anon_struct_counter}'
|
||||||
|
sym_struct := ast.TypeSymbol{
|
||||||
|
kind: .struct
|
||||||
|
language: .v
|
||||||
|
name: name
|
||||||
|
cname: util.no_dots(name)
|
||||||
|
mod: c.mod
|
||||||
|
info: ast.Struct{
|
||||||
|
is_anon: true
|
||||||
|
fields: init_fields
|
||||||
|
}
|
||||||
|
is_pub: true
|
||||||
|
}
|
||||||
|
ret := c.table.register_sym(sym_struct)
|
||||||
|
c.table.register_anon_struct(name, ret)
|
||||||
|
node.typ = c.table.find_type_idx(name)
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
if node.has_update_expr {
|
if node.has_update_expr {
|
||||||
|
@ -1140,3 +1169,17 @@ fn (mut c Checker) check_ref_fields_initialized_note(struct_sym &ast.TypeSymbol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) is_anon_struct_compatible(s1 ast.Struct, s2 ast.Struct) bool {
|
||||||
|
if !(s1.is_anon && s2.is_anon && s1.fields.len == s2.fields.len) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mut is_compatible := true
|
||||||
|
for k, field in s1.fields {
|
||||||
|
if !c.check_basic(field.typ, s2.fields[k].typ) {
|
||||||
|
is_compatible = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_compatible
|
||||||
|
}
|
||||||
|
|
|
@ -2760,6 +2760,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
|
||||||
g.expr_with_cast(arg.expr, arg_typ, expected_type)
|
g.expr_with_cast(arg.expr, arg_typ, expected_type)
|
||||||
g.write('.data')
|
g.write('.data')
|
||||||
return
|
return
|
||||||
|
} else if arg.expr is ast.Ident && arg_sym.info is ast.Struct && arg_sym.info.is_anon {
|
||||||
|
// make anon struct struct compatible with another anon struct declaration
|
||||||
|
g.write('*(${g.cc_type(expected_type, false)}*)&')
|
||||||
}
|
}
|
||||||
// check if the argument must be dereferenced or not
|
// check if the argument must be dereferenced or not
|
||||||
g.arg_no_auto_deref = is_smartcast && !arg_is_ptr && !exp_is_ptr && arg.should_be_ptr
|
g.arg_no_auto_deref = is_smartcast && !arg_is_ptr && !exp_is_ptr && arg.should_be_ptr
|
||||||
|
|
25
vlib/v/tests/structs/anon_struct_assign_expr_test.v
Normal file
25
vlib/v/tests/structs/anon_struct_assign_expr_test.v
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
fn t() int {
|
||||||
|
return 123
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r(a struct { name string age int }) {
|
||||||
|
assert '${a}' == "struct {
|
||||||
|
name: 'Foo'
|
||||||
|
age: 123
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
mut a := struct {
|
||||||
|
name: 'Foo'
|
||||||
|
age: t()
|
||||||
|
}
|
||||||
|
dump(a)
|
||||||
|
r(a)
|
||||||
|
r(struct { name: 'Foo', age: t() })
|
||||||
|
a.age = 2
|
||||||
|
assert '${a}' == "struct {
|
||||||
|
name: 'Foo'
|
||||||
|
age: 2
|
||||||
|
}"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue