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:
parent
b4ed5d5f20
commit
57c4188d98
@ -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{}
|
||||
|
@ -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()
|
||||
|
7
vlib/v/checker/tests/generic_fn_decl_err_a.out
Normal file
7
vlib/v/checker/tests/generic_fn_decl_err_a.out
Normal 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 | }
|
19
vlib/v/checker/tests/generic_fn_decl_err_a.vv
Normal file
19
vlib/v/checker/tests/generic_fn_decl_err_a.vv
Normal 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')
|
||||
}
|
Loading…
Reference in New Issue
Block a user