all: fix generic functions with pointer args (#10686)
							parent
							
								
									9eee6631cc
								
							
						
					
					
						commit
						d14de5fdaf
					
				|  | @ -1180,7 +1180,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 			return none | 			return none | ||||||
| 		} | 		} | ||||||
| 		typ := concrete_types[index] | 		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 { | 	match mut sym.info { | ||||||
| 		Array { | 		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) { | 			if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) { | ||||||
| 				idx := t.find_or_register_array_with_dims(typ, dims) | 				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 { | 		ArrayFixed { | ||||||
|  | @ -1203,7 +1203,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 				concrete_types) | 				concrete_types) | ||||||
| 			{ | 			{ | ||||||
| 				idx := t.find_or_register_array_fixed(typ, sym.info.size, None{}) | 				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 { | 		Chan { | ||||||
|  | @ -1211,7 +1211,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 				concrete_types) | 				concrete_types) | ||||||
| 			{ | 			{ | ||||||
| 				idx := t.find_or_register_chan(typ, typ.nr_muls() > 0) | 				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 { | 		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) | 			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 { | 		MultiReturn { | ||||||
| 			mut types := []Type{} | 			mut types := []Type{} | ||||||
|  | @ -1249,7 +1249,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 			} | 			} | ||||||
| 			if type_changed { | 			if type_changed { | ||||||
| 				idx := t.find_or_register_multi_return(types) | 				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 { | 		Map { | ||||||
|  | @ -1270,7 +1270,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 			} | 			} | ||||||
| 			if type_changed { | 			if type_changed { | ||||||
| 				idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type) | 				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 { | 		Struct { | ||||||
|  | @ -1292,7 +1292,7 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name | ||||||
| 				if idx == 0 { | 				if idx == 0 { | ||||||
| 					idx = t.add_placeholder_type(nrt, .v) | 					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 {} | 		else {} | ||||||
|  |  | ||||||
|  | @ -252,6 +252,12 @@ pub fn (t Type) derive(t_from Type) Type { | ||||||
| 	return (0xffff0000 & t_from) | u16(t) | 	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`
 | // return new type with TypeSymbol idx set to `idx`
 | ||||||
| [inline] | [inline] | ||||||
| pub fn new_type(idx int) Type { | pub fn new_type(idx int) Type { | ||||||
|  |  | ||||||
|  | @ -1677,9 +1677,8 @@ fn (mut f Fmt) write_generic_if_require(node ast.CallExpr) { | ||||||
| 	if node.concrete_types.len > 0 { | 	if node.concrete_types.len > 0 { | ||||||
| 		f.write('<') | 		f.write('<') | ||||||
| 		for i, concrete_type in node.concrete_types { | 		for i, concrete_type in node.concrete_types { | ||||||
| 			is_last := i == node.concrete_types.len - 1 | 			f.write(f.table.type_to_str_using_aliases(concrete_type, f.mod2alias)) | ||||||
| 			f.write(f.table.type_to_str(concrete_type)) | 			if i != node.concrete_types.len - 1 { | ||||||
| 			if !is_last { |  | ||||||
| 				f.write(', ') | 				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:
 | 		// Force usage of full path to const in the same module:
 | ||||||
| 		// `println(minute)` => `println(time.minute)`
 | 		// `println(minute)` => `println(time.minute)`
 | ||||||
| 		// This makes it clear that a module const is being used
 | 		// 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.
 | 		// ^^^ except for `main`, where consts are allowed to not have a `main.` prefix.
 | ||||||
| 		if !node.name.contains('.') && !f.inside_const { | 		if !node.name.contains('.') && !f.inside_const { | ||||||
| 			mod := f.cur_mod | 			mod := f.cur_mod | ||||||
|  |  | ||||||
|  | @ -582,6 +582,23 @@ fn (mut g Gen) base_type(t ast.Type) string { | ||||||
| 	return styp | 	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<string> and get_string
 | ||||||
|  | 	// `foo<int>()` => `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 { | fn (mut g Gen) expr_string(expr ast.Expr) string { | ||||||
| 	pos := g.out.len | 	pos := g.out.len | ||||||
| 	g.expr(expr) | 	g.expr(expr) | ||||||
|  |  | ||||||
|  | @ -190,15 +190,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { | ||||||
| 		name = c_name(name) | 		name = c_name(name) | ||||||
| 	} | 	} | ||||||
| 	mut type_name := g.typ(node.return_type) | 	mut type_name := g.typ(node.return_type) | ||||||
| 	if g.table.cur_concrete_types.len > 0 { | 
 | ||||||
| 		// foo<T>() => foo_T_int(), foo_T_string() etc
 | 	name = g.generic_fn_name(g.table.cur_concrete_types, name, true) | ||||||
| 		// Using _T_ to differentiate between get<string> and get_string
 | 
 | ||||||
| 		name += '_T' |  | ||||||
| 		for concrete_type in g.table.cur_concrete_types { |  | ||||||
| 			gen_name := g.typ(concrete_type) |  | ||||||
| 			name += '_' + gen_name |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') | 	if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') | ||||||
| 		&& name != 'main__main' && node.name != 'str' { | 		&& name != 'main__main' && node.name != 'str' { | ||||||
| 		mut key := node.name | 		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 { | 	name = g.generic_fn_name(node.concrete_types, name, false) | ||||||
| 		if concrete_type != ast.void_type && concrete_type != 0 { |  | ||||||
| 			// Using _T_ to differentiate between get<string> and get_string
 |  | ||||||
| 			// `foo<int>()` => `foo_T_int()`
 |  | ||||||
| 			if i == 0 { |  | ||||||
| 				name += '_T' |  | ||||||
| 			} |  | ||||||
| 			name += '_' + g.typ(concrete_type) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	// TODO2
 | 	// TODO2
 | ||||||
| 	// g.generate_tmp_autofree_arg_vars(node, name)
 | 	// 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') | 			panic('cgen: obf name "$key" not found, this should never happen') | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	for i, concrete_type in node.concrete_types { | 	name = g.generic_fn_name(node.concrete_types, name, false) | ||||||
| 		// Using _T_ to differentiate between get<string> and get_string
 |  | ||||||
| 		// `foo<int>()` => `foo_T_int()`
 |  | ||||||
| 		if i == 0 { |  | ||||||
| 			name += '_T' |  | ||||||
| 		} |  | ||||||
| 		name += '_' + g.typ(concrete_type) |  | ||||||
| 	} |  | ||||||
| 	// TODO2
 | 	// TODO2
 | ||||||
| 	// cgen shouldn't modify ast nodes, this should be moved
 | 	// cgen shouldn't modify ast nodes, this should be moved
 | ||||||
| 	// g.generate_tmp_autofree_arg_vars(node, name)
 | 	// g.generate_tmp_autofree_arg_vars(node, name)
 | ||||||
|  |  | ||||||
|  | @ -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`).
 | //	   otherwise it is not generic because it may be multi-value (e.g. `return f < foo, 0`).
 | ||||||
| // 5. `f<mod.Foo>` is same as case 3
 | // 5. `f<mod.Foo>` is same as case 3
 | ||||||
| // 6. `f<mod.Foo,` is same as case 4
 | // 6. `f<mod.Foo,` is same as case 4
 | ||||||
| // 7. otherwise, it's not generic
 | // 7. if there is a &, ignore the & and see if it is a type
 | ||||||
|  | // 10. otherwise, it's not generic
 | ||||||
| // see also test_generic_detection in vlib/v/tests/generics_test.v
 | // see also test_generic_detection in vlib/v/tests/generics_test.v
 | ||||||
| fn (p &Parser) is_generic_call() bool { | fn (p &Parser) is_generic_call() bool { | ||||||
| 	lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 { | 	lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 { | ||||||
|  | @ -1863,11 +1864,21 @@ fn (p &Parser) is_generic_call() bool { | ||||||
| 	if lit0_is_capital || p.peek_tok.kind != .lt { | 	if lit0_is_capital || p.peek_tok.kind != .lt { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	tok2 := p.peek_token(2) | 	mut tok2 := p.peek_token(2) | ||||||
| 	tok3 := p.peek_token(3) | 	mut tok3 := p.peek_token(3) | ||||||
| 	tok4 := p.peek_token(4) | 	mut tok4 := p.peek_token(4) | ||||||
| 	tok5 := p.peek_token(5) | 	mut tok5 := p.peek_token(5) | ||||||
| 	kind2, kind3, kind4, kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind | 	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 { | 	if kind2 == .lsbr { | ||||||
| 		// case 1
 | 		// case 1
 | ||||||
|  |  | ||||||
|  | @ -15,7 +15,8 @@ fn test_identity() { | ||||||
| 		'a': 'b' | 		'a': 'b' | ||||||
| 	})['a'] == 'b' | 	})['a'] == 'b' | ||||||
| 
 | 
 | ||||||
| 	assert simple<simplemodule.Data>(simplemodule.Data{ value: 0 }).value == 0 | 	assert simple<simplemodule.Data>(simplemodule.Data{ value: 8 }).value == 8 | ||||||
|  | 	assert simple<&simplemodule.Data>(&simplemodule.Data{ value: 123 }).value == 123 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn plus<T>(xxx T, b T) T { | fn plus<T>(xxx T, b T) T { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue