ast, checker: fix error for calling complex nested generic type function (fix #13025) (#13328)

pull/13332/head weekly.2022.05
yuyi 2022-01-31 19:00:27 +08:00 committed by GitHub
parent 46a096b95d
commit b34860e39b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 7 deletions

View File

@ -1428,8 +1428,12 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
if typ == 0 { if typ == 0 {
return none return none
} }
if typ.has_flag(.generic) {
return typ.derive_add_muls(generic_type).set_flag(.generic)
} else {
return typ.derive_add_muls(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 {
mut elem_type := sym.info.elem_type mut elem_type := sym.info.elem_type
@ -1443,32 +1447,48 @@ 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)
if typ.has_flag(.generic) {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
} }
} }
}
ArrayFixed { ArrayFixed {
if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names, if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names,
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{})
if typ.has_flag(.generic) {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
} }
} }
}
Chan { Chan {
if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names, if typ := t.resolve_generic_to_concrete(sym.info.elem_type, generic_names,
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)
if typ.has_flag(.generic) {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
} }
} }
}
FnType { FnType {
mut func := sym.info.func mut func := sym.info.func
mut has_generic := false
if func.return_type.has_flag(.generic) { if func.return_type.has_flag(.generic) {
if typ := t.resolve_generic_to_concrete(func.return_type, generic_names, if typ := t.resolve_generic_to_concrete(func.return_type, generic_names,
concrete_types) concrete_types)
{ {
func.return_type = typ func.return_type = typ
if typ.has_flag(.generic) {
has_generic = true
}
} }
} }
func.params = func.params.clone() func.params = func.params.clone()
@ -1478,13 +1498,20 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
concrete_types) concrete_types)
{ {
param.typ = typ param.typ = typ
if typ.has_flag(.generic) {
has_generic = true
}
} }
} }
} }
func.name = '' func.name = ''
idx := t.find_or_register_fn_type('', func, true, false) idx := t.find_or_register_fn_type('', func, true, false)
if has_generic {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(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{}
mut type_changed := false mut type_changed := false
@ -1498,9 +1525,13 @@ 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)
if types.any(it.has_flag(.generic)) {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
} }
} }
}
Map { Map {
mut type_changed := false mut type_changed := false
mut unwrapped_key_type := sym.info.key_type mut unwrapped_key_type := sym.info.key_type
@ -1519,9 +1550,13 @@ 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)
if unwrapped_key_type.has_flag(.generic) || unwrapped_value_type.has_flag(.generic) {
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
} else {
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic) return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
} }
} }
}
Struct, Interface, SumType { Struct, Interface, SumType {
if sym.info.is_generic { if sym.info.is_generic {
mut nrt := '$sym.name<' mut nrt := '$sym.name<'

View File

@ -963,6 +963,13 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
} }
if func.generic_names.len > 0 { if func.generic_names.len > 0 {
if has_generic { if has_generic {
if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
node.concrete_types)
{
if typ.has_flag(.generic) {
node.return_type = typ
}
}
return node.return_type return node.return_type
} else if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names, } else if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
concrete_types) concrete_types)

View File

@ -0,0 +1,26 @@
fn test_generics_with_complex_nested_generics_type() {
mut buf := []byte{}
initial<string, u64>(buf)
}
fn initial<K, V>(buf []byte) map[K]V {
mut ret := map[K]V{}
for _ in 0 .. 3 {
k := get<K>(buf)
v := get<V>(buf)
ret[k] = v
}
println(ret)
assert '$ret' == "{'get': 22}"
return ret
}
fn get<T>(buf []byte) T {
$if T is string {
return buf.bytestr() + 'get'
} $else $if T is u64 {
return u64(22)
} $else {
panic('oops!')
}
}