From 73f3dce5c7a81f23f2ae8ec7bf085237d431aca5 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:19 +0300 Subject: [PATCH] checker: fix cannot match generic type in generic function (fixes #24648) --- vlib/v/checker/checker.v | 24 ++++++++++++++++++- ...eneric_match_generic_interface_type_test.v | 21 ++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/generics/generic_match_generic_interface_type_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 56a761816..d8ac3368f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1730,6 +1730,28 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) { return to_lock, pos } +fn (mut c Checker) unwrap_generic_concrete_type(typ ast.Type) ast.Type { + utyp := c.unwrap_generic(typ) + if !c.needs_unwrap_generic_type(typ) || c.table.sym(utyp).kind != .placeholder { + return utyp + } + if c.inside_generic_struct_init { + generic_names := c.cur_struct_generic_types.map(c.table.sym(it).name) + return c.table.unwrap_generic_type(typ, generic_names, c.cur_struct_concrete_types) + } + if c.table.cur_fn != unsafe { nil } { + resolved := c.table.unwrap_generic_type(typ, c.table.cur_fn.generic_names, c.table.cur_concrete_types) + if c.table.sym(resolved).kind != .placeholder { + return resolved + } + if c.inside_lambda && c.table.cur_lambda.call_ctx != unsafe { nil } { + return c.table.unwrap_generic_type(typ, c.table.cur_lambda.func.decl.generic_names, + c.table.cur_lambda.call_ctx.concrete_types) + } + } + return utyp +} + fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos token.Pos) bool { mut resolved_interface_type := c.unwrap_generic(interface_type) if typ == resolved_interface_type { @@ -1738,7 +1760,7 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to $if debug_interface_type_implements ? { eprintln('> type_implements typ: ${typ.debug()} (`${c.table.type_to_str(typ)}`) | inter_typ: ${resolved_interface_type.debug()} (`${c.table.type_to_str(resolved_interface_type)}`)') } - utyp := c.unwrap_generic(typ) + utyp := c.unwrap_generic_concrete_type(typ) styp := c.table.type_to_str(utyp) typ_sym := c.table.sym(utyp) mut inter_sym := c.table.final_sym(resolved_interface_type) diff --git a/vlib/v/tests/generics/generic_match_generic_interface_type_test.v b/vlib/v/tests/generics/generic_match_generic_interface_type_test.v new file mode 100644 index 000000000..34f3e97fa --- /dev/null +++ b/vlib/v/tests/generics/generic_match_generic_interface_type_test.v @@ -0,0 +1,21 @@ +interface Named { + get_name() string +} + +struct GenericValue[T] implements Named {} + +fn (g GenericValue[T]) get_name() string { + return T.name +} + +fn is_match[T](base Named) bool { + match base { + GenericValue[T] { return true } + else { return false } + } +} + +fn test_match_generic_type_in_generic_fn_without_preinstantiation() { + base := Named(GenericValue[int]{}) + assert !is_match[string](base) +} -- 2.39.5