diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 985973bb99..2bc4ebf575 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -43,12 +43,12 @@ NB: A V string should be/is immutable from the point of view of pub struct string { - // mut: - // hash_cache int pub: str byteptr // points to a C style 0 terminated string of bytes. len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str). } + // mut: + // hash_cache int pub struct ustring { pub: @@ -166,8 +166,8 @@ pub fn (s string) replace(rep, with string) string { mut cur_idx := idxs[idx_pos] mut b_i := 0 for i := 0; i < s.len; i++ { - // Reached the location of rep, replace it with "with" if i == cur_idx { + // Reached the location of rep, replace it with "with" for j in 0..with.len { b[b_i] = with[j] b_i++ @@ -180,8 +180,8 @@ pub fn (s string) replace(rep, with string) string { cur_idx = idxs[idx_pos] } } - // Rep doesnt start here, just copy else { + // Rep doesnt start here, just copy b[b_i] = s[i] b_i++ } @@ -263,8 +263,8 @@ pub fn (s string) replace_each(vals []string) string { mut cur_idx := idxs[idx_pos] mut b_i := 0 for i := 0; i < s.len; i++ { - // Reached the location of rep, replace it with "with" if i == cur_idx.idx { + // Reached the location of rep, replace it with "with" rep := vals[cur_idx.val_idx] with := vals[cur_idx.val_idx + 1] for j in 0..with.len { @@ -279,8 +279,8 @@ pub fn (s string) replace_each(vals []string) string { cur_idx = idxs[idx_pos] } } - // Rep doesnt start here, just copy else { + // Rep doesnt start here, just copy b[b_i] = s.str[i] b_i++ } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 9b47e0e78b..d90735a7ce 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -265,6 +265,7 @@ pub struct GlobalDecl { pub: name string expr Expr + has_expr bool mut: typ table.Type } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index ef8789e520..c486bb9749 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -139,7 +139,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type { continue } if table.type_is_ptr(field.typ) { - c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized', struct_init.pos) + c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized', + struct_init.pos) } } } @@ -212,7 +213,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { if !c.table.check(right_type, left_type) { left_type_sym := c.table.get_type_symbol(left_type) right_type_sym := c.table.get_type_symbol(right_type) - c.error('cannot assign $right_type_sym.name to $left_type_sym.name', assign_expr.pos) + c.error('cannot assign `$right_type_sym.name` to `$left_type_sym.name`', assign_expr.pos) } } @@ -224,8 +225,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { left_type_sym := c.table.get_type_symbol(left_type) method_name := call_expr.name // TODO: remove this for actual methods, use only for compiler magic - if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 'map', - 'slice'] { + if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', + 'map', 'slice'] { if method_name in ['filter', 'map'] { array_info := left_type_sym.info as table.Array mut scope := c.file.scope.innermost(call_expr.pos.pos) @@ -252,7 +253,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { } if method := c.table.type_find_method(left_type_sym, method_name) { no_args := method.args.len - 1 - min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 } + min_required_args := method.args.len - if method.is_variadic && method.args.len > + 1 { 2 } else { 1 } if call_expr.args.len < min_required_args { c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)', call_expr.pos) @@ -479,7 +481,8 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) { return } if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type { - c.error('too many arguments to return, current function does not return anything', return_stmt.pos) + c.error('too many arguments to return, current function does not return anything', + return_stmt.pos) return } expected_type := c.fn_return_type @@ -542,7 +545,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { if !c.table.check(val_type, var_type) { val_type_sym := c.table.get_type_symbol(val_type) var_type_sym := c.table.get_type_symbol(var_type) - c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos) + c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', + assign_stmt.pos) } } ident_var_info.typ = val_type @@ -568,7 +572,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { if !c.table.check(val_type, var_type) { val_type_sym := c.table.get_type_symbol(val_type) var_type_sym := c.table.get_type_symbol(var_type) - c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos) + c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', + assign_stmt.pos) } } ident_var_info.typ = val_type @@ -1181,7 +1186,8 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type { // index_type_sym.kind != .enum_) { if typ_sym.kind in [.array, .array_fixed] && !(table.is_number(index_type) || index_type_sym.kind == .enum_) { - c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)', node.pos) + c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)', + node.pos) } else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx { c.error('non-string map index (map type `$typ_sym.name`)', node.pos) } @@ -1252,12 +1258,14 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type { if !c.table.check(key_type, key0_type) { key0_type_sym := c.table.get_type_symbol(key0_type) key_type_sym := c.table.get_type_symbol(key_type) - c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key', node.pos) + c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key', + node.pos) } if !c.table.check(val_type, val0_type) { val0_type_sym := c.table.get_type_symbol(val0_type) val_type_sym := c.table.get_type_symbol(val_type) - c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value', node.pos) + c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value', + node.pos) } } map_type := table.new_type(c.table.find_or_register_map(key0_type, val0_type)) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 76a840ae02..577a89d35a 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -11,7 +11,7 @@ import ( const ( tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t'] - max_len = 100 + max_len = 90 ) struct Fmt { @@ -137,6 +137,11 @@ fn (f mut Fmt) stmt(node ast.Stmt) { } f.is_assign = false } + ast.AssertStmt { + f.write('assert ') + f.expr(it.expr) + f.writeln('') + } ast.Attr { f.writeln('[$it.name]') } @@ -159,6 +164,16 @@ fn (f mut Fmt) stmt(node ast.Stmt) { ast.Comment { f.comment(it) } + ast.CompIf { + inversion := if it.is_not { '!' } else { '' } + f.writeln('\$if ${inversion}${it.val} {') + f.stmts(it.stmts) + if it.has_else { + f.writeln('} \$else {') + f.stmts(it.else_stmts) + } + f.writeln('}') + } ast.ConstDecl { if it.is_pub { f.write('pub ') @@ -252,6 +267,14 @@ fn (f mut Fmt) stmt(node ast.Stmt) { f.stmts(it.stmts) f.writeln('}') } + ast.GlobalDecl { + f.write('__global $it.name ') + f.write(f.table.type_to_str(it.typ)) + if it.has_expr { + f.write(' = ') + f.expr(it.expr) + } + } ast.GotoLabel { f.writeln('$it.name:') } @@ -285,29 +308,13 @@ fn (f mut Fmt) stmt(node ast.Stmt) { ast.StructDecl { f.struct_decl(it) } - ast.UnsafeStmt { - f.writeln('unsafe {') - f.stmts(it.stmts) - f.writeln('}') - } - ast.Import {} ast.TypeDecl { // already handled in f.imports f.type_decl(it) } - ast.AssertStmt { - f.write('assert ') - f.expr(it.expr) - f.writeln('') - } - ast.CompIf { - inversion := if it.is_not { '!' } else { '' } - f.writeln('\$if ${inversion}${it.val} {') + ast.UnsafeStmt { + f.writeln('unsafe {') f.stmts(it.stmts) - if it.has_else { - f.writeln('} \$else {') - f.stmts(it.else_stmts) - } f.writeln('}') } else { @@ -575,6 +582,15 @@ fn (f mut Fmt) expr(node ast.Expr) { f.write('.') f.write(it.field) } + ast.SizeOf { + f.writeln('sizeof(') + if it.type_name != '' { + f.writeln(it.type_name) + } else { + f.writeln(f.table.type_to_str(it.typ)) + } + f.writeln(')') + } ast.StringLiteral { if it.val.contains("'") { f.write('"$it.val"') diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index af741e3569..3200e0cea7 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -15,10 +15,10 @@ import ( ) const ( - c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', - 'panic', 'auto', 'char', 'default', 'do', 'double', 'extern', 'float', 'inline', - 'int', 'long', 'register', 'restrict', 'short', 'signed', 'sizeof', 'static', 'switch', - 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'] + c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto', + 'char', 'default', 'do', 'double', 'extern', 'float', 'inline', 'int', 'long', 'register', + 'restrict', 'short', 'signed', 'sizeof', 'static', 'switch', 'typedef', 'union', 'unsigned', + 'void', 'volatile', 'while'] ) struct Gen { @@ -58,8 +58,8 @@ mut: } const ( - tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', - '\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t'] + tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', + '\t\t\t\t\t\t\t\t'] ) pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string { @@ -86,7 +86,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string indent: -1 } g.init() - // + // mut autofree_used := false for file in files { g.file = file @@ -115,10 +115,10 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string if g.is_test { g.write_tests_main() } - // + // g.finish() - return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + - g.definitions.str() + g.gowrappers.str() + g.stringliterals.str() + g.out.str() + return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + g.definitions.str() + + g.gowrappers.str() + g.stringliterals.str() + g.out.str() } pub fn (g Gen) hashes() string { @@ -141,7 +141,7 @@ pub fn (g mut Gen) init() { g.write_sorted_types() g.write_multi_return_types() g.definitions.writeln('// end of definitions #endif') - // + // g.stringliterals.writeln('') g.stringliterals.writeln('// >> string literal consts') g.stringliterals.writeln('void vinit_string_literals(){') @@ -205,7 +205,7 @@ pub fn (g mut Gen) typ(t table.Type) string { return styp } -// +// pub fn (g mut Gen) write_typedef_types() { for typ in g.table.types { match typ.kind { @@ -817,7 +817,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { } } */ - // + // g.fn_args(it.args, it.is_variadic) if it.no_body { // Just a function header. @@ -1006,7 +1006,8 @@ fn (g mut Gen) expr(node ast.Expr) { g.out.go_back(1) } sym := g.table.get_type_symbol(it.typ) - if sym.kind == .string { + if sym.kind == .string && !table.type_is_ptr(it.typ) { + // `string(x)` needs `tos()`, but not `&string(x) // `tos(str, len)`, `tos2(str)` if it.has_arg { g.write('tos(') @@ -1135,8 +1136,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.write('tos3("$escaped_val")') return } - escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', - '\\n']) + escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n']) if g.is_c_call || it.is_c { // In C calls we have to generate C strings // `C.printf("hi")` => `printf("hi");` @@ -1361,8 +1361,7 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { g.expr(node.left) g.write(')') } - } else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind == - .array { + } else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind == .array { // arr << val tmp := g.new_tmp_var() sym := g.table.get_type_symbol(node.left_type) @@ -1452,7 +1451,7 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) { // sum_type_str } else if type_sym.kind == .string { g.write('string_eq(') - // + // g.expr(node.cond) g.write(', ') // g.write('string_eq($tmp, ') @@ -1547,8 +1546,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) { // one line ?: // TODO clean this up once `is` is supported // TODO: make sure only one stmt in each branch - if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != - .void { + if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void { g.inside_ternary = true g.write('(') for i, branch in node.branches { @@ -1952,7 +1950,7 @@ fn (g mut Gen) assoc(node ast.Assoc) { } fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) { - is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len - + is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len - 1], .variadic) mut arg_no := 0 for arg in args { @@ -1996,8 +1994,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) { [inline] fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { - arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in - table.pointer_type_idxs + arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs if arg.is_mut && !arg_is_ptr { g.write('&/*mut*/') @@ -2134,7 +2131,7 @@ fn (g mut Gen) write_types(types []table.TypeSymbol) { g.definitions.writeln('EMPTY_STRUCT_DECLARATION;') } // g.definitions.writeln('} $name;\n') - // + // g.definitions.writeln('};\n') } table.Alias { @@ -2201,8 +2198,8 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol { // sort graph dep_graph_sorted := dep_graph.resolve() if !dep_graph_sorted.acyclic { - verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + - dep_graph_sorted.display_cycles() + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' + + verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + dep_graph_sorted.display_cycles() + + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' + '\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro') } // sort types @@ -2339,8 +2336,8 @@ fn (g mut Gen) method_call(node ast.CallExpr) { return } // TODO performance, detect `array` method differently - if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', - 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] { + if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', + 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] { // && rec_sym.name == 'array' { // && rec_sym.name == 'array' && receiver_name.starts_with('array') { // `array_byte_clone` => `array_clone` @@ -2365,7 +2362,7 @@ fn (g mut Gen) method_call(node ast.CallExpr) { g.write('/*rec*/*') } g.expr(node.left) - is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len - + is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len - 1], .variadic) if node.args.len > 0 || is_variadic { g.write(', ') @@ -2743,8 +2740,7 @@ pub fn (g mut Gen) write_tests_main() { g.definitions.writeln('int g_test_fails = 0;') $if windows { g.writeln('int wmain() {') - } - $else { + } $else { g.writeln('int main() {') } g.writeln('\t_vinit();') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index eeb11d0bb8..f47129c40d 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -627,7 +627,8 @@ pub fn (p mut Parser) name_expr() ast.Expr { name_w_mod := p.prepend_mod(name) // type cast. TODO: finish // if name in table.builtin_type_names { - if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) { + if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', + 'C.sigaction']) { // TODO handle C.stat() mut to_typ := p.parse_type() if p.is_amp { @@ -660,9 +661,9 @@ pub fn (p mut Parser) name_expr() ast.Expr { x := p.call_expr(is_c, mod) // TODO `node,typ :=` should work node = x } - } else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && p.tok.lit in - table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len - 1].is_capital()) && - !p.inside_match_case { + } else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && + p.tok.lit in table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len - + 1].is_capital()) && !p.inside_match_case { // || p.table.known_type(p.tok.lit)) { return p.struct_init(false) // short_syntax: false } else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) { @@ -1714,17 +1715,19 @@ fn (p mut Parser) hash() ast.HashStmt { } fn (p mut Parser) global_decl() ast.GlobalDecl { - if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && - p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals { + if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != + 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals { p.error('use `v --enable-globals ...` to enable globals') } p.next() name := p.check_name() // println(name) typ := p.parse_type() - if p.tok.kind == .assign { + mut expr := ast.Expr{} + has_expr := p.tok.kind == .assign + if has_expr { p.next() - p.expr(0) + expr = p.expr(0) } // p.genln(p.table.cgen_name_type_pair(name, typ)) /* @@ -1744,6 +1747,8 @@ fn (p mut Parser) global_decl() ast.GlobalDecl { glob := ast.GlobalDecl{ name: name typ: typ + has_expr: has_expr + expr: expr } p.global_scope.register(name, glob) return glob diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 65a95d19ea..5e742dc63d 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -389,34 +389,36 @@ pub fn (t &Table) value_type(typ Type) Type { // ...string => string return type_set(typ, .unset) } - else if typ_sym.kind == .array { + if typ_sym.kind == .array { // Check index type info := typ_sym.info as Array return info.elem_type } - else if typ_sym.kind == .array_fixed { + if typ_sym.kind == .array_fixed { info := typ_sym.info as ArrayFixed return info.elem_type } - else if typ_sym.kind == .map { + if typ_sym.kind == .map { info := typ_sym.info as Map return info.value_type } - else if typ_sym.kind in [.byteptr, .string] { + if typ_sym.kind == .string && table.type_is_ptr(typ) { + // (&string)[i] => string + return string_type + } + if typ_sym.kind in [.byteptr, .string] { return byte_type } - else if type_is_ptr(typ) { + if type_is_ptr(typ) { // byte* => byte // bytes[0] is a byte, not byte* return type_deref(typ) } - else { - // TODO: remove when map_string is removed - if typ_sym.name == 'map_string' { - return string_type - } - return void_type + // TODO: remove when map_string is removed + if typ_sym.name == 'map_string' { + return string_type } + return void_type } pub fn (t &Table) check(got, expected Type) bool { diff --git a/vlib/v/tests/module_test.v b/vlib/v/tests/module_test.v index e174093615..87b189c656 100644 --- a/vlib/v/tests/module_test.v +++ b/vlib/v/tests/module_test.v @@ -1,10 +1,10 @@ -import os -import time as t -import crypto.sha256 as s2 import ( + os + time as t + crypto.sha256 math log as l - crypto.sha512 as s5 + crypto.sha512 ) struct TestAliasInStruct { @@ -12,7 +12,9 @@ struct TestAliasInStruct { } fn test_import() { - assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && s2.size == s2.size && math.pi == math.pi && l.INFO == l.INFO && s5.size == s5.size + info := l.Level.info + assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && sha256.size == + sha256.size && math.pi == math.pi && info == .info && sha512.size == sha512.size } fn test_alias_in_struct_field() {