diff --git a/vlib/v/checker/interface.v b/vlib/v/checker/interface.v index 15dd1bf1f2..69f3c90a94 100644 --- a/vlib/v/checker/interface.v +++ b/vlib/v/checker/interface.v @@ -272,6 +272,27 @@ fn (mut c Checker) resolve_generic_interface(typ ast.Type, interface_type ast.Ty ret_typ = ret_typ.clear_flag(.optional) } inferred_type = ret_typ + } else if imret_sym.info is ast.SumType && mret_sym.info is ast.SumType { + im_generic_names := imret_sym.info.generic_types.map(c.table.sym(it).name) + if gt_name in im_generic_names + && imret_sym.info.generic_types.len == mret_sym.info.concrete_types.len { + idx := im_generic_names.index(gt_name) + inferred_type = mret_sym.info.concrete_types[idx] + } + } else if imret_sym.info is ast.Interface && mret_sym.info is ast.Interface { + im_generic_names := imret_sym.info.generic_types.map(c.table.sym(it).name) + if gt_name in im_generic_names + && imret_sym.info.generic_types.len == mret_sym.info.concrete_types.len { + idx := im_generic_names.index(gt_name) + inferred_type = mret_sym.info.concrete_types[idx] + } + } else if imret_sym.info is ast.Struct && mret_sym.info is ast.Struct { + im_generic_names := imret_sym.info.generic_types.map(c.table.sym(it).name) + if gt_name in im_generic_names + && imret_sym.info.generic_types.len == mret_sym.info.concrete_types.len { + idx := im_generic_names.index(gt_name) + inferred_type = mret_sym.info.concrete_types[idx] + } } } for i, iparam in imethod.params { diff --git a/vlib/v/tests/generics_interface_with_generic_sumtype_test.v b/vlib/v/tests/generics_interface_with_generic_sumtype_test.v new file mode 100644 index 0000000000..97759014b2 --- /dev/null +++ b/vlib/v/tests/generics_interface_with_generic_sumtype_test.v @@ -0,0 +1,81 @@ +// optional.v +struct NonValue {} + +pub type Optional = NonValue | T + +pub fn (self Optional) is_some() bool { + return self is T +} + +pub fn (self Optional) is_none() bool { + return !self.is_some() +} + +pub fn (self Optional) expect(msg string) T { + if self.is_some() { + return self as T + } else { + panic(msg) + } +} + +pub fn (self Optional) unwrap() T { + return self.expect('unwrap on a none value') +} + +pub fn (self Optional) unwrap_or(default T) T { + if self.is_some() { + return self as T + } else { + return default + } +} + +pub fn (self Optional) unwrap_or_else(else_fn fn () T) T { + if self.is_some() { + return self as T + } else { + return else_fn() + } +} + +pub fn some(value T) Optional { + return Optional(value as T) +} + +pub fn null() Optional { + return Optional(NonValue{}) +} + +// iter.v +pub interface Iterator { +mut: + next() Optional +} + +pub fn (mut self Iterator) count() int { + mut count := 0 + for self.next().is_some() { + count += 1 + } + return count +} + +struct EmptyIter { + value NonValue +} + +fn (mut self EmptyIter) next() Optional { + return Optional(self.value) +} + +// iter_test.v +fn test_generics_interface_with_generic_sumtype() { + mut iter1 := EmptyIter{} + println(iter1) + assert iter1.next().is_none() + + mut iter2 := Iterator(iter1) + println(iter2) + assert iter2.count() == 0 +}