Skip to content

Commit

Permalink
ast: clean up ast.StructInit (#18518)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyi98 committed Jun 22, 2023
1 parent af4e113 commit 22bd1b9
Show file tree
Hide file tree
Showing 21 changed files with 125 additions and 124 deletions.
2 changes: 1 addition & 1 deletion cmd/tools/vast/vast.v
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
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
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
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
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
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
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
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
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
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

0 comments on commit 22bd1b9

Please sign in to comment.