checker,cgen: stabilise generic method handling (fix a source code ordering issue)

pull/12938/head
Delyan Angelov 2021-12-22 16:16:10 +02:00
parent b3161b05a3
commit e256f1b2aa
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
6 changed files with 53 additions and 3 deletions

View File

@ -488,6 +488,7 @@ pub mut:
return_type_pos token.Position // `string` in `fn (u User) name() string` position
has_return bool
should_be_skipped bool // true, when -skip-unused could not find any usages of that function, starting from main + other known used functions
ninstances int // 0 for generic functions with no concrete instances
has_await bool // 'true' if this function uses JS.await
//
comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl

View File

@ -291,7 +291,7 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) {
c.timers.start('checker_post_process_generic_fns')
last_file := c.file
// post process generic functions. must be done after all files have been
// checked, to eunsure all generic calls are processed as this information
// checked, to ensure all generic calls are processed as this information
// is needed when the generic type is auto inferred from the call argument
// Check more times if there are more new registered fn concrete types
for {
@ -4831,7 +4831,11 @@ fn (mut c Checker) post_process_generic_fns() {
for i in 0 .. c.file.generic_fns.len {
mut node := c.file.generic_fns[i]
c.mod = node.mod
for concrete_types in c.table.fn_generic_types[node.name] {
gtypes := c.table.fn_generic_types[node.name]
$if trace_post_process_generic_fns ? {
eprintln('> post_process_generic_fns $node.mod | $node.name | $gtypes')
}
for concrete_types in gtypes {
c.table.cur_concrete_types = concrete_types
c.fn_decl(mut node)
if node.name == 'vweb.run' {
@ -4843,6 +4847,11 @@ fn (mut c Checker) post_process_generic_fns() {
}
}
c.table.cur_concrete_types = []
$if trace_post_process_generic_fns ? {
if node.generic_names.len > 0 {
eprintln(' > fn_decl node.name: $node.name | generic_names: $node.generic_names | ninstances: $node.ninstances')
}
}
}
}

View File

@ -14,8 +14,10 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
// have a chance to populate c.table.fn_generic_types with
// the correct concrete types.
c.file.generic_fns << node
c.need_recheck_generic_fns = true
return
}
node.ninstances++
// save all the state that fn_decl or inner statements/expressions
// could potentially modify, since functions can be nested, due to
// anonymous function support, and ensure that it is restored, when

View File

@ -4855,6 +4855,10 @@ fn (mut g Gen) return_stmt(node ast.Return) {
has_semicolon = true
}
} else if node.exprs.len >= 1 {
if node.types.len == 0 {
g.checker_bug('node.exprs.len == $node.exprs.len && node.types.len == 0',
node.pos)
}
// normal return
return_sym := g.table.sym(node.types[0])
expr0 := node.exprs[0]

View File

@ -32,6 +32,12 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
if node.should_be_skipped {
return
}
if node.ninstances == 0 && node.generic_names.len > 0 {
$if trace_generics ? {
eprintln('skipping generic fn with no concrete instances: $node.mod $node.name')
}
return
}
if !g.is_used_by_main(node) {
return
}
@ -82,7 +88,8 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
if node.is_main {
g.has_main = true
}
is_backtrace := node.name.starts_with('backtrace') // TODO PERF remove this from here
// TODO PERF remove this from here
is_backtrace := node.name.starts_with('backtrace')
&& node.name in ['backtrace_symbols', 'backtrace', 'backtrace_symbols_fd']
if is_backtrace {
g.write('\n#ifndef __cplusplus\n')

View File

@ -0,0 +1,27 @@
struct Foo<T> {
x int
}
fn (f Foo<T>) pop() {
println('hey')
}
struct Bar<T> {
y int
}
// NB: Bar.foo before Bar.pop, should not cause a V compiler panic
fn (b Bar<T>) foo() bool {
return true
}
fn (b Bar<T>) pop() {
println(b.foo())
}
// fn dummy() { println(Bar<int>{}) }
fn test_foo() {
dump(Foo<int>{})
assert true
}