1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast, checker: check generic fn declaration error (#15079)

This commit is contained in:
yuyi 2022-07-15 19:18:06 +08:00 committed by GitHub
parent b4ed5d5f20
commit 57c4188d98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 1 deletions

View File

@ -1686,6 +1686,70 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
return none
}
fn generic_names_push_with_filter(mut to_names []string, from_names []string) {
for name in from_names {
if name !in to_names {
to_names << name
}
}
}
pub fn (mut t Table) generic_type_names(generic_type Type) []string {
mut names := []string{}
mut sym := t.sym(generic_type)
if sym.name.len == 1 && sym.name[0].is_capital() {
names << sym.name
return names
}
match mut sym.info {
Array {
mut elem_type := sym.info.elem_type
mut elem_sym := t.sym(elem_type)
mut dims := 1
for mut elem_sym.info is Array {
elem_type = elem_sym.info.elem_type
elem_sym = t.sym(elem_type)
dims++
}
names << t.generic_type_names(elem_type)
}
ArrayFixed {
names << t.generic_type_names(sym.info.elem_type)
}
Chan {
names << t.generic_type_names(sym.info.elem_type)
}
FnType {
mut func := sym.info.func
if func.return_type.has_flag(.generic) {
names << t.generic_type_names(func.return_type)
}
func.params = func.params.clone()
for mut param in func.params {
if param.typ.has_flag(.generic) {
generic_names_push_with_filter(mut names, t.generic_type_names(param.typ))
}
}
}
MultiReturn {
for ret_type in sym.info.types {
generic_names_push_with_filter(mut names, t.generic_type_names(ret_type))
}
}
Map {
names << t.generic_type_names(sym.info.key_type)
generic_names_push_with_filter(mut names, t.generic_type_names(sym.info.value_type))
}
Struct, Interface, SumType {
if sym.info.is_generic {
names << sym.info.generic_types.map(t.sym(it).name)
}
}
else {}
}
return names
}
pub fn (mut t Table) unwrap_generic_type(typ Type, generic_names []string, concrete_types []Type) Type {
mut final_concrete_types := []Type{}
mut fields := []StructField{}

View File

@ -207,7 +207,16 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
}
}
}
//&& node.params.len == 1 && param.typ.is_ptr() {
if param.typ.has_flag(.generic) {
generic_names := c.table.generic_type_names(param.typ)
for name in generic_names {
if name !in node.generic_names {
fn_generic_names := node.generic_names.join(', ')
c.error('generic type name `$name` is not mentioned in fn `$node.name<$fn_generic_names>`',
param.type_pos)
}
}
}
if (c.pref.translated || c.file.is_translated) && node.is_variadic && param.typ.is_ptr() {
// TODO c2v hack to fix `(const char *s, ...)`
param.typ = ast.int_type.ref()

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/generic_fn_decl_err_a.vv:17:28: error: generic type name `P` is not mentioned in fn `create<U>`
15 | }
16 |
17 | fn (r Db) create<U>(u U, p P) {
| ^
18 | println('Yo')
19 | }

View File

@ -0,0 +1,19 @@
module main
struct Db {}
struct User {}
struct Post {}
fn main() {
r := Db{}
u := User{}
p := Post{}
r.create(u, p)
}
fn (r Db) create<U>(u U, p P) {
println('Yo')
}