mirror of
https://github.com/vlang/v.git
synced 2025-09-09 23:39:39 -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
|
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.
|
// resolve_generic_to_concrete resolves generics to real types T => int.
|
||||||
// Even map[string]map[string]T can be resolved.
|
// 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.
|
// 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 (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' {
|
if fn_name == 'main' {
|
||||||
c.error('the `main` function cannot be called in the program', node.pos)
|
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
|
is_selector_call = true
|
||||||
}
|
}
|
||||||
mut name := node.name
|
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']
|
is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic']
|
||||||
print_method := name
|
print_method := name
|
||||||
is_json_encode := name == 'json.encode'
|
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{} {...} }`
|
// `if a == Foo{} {...}` or `match foo { Foo{} {...} }`
|
||||||
return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option)
|
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 {
|
} else if p.peek_tok.kind == .dot && lit0_is_capital && !known_var && language == .v {
|
||||||
// T.name
|
// T.name selector
|
||||||
if p.is_generic_name() {
|
if p.is_generic_name() && p.peek_token(3).kind != .lpar {
|
||||||
pos := p.tok.pos()
|
pos := p.tok.pos()
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
p.check(.dot)
|
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