checker: fix generics with generic struct receiver (#9658)
parent
5273214ec2
commit
bf6a2f80ef
|
@ -1108,7 +1108,9 @@ pub fn (mut t Table) generic_struct_insts_to_concrete() {
|
|||
fields[i] = field
|
||||
}
|
||||
parent_info.generic_types = []
|
||||
parent_info.concrete_types = info.generic_types.clone()
|
||||
parent_info.fields = fields
|
||||
parent_info.parent_type = new_type(info.parent_idx).set_flag(.generic)
|
||||
typ.is_public = true
|
||||
typ.kind = .struct_
|
||||
typ.info = parent_info
|
||||
|
|
|
@ -721,6 +721,8 @@ pub mut:
|
|||
is_union bool
|
||||
is_heap bool
|
||||
generic_types []Type
|
||||
concrete_types []Type
|
||||
parent_type Type
|
||||
}
|
||||
|
||||
// instantiation of a generic struct
|
||||
|
|
|
@ -486,6 +486,16 @@ pub fn (mut c Checker) infer_fn_types(f ast.Fn, mut call_expr ast.CallExpr) {
|
|||
mut typ := ast.void_type
|
||||
for i, param in f.params {
|
||||
mut to_set := ast.void_type
|
||||
// resolve generic struct receiver (TODO: multi generic struct)
|
||||
if i == 0 && call_expr.is_method && param.typ.has_flag(.generic) {
|
||||
sym := c.table.get_type_symbol(call_expr.receiver_type)
|
||||
if sym.kind == .struct_ {
|
||||
info := sym.info as ast.Struct
|
||||
if info.concrete_types.len > 0 {
|
||||
typ = info.concrete_types[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
arg_i := if i != 0 && call_expr.is_method { i - 1 } else { i }
|
||||
if call_expr.args.len <= arg_i {
|
||||
break
|
||||
|
|
|
@ -1464,7 +1464,7 @@ fn (mut c Checker) check_return_generics_struct(return_type ast.Type, mut call_e
|
|||
pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||
left_type := c.expr(call_expr.left)
|
||||
c.expected_type = left_type
|
||||
is_generic := left_type.has_flag(.generic)
|
||||
mut is_generic := left_type.has_flag(.generic)
|
||||
call_expr.left_type = left_type
|
||||
// Set default values for .return_type & .receiver_type too,
|
||||
// or there will be hard to diagnose 0 type panics in cgen.
|
||||
|
@ -1533,6 +1533,14 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
} else {
|
||||
// can this logic be moved to ast.type_find_method() so it can be used from anywhere
|
||||
if left_type_sym.info is ast.Struct {
|
||||
if left_type_sym.info.parent_type != 0 {
|
||||
type_sym := c.table.get_type_symbol(left_type_sym.info.parent_type)
|
||||
if m := c.table.type_find_method(type_sym, method_name) {
|
||||
method = m
|
||||
has_method = true
|
||||
is_generic = true
|
||||
}
|
||||
} else {
|
||||
mut found_methods := []ast.Fn{}
|
||||
mut embed_of_found_methods := []ast.Type{}
|
||||
for embed in left_type_sym.info.embeds {
|
||||
|
@ -1551,6 +1559,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
|||
c.error('ambiguous method `$method_name`', call_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
if left_type_sym.kind == .aggregate {
|
||||
// the error message contains the problematic type
|
||||
unknown_method_msg = err.msg
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
struct Num<T> {
|
||||
num T
|
||||
}
|
||||
|
||||
fn (num Num<T>) is_autom<T>() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
fn test_generics_with_generic_struct_receiver() {
|
||||
num := Num<int>{3}
|
||||
println(num.is_autom())
|
||||
assert num.is_autom()
|
||||
}
|
Loading…
Reference in New Issue