diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 1976a88f4a3e0e..82c2d33e178eff 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1492,6 +1492,7 @@ pub mut: elem_type Type // element type init_type Type // init: value type typ Type // array type + alias_type Type // alias type } pub struct ArrayDecompose { diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 18140524cc42f3..7c73081c653127 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1710,7 +1710,11 @@ pub fn (mut f Fmt) array_init(node ast.ArrayInit) { if node.exprs.len == 0 && node.typ != 0 && node.typ != ast.void_type { // `x := []string{}` f.mark_types_import_as_used(node.typ) - f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) + if node.alias_type != ast.void_type { + f.write(f.table.type_to_str_using_aliases(node.alias_type, f.mod2alias)) + } else { + f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) + } f.write('{') if node.has_len { f.write('len: ') diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v index 69ac305e029a90..1657df7c1c3240 100644 --- a/vlib/v/parser/containers.v +++ b/vlib/v/parser/containers.v @@ -6,10 +6,9 @@ module parser import v.ast import v.token -fn (mut p Parser) array_init(is_option bool) ast.ArrayInit { +fn (mut p Parser) array_init(is_option bool, alias_array_type ast.Type) ast.ArrayInit { first_pos := p.tok.pos() mut last_pos := p.tok.pos() - p.check(.lsbr) mut array_type := ast.void_type mut elem_type := ast.void_type mut elem_type_pos := first_pos @@ -22,103 +21,112 @@ fn (mut p Parser) array_init(is_option bool) ast.ArrayInit { mut has_init := false mut has_index := false mut init_expr := ast.empty_expr - if p.tok.kind == .rsbr { - last_pos = p.tok.pos() - // []typ => `[]` and `typ` must be on the same line - line_nr := p.tok.line_nr - p.next() - // []string - if p.tok.kind in [.name, .amp, .lsbr, .question, .key_shared] && p.tok.line_nr == line_nr { - elem_type_pos = p.tok.pos() - elem_type = p.parse_type() - // this is set here because it's a known type, others could be the - // result of expr so we do those in checker - if elem_type != 0 { - idx := p.table.find_or_register_array(elem_type) - if elem_type.has_flag(.generic) { - array_type = ast.new_type(idx).set_flag(.generic) - } else { - array_type = ast.new_type(idx) - } - if is_option { - array_type = array_type.set_flag(.option) + if alias_array_type == ast.void_type { + p.check(.lsbr) + if p.tok.kind == .rsbr { + last_pos = p.tok.pos() + // []typ => `[]` and `typ` must be on the same line + line_nr := p.tok.line_nr + p.next() + // []string + if p.tok.kind in [.name, .amp, .lsbr, .question, .key_shared] + && p.tok.line_nr == line_nr { + elem_type_pos = p.tok.pos() + elem_type = p.parse_type() + // this is set here because it's a known type, others could be the + // result of expr so we do those in checker + if elem_type != 0 { + idx := p.table.find_or_register_array(elem_type) + if elem_type.has_flag(.generic) { + array_type = ast.new_type(idx).set_flag(.generic) + } else { + array_type = ast.new_type(idx) + } + if is_option { + array_type = array_type.set_flag(.option) + } + has_type = true } - has_type = true - } - } - last_pos = p.tok.pos() - } else { - // [1,2,3] or [const]u8 - old_inside_array_lit := p.inside_array_lit - p.inside_array_lit = true - pre_cmnts = p.eat_comments() - for i := 0; p.tok.kind !in [.rsbr, .eof]; i++ { - exprs << p.expr(0) - ecmnts << p.eat_comments() - if p.tok.kind == .comma { - p.next() } - ecmnts.last() << p.eat_comments() - } - p.inside_array_lit = old_inside_array_lit - line_nr := p.tok.line_nr - last_pos = p.tok.pos() - p.check(.rsbr) - if exprs.len == 1 && p.tok.line_nr == line_nr - && (p.tok.kind in [.name, .amp, .question, .key_shared] - || (p.tok.kind == .lsbr && p.is_array_type())) { - // [100]u8 - elem_type = p.parse_type() - if p.table.sym(elem_type).name == 'byte' { - p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8{}` instead of `[10]byte{}`') + last_pos = p.tok.pos() + } else { + // [1,2,3] or [const]u8 + old_inside_array_lit := p.inside_array_lit + p.inside_array_lit = true + pre_cmnts = p.eat_comments() + for i := 0; p.tok.kind !in [.rsbr, .eof]; i++ { + exprs << p.expr(0) + ecmnts << p.eat_comments() + if p.tok.kind == .comma { + p.next() + } + ecmnts.last() << p.eat_comments() } + p.inside_array_lit = old_inside_array_lit + line_nr := p.tok.line_nr last_pos = p.tok.pos() - is_fixed = true - if p.tok.kind == .lcbr { - p.next() - if p.tok.kind != .rcbr { - pos := p.tok.pos() - n := p.check_name() - if n != 'init' { - if is_fixed { - p.error_with_pos('`len` and `cap` are invalid attributes for fixed array dimension', - pos) - } else { - p.error_with_pos('expected `init:`, not `${n}`', pos) + p.check(.rsbr) + if exprs.len == 1 && p.tok.line_nr == line_nr + && (p.tok.kind in [.name, .amp, .question, .key_shared] + || (p.tok.kind == .lsbr && p.is_array_type())) { + // [100]u8 + elem_type = p.parse_type() + if p.table.sym(elem_type).name == 'byte' { + p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8{}` instead of `[10]byte{}`') + } + last_pos = p.tok.pos() + is_fixed = true + if p.tok.kind == .lcbr { + p.next() + if p.tok.kind != .rcbr { + pos := p.tok.pos() + n := p.check_name() + if n != 'init' { + if is_fixed { + p.error_with_pos('`len` and `cap` are invalid attributes for fixed array dimension', + pos) + } else { + p.error_with_pos('expected `init:`, not `${n}`', pos) + } + return ast.ArrayInit{} } - return ast.ArrayInit{} + p.check(.colon) + has_init = true + has_index = p.handle_index_variable(mut init_expr) } - p.check(.colon) - has_init = true - has_index = p.handle_index_variable(mut init_expr) + last_pos = p.tok.pos() + p.check(.rcbr) + } else { + modifier := if is_option { '?' } else { '' } + p.warn_with_pos('use e.g. `x := ${modifier}[1]Type{}` instead of `x := ${modifier}[1]Type`', + first_pos.extend(last_pos)) } - last_pos = p.tok.pos() - p.check(.rcbr) } else { + if p.tok.kind == .not { + last_pos = p.tok.pos() + is_fixed = true + has_val = true + p.next() + } + if p.tok.kind == .not && p.tok.line_nr == p.prev_tok.line_nr { + last_pos = p.tok.pos() + p.error_with_pos('use e.g. `[1, 2, 3]!` instead of `[1, 2, 3]!!`', + last_pos) + p.next() + } + } + } + if exprs.len == 0 && p.tok.kind != .lcbr && has_type { + if !p.pref.is_fmt { modifier := if is_option { '?' } else { '' } - p.warn_with_pos('use e.g. `x := ${modifier}[1]Type{}` instead of `x := ${modifier}[1]Type`', + p.warn_with_pos('use `x := ${modifier}[]Type{}` instead of `x := ${modifier}[]Type`', first_pos.extend(last_pos)) } - } else { - if p.tok.kind == .not { - last_pos = p.tok.pos() - is_fixed = true - has_val = true - p.next() - } - if p.tok.kind == .not && p.tok.line_nr == p.prev_tok.line_nr { - last_pos = p.tok.pos() - p.error_with_pos('use e.g. `[1, 2, 3]!` instead of `[1, 2, 3]!!`', last_pos) - p.next() - } - } - } - if exprs.len == 0 && p.tok.kind != .lcbr && has_type { - if !p.pref.is_fmt { - modifier := if is_option { '?' } else { '' } - p.warn_with_pos('use `x := ${modifier}[]Type{}` instead of `x := ${modifier}[]Type`', - first_pos.extend(last_pos)) } + } else { + array_type = (p.table.sym(alias_array_type).info as ast.Alias).parent_type + elem_type = p.table.sym(array_type).array_info().elem_type + p.next() } mut has_len := false mut has_cap := false @@ -170,6 +178,7 @@ fn (mut p Parser) array_init(is_option bool) ast.ArrayInit { mod: p.mod elem_type: elem_type typ: array_type + alias_type: alias_array_type exprs: exprs ecmnts: ecmnts pre_cmnts: pre_cmnts diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index 9e842cef5a4cd8..d54983074a14df 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -216,10 +216,10 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr { pos: pos } } else { - node = p.array_init(false) + node = p.array_init(false, ast.void_type) } } else { - node = p.array_init(false) + node = p.array_init(false, ast.void_type) } } .key_none { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index bc0393fc1a76c9..d47fc90cc0e649 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2543,6 +2543,19 @@ fn (mut p Parser) is_generic_cast() bool { return false } +fn (mut p Parser) alias_array_type() ast.Type { + full_name := p.prepend_mod(p.tok.lit) + if idx := p.table.type_idxs[full_name] { + sym := p.table.sym(idx) + if sym.info is ast.Alias { + if p.table.sym(sym.info.parent_type).kind == .array { + return idx + } + } + } + return ast.void_type +} + @[direct_array_access] fn (mut p Parser) name_expr() ast.Expr { prev_tok_kind := p.prev_tok.kind @@ -2840,7 +2853,13 @@ fn (mut p Parser) name_expr() ast.Expr { && (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital)) && !p.inside_match_case && (!p.inside_if || p.inside_select) && (!p.inside_for || p.inside_select) { - return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option) // short_syntax: false + alias_array_type := p.alias_array_type() + if alias_array_type != ast.void_type { + return p.array_init(is_option, alias_array_type) + } else { + // `if a == Foo{} {...}` or `match foo { Foo{} {...} }` + return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option) + } } else if p.peek_tok.kind == .lcbr && ((p.inside_if && lit0_is_capital && p.tok.lit.len > 1 && !known_var && language == .v) || (p.inside_match_case && p.tok.kind == .name && p.peek_tok.is_next_to(p.tok))) { @@ -2957,7 +2976,7 @@ fn (mut p Parser) name_expr() ast.Expr { p.expr_mod = '' return node } else if is_option && p.tok.kind == .lsbr { - return p.array_init(is_option) + return p.array_init(is_option, ast.void_type) } else if !known_var && language == .v && p.peek_tok.kind == .dot && !p.pref.is_fmt { peek_tok2 := p.peek_token(2) peek_tok3 := p.peek_token(3) diff --git a/vlib/v/tests/alias_array_no_cast_init_test.v b/vlib/v/tests/alias_array_no_cast_init_test.v new file mode 100644 index 00000000000000..a5cd423d727be8 --- /dev/null +++ b/vlib/v/tests/alias_array_no_cast_init_test.v @@ -0,0 +1,12 @@ +pub type Labels = [][]int + +pub fn new_labels(width int, height int) Labels { + mut labels := Labels{len: height, init: []int{len: width}} + return labels +} + +fn test_alias_array_no_cast_init() { + mut labels := new_labels(2, 2) + println(labels) + assert labels == [[0, 0], [0, 0]] +}