diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index cfc1d04a04..c425b85abe 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1180,7 +1180,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name return none } typ := concrete_types[index] - return typ.derive(generic_type).clear_flag(.generic) + return typ.derive_add_muls(generic_type).clear_flag(.generic) } match mut sym.info { Array { @@ -1195,7 +1195,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) { idx := t.find_or_register_array_with_dims(typ, dims) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } ArrayFixed { @@ -1203,7 +1203,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name concrete_types) { idx := t.find_or_register_array_fixed(typ, sym.info.size, None{}) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } Chan { @@ -1211,7 +1211,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name concrete_types) { idx := t.find_or_register_chan(typ, typ.nr_muls() > 0) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } FnType { @@ -1234,7 +1234,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } } idx := t.find_or_register_fn_type('', func, true, false) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } MultiReturn { mut types := []Type{} @@ -1249,7 +1249,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } if type_changed { idx := t.find_or_register_multi_return(types) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } Map { @@ -1270,7 +1270,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name } if type_changed { idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type) - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } Struct { @@ -1292,7 +1292,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name if idx == 0 { idx = t.add_placeholder_type(nrt, .v) } - return new_type(idx).derive(generic_type).clear_flag(.generic) + return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) } } else {} diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index ec5ecc5ea7..9f5acdb766 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -252,6 +252,12 @@ pub fn (t Type) derive(t_from Type) Type { return (0xffff0000 & t_from) | u16(t) } +// copy flags from `t_from` to `t` and return `t` +[inline] +pub fn (t Type) derive_add_muls(t_from Type) Type { + return Type((0xff000000 & t_from) | u16(t)).set_nr_muls(t.nr_muls() + t_from.nr_muls()) +} + // return new type with TypeSymbol idx set to `idx` [inline] pub fn new_type(idx int) Type { diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 36eeafc795..cd0fad711f 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1677,9 +1677,8 @@ fn (mut f Fmt) write_generic_if_require(node ast.CallExpr) { if node.concrete_types.len > 0 { f.write('<') for i, concrete_type in node.concrete_types { - is_last := i == node.concrete_types.len - 1 - f.write(f.table.type_to_str(concrete_type)) - if !is_last { + f.write(f.table.type_to_str_using_aliases(concrete_type, f.mod2alias)) + if i != node.concrete_types.len - 1 { f.write(', ') } } @@ -1824,7 +1823,7 @@ pub fn (mut f Fmt) ident(node ast.Ident) { // Force usage of full path to const in the same module: // `println(minute)` => `println(time.minute)` // This makes it clear that a module const is being used - // (since V's conts are no longer ALL_CAP). + // (since V's consts are no longer ALL_CAP). // ^^^ except for `main`, where consts are allowed to not have a `main.` prefix. if !node.name.contains('.') && !f.inside_const { mod := f.cur_mod diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 15de443f75..d07a6a6d9d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -582,6 +582,23 @@ fn (mut g Gen) base_type(t ast.Type) string { return styp } +fn (mut g Gen) generic_fn_name(types []ast.Type, before string, is_decl bool) string { + if types.len == 0 { + return before + } + // Using _T_ to differentiate between get and get_string + // `foo()` => `foo_T_int()` + mut name := before + '_T' + for typ in types { + nr_muls := typ.nr_muls() + if is_decl && nr_muls > 0 { + name = strings.repeat(`*`, nr_muls) + name + } + name += '_' + strings.repeat_string('__ptr__', nr_muls) + g.typ(typ.set_nr_muls(0)) + } + return name +} + fn (mut g Gen) expr_string(expr ast.Expr) string { pos := g.out.len g.expr(expr) diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 4b2375e7e5..29849a089a 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -190,15 +190,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { name = c_name(name) } mut type_name := g.typ(node.return_type) - if g.table.cur_concrete_types.len > 0 { - // foo() => foo_T_int(), foo_T_string() etc - // Using _T_ to differentiate between get and get_string - name += '_T' - for concrete_type in g.table.cur_concrete_types { - gen_name := g.typ(concrete_type) - name += '_' + gen_name - } - } + + name = g.generic_fn_name(g.table.cur_concrete_types, name, true) + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && name != 'main__main' && node.name != 'str' { mut key := node.name @@ -726,16 +720,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } } } - for i, concrete_type in node.concrete_types { - if concrete_type != ast.void_type && concrete_type != 0 { - // Using _T_ to differentiate between get and get_string - // `foo()` => `foo_T_int()` - if i == 0 { - name += '_T' - } - name += '_' + g.typ(concrete_type) - } - } + name = g.generic_fn_name(node.concrete_types, name, false) // TODO2 // g.generate_tmp_autofree_arg_vars(node, name) // @@ -923,14 +908,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { panic('cgen: obf name "$key" not found, this should never happen') } } - for i, concrete_type in node.concrete_types { - // Using _T_ to differentiate between get and get_string - // `foo()` => `foo_T_int()` - if i == 0 { - name += '_T' - } - name += '_' + g.typ(concrete_type) - } + name = g.generic_fn_name(node.concrete_types, name, false) // TODO2 // cgen shouldn't modify ast nodes, this should be moved // g.generate_tmp_autofree_arg_vars(node, name) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4dc0470e5c..6a8ba0a484 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1852,7 +1852,8 @@ fn (p &Parser) is_typename(t token.Token) bool { // otherwise it is not generic because it may be multi-value (e.g. `return f < foo, 0`). // 5. `f` is same as case 3 // 6. `f 0 { @@ -1863,11 +1864,21 @@ fn (p &Parser) is_generic_call() bool { if lit0_is_capital || p.peek_tok.kind != .lt { return false } - tok2 := p.peek_token(2) - tok3 := p.peek_token(3) - tok4 := p.peek_token(4) - tok5 := p.peek_token(5) - kind2, kind3, kind4, kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind + mut tok2 := p.peek_token(2) + mut tok3 := p.peek_token(3) + mut tok4 := p.peek_token(4) + mut tok5 := p.peek_token(5) + mut kind2, mut kind3, mut kind4, mut kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind + if kind2 == .amp { // if there is a & in front, shift everything left + tok2 = tok3 + kind2 = kind3 + tok3 = tok4 + kind3 = kind4 + tok4 = tok5 + kind4 = kind5 + tok5 = p.peek_token(6) + kind5 = tok5.kind + } if kind2 == .lsbr { // case 1 diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index 580f27abd8..c6b5a68487 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -15,7 +15,8 @@ fn test_identity() { 'a': 'b' })['a'] == 'b' - assert simple(simplemodule.Data{ value: 0 }).value == 0 + assert simple(simplemodule.Data{ value: 8 }).value == 8 + assert simple<&simplemodule.Data>(&simplemodule.Data{ value: 123 }).value == 123 } fn plus(xxx T, b T) T {