mirror of
https://github.com/vlang/v.git
synced 2025-09-09 15:27:05 -04:00
checker, parser, cgen: allow static call on generic type (#21071)
This commit is contained in:
parent
dbdbfe24a5
commit
29e5124c48
@ -1544,6 +1544,23 @@ pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (mut t Table) resolve_generic_static_type_name(fn_name string, generic_names []string, concrete_types []Type) string {
|
||||
if index := fn_name.index('__static__') {
|
||||
if index > 0 {
|
||||
generic_name := fn_name[0..index]
|
||||
valid_generic := util.is_generic_type_name(generic_name)
|
||||
&& generic_name in generic_names
|
||||
if valid_generic {
|
||||
name_type := Type(t.find_type_idx(generic_name)).set_flag(.generic)
|
||||
if typ := t.resolve_generic_to_concrete(name_type, generic_names, concrete_types) {
|
||||
return '${t.type_to_str(typ)}${fn_name[index..]}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fn_name
|
||||
}
|
||||
|
||||
// resolve_generic_to_concrete resolves generics to real types T => int.
|
||||
// Even map[string]map[string]T can be resolved.
|
||||
// This is used for resolving the generic return type of CallExpr white `unwrap_generic` is used to resolve generic usage in FnDecl.
|
||||
|
@ -676,7 +676,14 @@ fn (mut c Checker) needs_unwrap_generic_type(typ ast.Type) bool {
|
||||
}
|
||||
|
||||
fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type {
|
||||
fn_name := node.name
|
||||
mut fn_name := node.name
|
||||
if index := node.name.index('__static__') {
|
||||
// resolve static call T.name()
|
||||
if index > 0 && c.table.cur_fn != unsafe { nil } {
|
||||
fn_name = c.table.resolve_generic_static_type_name(fn_name, c.table.cur_fn.generic_names,
|
||||
c.table.cur_concrete_types)
|
||||
}
|
||||
}
|
||||
if fn_name == 'main' {
|
||||
c.error('the `main` function cannot be called in the program', node.pos)
|
||||
}
|
||||
|
@ -1783,6 +1783,13 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
is_selector_call = true
|
||||
}
|
||||
mut name := node.name
|
||||
if index := node.name.index('__static__') {
|
||||
// resolve static call T.name()
|
||||
if index > 0 && g.cur_fn != unsafe { nil } {
|
||||
name = g.table.resolve_generic_static_type_name(node.name, g.cur_fn.generic_names,
|
||||
g.cur_concrete_types)
|
||||
}
|
||||
}
|
||||
is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic']
|
||||
print_method := name
|
||||
is_json_encode := name == 'json.encode'
|
||||
|
@ -2889,8 +2889,8 @@ fn (mut p Parser) name_expr() ast.Expr {
|
||||
// `if a == Foo{} {...}` or `match foo { Foo{} {...} }`
|
||||
return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option)
|
||||
} else if p.peek_tok.kind == .dot && lit0_is_capital && !known_var && language == .v {
|
||||
// T.name
|
||||
if p.is_generic_name() {
|
||||
// T.name selector
|
||||
if p.is_generic_name() && p.peek_token(3).kind != .lpar {
|
||||
pos := p.tok.pos()
|
||||
name := p.check_name()
|
||||
p.check(.dot)
|
||||
|
63
vlib/v/tests/generic_static_call_test.v
Normal file
63
vlib/v/tests/generic_static_call_test.v
Normal file
@ -0,0 +1,63 @@
|
||||
module main
|
||||
|
||||
type Tag = int
|
||||
type Octet = string
|
||||
|
||||
fn (o Octet) tag() Tag {
|
||||
return Tag(1)
|
||||
}
|
||||
|
||||
fn (o Octet) pack() ![]u8 {
|
||||
return o.bytes()
|
||||
}
|
||||
|
||||
fn (o Octet) bytes() []u8 {
|
||||
s := string(o)
|
||||
return s.bytes()
|
||||
}
|
||||
|
||||
// static method on concrete type
|
||||
fn Octet.unpack(b []u8) Octet {
|
||||
return Octet(b.bytestr())
|
||||
}
|
||||
|
||||
// This is generic type
|
||||
struct Elm[T] {
|
||||
mut:
|
||||
val T
|
||||
}
|
||||
|
||||
fn Elm.new[T](val T) Elm[T] {
|
||||
return Elm[T]{
|
||||
val: val
|
||||
}
|
||||
}
|
||||
|
||||
fn (el Elm[T]) the_t() T {
|
||||
return el.val
|
||||
}
|
||||
|
||||
fn Elm.unpack[T](src []u8) !Elm[T] {
|
||||
t := T.unpack(src)
|
||||
return Elm[T]{t}
|
||||
}
|
||||
|
||||
fn (el Elm[T]) tag() Tag {
|
||||
return el.val.tag()
|
||||
}
|
||||
|
||||
fn (el Elm[T]) pack() ![]u8 {
|
||||
return el.val.pack()!
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
b := Octet('xx')
|
||||
mut el := Elm.new[Octet](b)
|
||||
bytes := el.pack()!
|
||||
assert bytes == [u8(120), 120]
|
||||
|
||||
// unpack
|
||||
ab := Elm.unpack[Octet](bytes)!
|
||||
assert el == ab
|
||||
assert el.the_t() == Octet('xx')
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user