Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ast: clean up ast.StructInit #18518

Merged
merged 2 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/tools/vast/vast.v
Original file line number Diff line number Diff line change
Expand Up @@ -1569,7 +1569,7 @@ fn (t Tree) struct_init(node ast.StructInit) &Node {
obj.add('pos', t.pos(node.pos))
obj.add('name_pos', t.pos(node.name_pos))
obj.add('update_expr_comments', t.array_node_comment(node.update_expr_comments))
obj.add_terse('fields', t.array_node_struct_init_field(node.fields))
obj.add_terse('init_fields', t.array_node_struct_init_field(node.init_fields))
obj.add('pre_comments', t.array_node_comment(node.pre_comments))
return obj
}
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ pub mut:
update_expr_comments []Comment
is_update_embed bool
has_update_expr bool // has `...a`
fields []StructInitField
init_fields []StructInitField
generic_types []Type
}

Expand Down Expand Up @@ -2145,7 +2145,7 @@ pub fn (node Node) children() []Node {
return node.stmts.map(Node(it))
}
StructInit {
return node.fields.map(Node(it))
return node.init_fields.map(Node(it))
}
AnonFn {
children << Stmt(node.decl)
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/ast/init.v
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn (t &Table) resolve_init(node StructInit, typ Type) Expr {
mut cap_expr := empty_expr
mut default_expr := empty_expr
mut exprs := []Expr{}
for field in node.fields {
for field in node.init_fields {
match field.name {
'len' {
has_len = true
Expand Down Expand Up @@ -48,7 +48,7 @@ pub fn (t &Table) resolve_init(node StructInit, typ Type) Expr {
Map {
mut keys := []Expr{}
mut vals := []Expr{}
for field in node.fields {
for field in node.init_fields {
keys << StringLiteral{
val: field.name
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -2368,7 +2368,7 @@ pub fn (t &Table) dependent_names_in_expr(expr Expr) []string {
names << t.dependent_names_in_expr(expr.expr)
}
StructInit {
for field in expr.fields {
for field in expr.init_fields {
names << t.dependent_names_in_expr(field.expr)
}
}
Expand Down
10 changes: 5 additions & 5 deletions vlib/v/checker/check_types.v
Original file line number Diff line number Diff line change
Expand Up @@ -694,15 +694,15 @@ fn (mut c Checker) infer_struct_generic_types(typ ast.Type, node ast.StructInit)
for ft in sym.info.fields {
field_sym := c.table.sym(ft.typ)
if field_sym.name == gt_name {
for t in node.fields {
for t in node.init_fields {
if ft.name == t.name && t.typ != 0 {
concrete_types << ast.mktyp(t.typ)
continue gname
}
}
}
if field_sym.info is ast.Array {
for t in node.fields {
for t in node.init_fields {
if ft.name == t.name {
init_sym := c.table.sym(t.typ)
if init_sym.info is ast.Array {
Expand Down Expand Up @@ -730,7 +730,7 @@ fn (mut c Checker) infer_struct_generic_types(typ ast.Type, node ast.StructInit)
}
}
} else if field_sym.info is ast.ArrayFixed {
for t in node.fields {
for t in node.init_fields {
if ft.name == t.name {
init_sym := c.table.sym(t.typ)
if init_sym.info is ast.ArrayFixed {
Expand Down Expand Up @@ -758,7 +758,7 @@ fn (mut c Checker) infer_struct_generic_types(typ ast.Type, node ast.StructInit)
}
}
} else if field_sym.info is ast.Map {
for t in node.fields {
for t in node.init_fields {
if ft.name == t.name {
init_sym := c.table.sym(t.typ)
if init_sym.info is ast.Map {
Expand Down Expand Up @@ -786,7 +786,7 @@ fn (mut c Checker) infer_struct_generic_types(typ ast.Type, node ast.StructInit)
}
}
} else if field_sym.info is ast.FnType {
for t in node.fields {
for t in node.init_fields {
if ft.name == t.name {
init_sym := c.table.sym(t.typ)
if init_sym.info is ast.FnType {
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -4376,12 +4376,12 @@ fn (mut c Checker) error(message string, pos token.Pos) {
}

fn (c &Checker) check_struct_signature_init_fields(from ast.Struct, to ast.Struct, node ast.StructInit) bool {
if node.fields.len == 0 {
if node.init_fields.len == 0 {
return from.fields.len == to.fields.len
}

mut count_not_in_from := 0
for field in node.fields {
for field in node.init_fields {
filtered := from.fields.filter(it.name == field.name)
if filtered.len != 1 {
count_not_in_from++
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ fn (_ &Checker) check_field_of_inserting_struct_is_uninitialized(node &ast.SqlSt
struct_scope := node.scope.find_var(node.object_var_name) or { return false }

if struct_scope.expr is ast.StructInit {
return struct_scope.expr.fields.filter(it.name == field_name).len == 0
return struct_scope.expr.init_fields.filter(it.name == field_name).len == 0
}

return false
Expand Down
81 changes: 41 additions & 40 deletions vlib/v/checker/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
c.error('cannot initialize enums', node.pos)
}
}
if type_sym.kind == .sum_type && node.fields.len == 1 {
sexpr := node.fields[0].expr.str()
if type_sym.kind == .sum_type && node.init_fields.len == 1 {
sexpr := node.init_fields[0].expr.str()
c.error('cast to sum type using `${type_sym.name}(${sexpr})` not `${type_sym.name}{${sexpr}}`',
node.pos)
}
Expand Down Expand Up @@ -420,16 +420,16 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
.any {
// `T{ foo: 22 }`
for mut field in node.fields {
field.typ = c.expr(field.expr)
field.expected_type = field.typ
for mut init_field in node.init_fields {
init_field.typ = c.expr(init_field.expr)
init_field.expected_type = init_field.typ
}
sym := c.table.sym(c.unwrap_generic(node.typ))
if sym.kind == .struct_ {
info := sym.info as ast.Struct
if node.no_keys && node.fields.len != info.fields.len {
if node.no_keys && node.init_fields.len != info.fields.len {
fname := if info.fields.len != 1 { 'fields' } else { 'field' }
c.error('initializing struct `${sym.name}` needs `${info.fields.len}` ${fname}, but got `${node.fields.len}`',
c.error('initializing struct `${sym.name}` needs `${info.fields.len}` ${fname}, but got `${node.init_fields.len}`',
node.pos)
}
}
Expand All @@ -454,7 +454,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
if node.no_keys {
exp_len := info.fields.len
got_len := node.fields.len
got_len := node.init_fields.len
if exp_len != got_len && !c.pref.translated {
// XTODO remove !translated check
amount := if exp_len < got_len { 'many' } else { 'few' }
Expand All @@ -467,7 +467,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
info_fields_sorted = info.fields.clone()
info_fields_sorted.sort(a.i < b.i)
}
for i, mut field in node.fields {
for i, mut init_field in node.init_fields {
mut field_info := ast.StructField{}
mut field_name := ''
if node.no_keys {
Expand All @@ -478,23 +478,23 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
field_info = info_fields_sorted[i]
field_name = field_info.name
node.fields[i].name = field_name
node.init_fields[i].name = field_name
} else {
field_name = field.name
field_name = init_field.name
mut exists := true
field_info = c.table.find_field_with_embeds(type_sym, field_name) or {
exists = false
ast.StructField{}
}
if !exists {
existing_fields := c.table.struct_fields(type_sym).map(it.name)
c.error(util.new_suggestion(field.name, existing_fields).say('unknown field `${field.name}` in struct literal of type `${type_sym.name}`'),
field.pos)
c.error(util.new_suggestion(init_field.name, existing_fields).say('unknown field `${init_field.name}` in struct literal of type `${type_sym.name}`'),
init_field.pos)
continue
}
if field_name in inited_fields {
c.error('duplicate field name in struct literal: `${field_name}`',
field.pos)
init_field.pos)
continue
}
}
Expand All @@ -504,83 +504,84 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
exp_type = field_info.typ
exp_type_sym := c.table.sym(exp_type)
c.expected_type = exp_type
got_type = c.expr(field.expr)
got_type = c.expr(init_field.expr)
got_type_sym := c.table.sym(got_type)
if got_type == ast.void_type {
c.error('`${field.expr}` (no value) used as value', field.pos)
c.error('`${init_field.expr}` (no value) used as value', init_field.pos)
}
if !exp_type.has_flag(.option) && !got_type.has_flag(.result) {
got_type = c.check_expr_opt_call(field.expr, got_type)
got_type = c.check_expr_opt_call(init_field.expr, got_type)
if got_type.has_flag(.option) {
c.error('cannot assign an Option value to a non-option struct field',
field.pos)
init_field.pos)
}
}
if exp_type_sym.kind == .voidptr && got_type_sym.kind == .struct_
&& !got_type.is_ptr() {
c.error('allocate on the heap for use in other functions', field.pos)
c.error('allocate on the heap for use in other functions', init_field.pos)
}
if exp_type_sym.kind == .interface_ {
if c.type_implements(got_type, exp_type, field.pos) {
if c.type_implements(got_type, exp_type, init_field.pos) {
if !c.inside_unsafe && got_type_sym.kind != .interface_
&& !got_type.is_any_kind_of_pointer() {
c.mark_as_referenced(mut &field.expr, true)
c.mark_as_referenced(mut &init_field.expr, true)
}
}
} else if got_type != ast.void_type && got_type_sym.kind != .placeholder
&& !exp_type.has_flag(.generic) {
c.check_expected(c.unwrap_generic(got_type), c.unwrap_generic(exp_type)) or {
c.error('cannot assign to field `${field_info.name}`: ${err.msg()}',
field.pos)
init_field.pos)
}
}
if exp_type.has_flag(.shared_f) {
if !got_type.has_flag(.shared_f) && got_type.is_ptr() {
c.error('`shared` field must be initialized with `shared` or value',
field.pos)
init_field.pos)
}
} else {
if exp_type.is_ptr() && !got_type.is_any_kind_of_pointer()
&& field.expr.str() != '0' && !exp_type.has_flag(.option) {
&& init_field.expr.str() != '0' && !exp_type.has_flag(.option) {
c.error('reference field must be initialized with reference',
field.pos)
init_field.pos)
} else if exp_type.is_pointer() && !got_type.is_any_kind_of_pointer()
&& !got_type.is_int() {
got_typ_str := c.table.type_to_str(got_type)
exp_typ_str := c.table.type_to_str(exp_type)
c.error('cannot assign to field `${field_info.name}`: expected a pointer `${exp_typ_str}`, but got `${got_typ_str}`',
field.pos)
init_field.pos)
}
}
node.fields[i].typ = got_type
node.fields[i].expected_type = exp_type
node.init_fields[i].typ = got_type
node.init_fields[i].expected_type = exp_type

if got_type.is_ptr() && exp_type.is_ptr() {
if mut field.expr is ast.Ident {
c.fail_if_stack_struct_action_outside_unsafe(mut field.expr, 'assigned')
if mut init_field.expr is ast.Ident {
c.fail_if_stack_struct_action_outside_unsafe(mut init_field.expr,
'assigned')
}
}
if field_info.typ in ast.unsigned_integer_type_idxs {
if mut field.expr is ast.IntegerLiteral {
if field.expr.val[0] == `-` {
if mut init_field.expr is ast.IntegerLiteral {
if init_field.expr.val[0] == `-` {
c.error('cannot assign negative value to unsigned integer type',
field.expr.pos)
init_field.expr.pos)
}
}
}

if exp_type_sym.kind == .struct_ && !(exp_type_sym.info as ast.Struct).is_anon
&& mut field.expr is ast.StructInit {
if field.expr.is_anon {
&& mut init_field.expr is ast.StructInit {
if init_field.expr.is_anon {
c.error('cannot assign anonymous `struct` to a typed `struct`',
field.expr.pos)
init_field.expr.pos)
}
}

// all the fields of initialized embedded struct are ignored, they are considered initialized
sym := c.table.sym(field.typ)
if field.name.len > 0 && field.name[0].is_capital() && sym.kind == .struct_
&& sym.language == .v {
sym := c.table.sym(init_field.typ)
if init_field.name.len > 0 && init_field.name[0].is_capital()
&& sym.kind == .struct_ && sym.language == .v {
struct_fields := c.table.struct_fields(sym)
for struct_field in struct_fields {
inited_fields << struct_field.name
Expand Down Expand Up @@ -666,7 +667,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
// Check for `[required]` struct attr
if field.attrs.contains('required') && !node.no_keys && !node.has_update_expr {
mut found := false
for init_field in node.fields {
for init_field in node.init_fields {
if field.name == init_field.name {
found = true
break
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/fmt/fmt.v
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ fn expr_is_single_line(expr ast.Expr) bool {
}
}
ast.StructInit {
if !expr.no_keys && (expr.fields.len > 0 || expr.pre_comments.len > 0) {
if !expr.no_keys && (expr.init_fields.len > 0 || expr.pre_comments.len > 0) {
return false
}
}
Expand Down
28 changes: 14 additions & 14 deletions vlib/v/fmt/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
if node.is_anon {
f.write('struct ')
}
if node.fields.len == 0 && !node.has_update_expr {
if node.init_fields.len == 0 && !node.has_update_expr {
// `Foo{}` on one line if there are no fields or comments
if node.pre_comments.len == 0 {
f.write('${name}{}')
Expand All @@ -279,9 +279,9 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
f.expr(node.update_expr)
f.write(', ')
}
for i, field in node.fields {
f.expr(field.expr)
if i < node.fields.len - 1 {
for i, init_field in node.init_fields {
f.expr(init_field.expr)
if i < node.init_fields.len - 1 {
f.write(', ')
}
}
Expand Down Expand Up @@ -320,29 +320,29 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
f.write('...')
f.expr(node.update_expr)
if single_line_fields {
if node.fields.len > 0 {
if node.init_fields.len > 0 {
f.write(', ')
}
} else {
f.writeln('')
}
f.comments(node.update_expr_comments, inline: true, has_nl: true, level: .keep)
}
for i, field in node.fields {
f.write('${field.name}: ')
f.expr(field.expr)
f.comments(field.comments, inline: true, has_nl: false, level: .indent)
for i, init_field in node.init_fields {
f.write('${init_field.name}: ')
f.expr(init_field.expr)
f.comments(init_field.comments, inline: true, has_nl: false, level: .indent)
if single_line_fields {
if i < node.fields.len - 1 {
if i < node.init_fields.len - 1 {
f.write(', ')
}
} else {
f.writeln('')
}
f.comments(field.next_comments, inline: false, has_nl: true, level: .keep)
if single_line_fields && (field.comments.len > 0
|| field.next_comments.len > 0
|| !expr_is_single_line(field.expr)
f.comments(init_field.next_comments, inline: false, has_nl: true, level: .keep)
if single_line_fields && (init_field.comments.len > 0
|| init_field.next_comments.len > 0
|| !expr_is_single_line(init_field.expr)
|| f.line_len > max_len.last()) {
single_line_fields = false
f.out.go_back_to(fields_start)
Expand Down