mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: fix generics with nested generics fn (#9757)
This commit is contained in:
parent
e2be3ec396
commit
8cb44ed9db
|
@ -389,6 +389,7 @@ pub mut:
|
||||||
scope &Scope
|
scope &Scope
|
||||||
label_names []string
|
label_names []string
|
||||||
pos token.Position // function declaration position
|
pos token.Position // function declaration position
|
||||||
|
cur_generic_types []Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// break, continue
|
// break, continue
|
||||||
|
|
|
@ -62,7 +62,6 @@ pub mut:
|
||||||
inside_anon_fn bool
|
inside_anon_fn bool
|
||||||
inside_ref_lit bool
|
inside_ref_lit bool
|
||||||
skip_flags bool // should `#flag` and `#include` be skipped
|
skip_flags bool // should `#flag` and `#include` be skipped
|
||||||
cur_generic_types []ast.Type
|
|
||||||
mut:
|
mut:
|
||||||
files []ast.File
|
files []ast.File
|
||||||
expr_level int // to avoid infinite recursion segfaults due to compiler bugs
|
expr_level int // to avoid infinite recursion segfaults due to compiler bugs
|
||||||
|
@ -476,7 +475,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||||
// Make sure the first letter is capital, do not allow e.g. `x := string{}`,
|
// Make sure the first letter is capital, do not allow e.g. `x := string{}`,
|
||||||
// but `x := T{}` is ok.
|
// but `x := T{}` is ok.
|
||||||
if !c.is_builtin_mod && !c.inside_unsafe && type_sym.language == .v
|
if !c.is_builtin_mod && !c.inside_unsafe && type_sym.language == .v
|
||||||
&& c.cur_generic_types.len == 0 {
|
&& c.cur_fn.cur_generic_types.len == 0 {
|
||||||
pos := type_sym.name.last_index('.') or { -1 }
|
pos := type_sym.name.last_index('.') or { -1 }
|
||||||
first_letter := type_sym.name[pos + 1]
|
first_letter := type_sym.name[pos + 1]
|
||||||
if !first_letter.is_capital() {
|
if !first_letter.is_capital() {
|
||||||
|
@ -1492,13 +1491,8 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if has_generic_generic {
|
if has_generic_generic {
|
||||||
if c.mod != '' {
|
|
||||||
// Need to prepend the module when adding a generic type to a function
|
|
||||||
c.table.register_fn_generic_types(c.mod + '.' + call_expr.name, generic_types)
|
|
||||||
} else {
|
|
||||||
c.table.register_fn_generic_types(call_expr.name, generic_types)
|
c.table.register_fn_generic_types(call_expr.name, generic_types)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: remove this for actual methods, use only for compiler magic
|
// TODO: remove this for actual methods, use only for compiler magic
|
||||||
// FIXME: Argument count != 1 will break these
|
// FIXME: Argument count != 1 will break these
|
||||||
if left_type_sym.kind == .array && method_name in checker.array_builtin_methods {
|
if left_type_sym.kind == .array && method_name in checker.array_builtin_methods {
|
||||||
|
@ -2653,7 +2647,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||||
mut expected_types := [expected_type]
|
mut expected_types := [expected_type]
|
||||||
if expected_type_sym.info is ast.MultiReturn {
|
if expected_type_sym.info is ast.MultiReturn {
|
||||||
expected_types = expected_type_sym.info.types
|
expected_types = expected_type_sym.info.types
|
||||||
if c.cur_generic_types.len > 0 {
|
if c.cur_fn.cur_generic_types.len > 0 {
|
||||||
expected_types = expected_types.map(c.unwrap_generic(it))
|
expected_types = expected_types.map(c.unwrap_generic(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4055,7 +4049,7 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
|
||||||
|
|
||||||
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
|
pub fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
|
||||||
if typ.has_flag(.generic) {
|
if typ.has_flag(.generic) {
|
||||||
if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_generic_types) {
|
if t_typ := c.table.resolve_generic_by_names(typ, c.cur_fn.generic_names, c.cur_fn.cur_generic_types) {
|
||||||
return t_typ
|
return t_typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6333,19 +6327,19 @@ fn (mut c Checker) post_process_generic_fns() {
|
||||||
mut node := c.file.generic_fns[i]
|
mut node := c.file.generic_fns[i]
|
||||||
c.mod = node.mod
|
c.mod = node.mod
|
||||||
for gen_types in c.table.fn_generic_types[node.name] {
|
for gen_types in c.table.fn_generic_types[node.name] {
|
||||||
c.cur_generic_types = gen_types
|
node.cur_generic_types = gen_types
|
||||||
c.fn_decl(mut node)
|
c.fn_decl(mut node)
|
||||||
if node.name in ['vweb.run_app', 'vweb.run'] {
|
if node.name in ['vweb.run_app', 'vweb.run'] {
|
||||||
c.vweb_gen_types << gen_types
|
c.vweb_gen_types << gen_types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.cur_generic_types = []
|
node.cur_generic_types = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
c.returns = false
|
c.returns = false
|
||||||
if node.generic_names.len > 0 && c.cur_generic_types.len == 0 {
|
if node.generic_names.len > 0 && node.cur_generic_types.len == 0 {
|
||||||
// Just remember the generic function for now.
|
// Just remember the generic function for now.
|
||||||
// It will be processed later in c.post_process_generic_fns,
|
// It will be processed later in c.post_process_generic_fns,
|
||||||
// after all other normal functions are processed.
|
// after all other normal functions are processed.
|
||||||
|
|
29
vlib/v/tests/generics_with_nested_generics_fn_test.v
Normal file
29
vlib/v/tests/generics_with_nested_generics_fn_test.v
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
struct NestedGeneric {
|
||||||
|
a int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
mut:
|
||||||
|
context Context
|
||||||
|
}
|
||||||
|
|
||||||
|
fn method_test<T>(mut app T) int {
|
||||||
|
ng := NestedGeneric{}
|
||||||
|
ng.nested_test<T>(app)
|
||||||
|
return 22
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (ng NestedGeneric) nested_test<T>(mut app T) {
|
||||||
|
app.context = Context{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generics_with_generics_fn() {
|
||||||
|
mut app := App{}
|
||||||
|
ret := method_test(mut app)
|
||||||
|
println('result = $ret')
|
||||||
|
assert ret == 22
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user