vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.54k stars 2.14k forks source link

Compiler bug: `go fn (){ go func() }()` #21433

Open vcker opened 2 months ago

vcker commented 2 months ago

Describe the bug

this compile error

pub fn (mut me Exchange) start() ! {
    go fn () {
        mut rconn := net.dial_tcp(me.raddr)!
        go me.exchange(me.lconn, mut rconn)
        go me.exchange(rconn, mut me.lconn)
        _ = <-me.end_sig
        me.lconn.close() or {} // ignore
        rconn.close() or {} // ignore
        println('all exchange end')
    }()
}
V panic: final_sym: invalid type (typ=ast.Type(0x0 = 0) idx=0). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.
v hash: 065399e
0   v                                   0x0000000106d4a4a1 v__ast__default_table_panic_handler + 33
1   v                                   0x0000000106d4a4f8 v__ast__Table_panic + 72
2   v                                   0x0000000106d581f2 v__ast__Table_final_sym + 466
3   v                                   0x0000000106e14441 v__checker__Checker_spawn_expr + 257
4   v                                   0x0000000106da7b7a v__checker__Checker_expr + 7722
5   v                                   0x0000000106dc43cf v__checker__Checker_stmt + 1919
6   v                                   0x0000000106dd5ff7 v__checker__Checker_stmts_ending_with_expression + 631
7   v                                   0x0000000106df2568 v__checker__Checker_stmts + 56
8   v                                   0x0000000106e0a29c v__checker__Checker_anon_fn + 1836
9   v                                   0x0000000106da60ff v__checker__Checker_expr + 943
10  v                                   0x0000000106e0cea7 v__checker__Checker_call_expr + 439
11  v                                   0x0000000106e14360 v__checker__Checker_spawn_expr + 32
12  v                                   0x0000000106da7b7a v__checker__Checker_expr + 7722
13  v                                   0x0000000106dc43cf v__checker__Checker_stmt + 1919
14  v                                   0x0000000106dd5ff7 v__checker__Checker_stmts_ending_with_expression + 631
15  v                                   0x0000000106df2568 v__checker__Checker_stmts + 56
16  v                                   0x0000000106df7ce8 v__checker__Checker_fn_decl + 22376
17  v                                   0x0000000106dc46b7 v__checker__Checker_stmt + 2663
18  v                                   0x0000000106dc3b23 v__checker__Checker_check + 4259
19  v                                   0x0000000106dc5573 v__checker__Checker_check_files + 371
20  v                                   0x0000000107030ba8 v__builder__Builder_middle_stages + 216
21  v                                   0x0000000107033098 v__builder__Builder_front_and_middle_stages + 120
22  v                                   0x000000010704a492 v__builder__cbuilder__gen_c + 66
23  v                                   0x000000010704a2b6 v__builder__cbuilder__build_c + 294
24  v                                   0x000000010704a15f v__builder__cbuilder__compile_c + 543
25  v                                   0x00000001070421d1 v__builder__Builder_rebuild + 81
26  v                                   0x00000001070419d8 v__builder__compile + 88
27  v                                   0x000000010704d5d9 main__rebuild + 121
28  v                                   0x000000010704c79a main__main + 2186
29  v                                   0x000000010705216b main + 59
30  dyld                                0x0000000110ed44fe start + 462

put fn(){}() to start_2, it compil ok

pub fn (mut me Exchange) start() ! {
    go me.start_2()
}

pub fn (mut me Exchange) start_2() ! {
    mut rconn := net.dial_tcp(me.raddr)!
    go me.exchange(me.lconn, mut rconn)
    go me.exchange(rconn, mut me.lconn)
    _ = <-me.end_sig
    me.lconn.close() or {} // ignore
    rconn.close() or {} // ignore
    println('all exchange end')
}

Reproduction Steps

v fmt -w exchange.v && v run exchange.v

Expected Behavior

no compile error

Current Behavior

V panic: final_sym: invalid type (typ=ast.Type(0x0 = 0) idx=0). Compiler bug. This should never happen. Please report the bug using `v bug file.v`.
v hash: 065399e
0   v                                   0x0000000106d4a4a1 v__ast__default_table_panic_handler + 33
1   v                                   0x0000000106d4a4f8 v__ast__Table_panic + 72
2   v                                   0x0000000106d581f2 v__ast__Table_final_sym + 466
3   v                                   0x0000000106e14441 v__checker__Checker_spawn_expr + 257
4   v                                   0x0000000106da7b7a v__checker__Checker_expr + 7722
5   v                                   0x0000000106dc43cf v__checker__Checker_stmt + 1919
6   v                                   0x0000000106dd5ff7 v__checker__Checker_stmts_ending_with_expression + 631
7   v                                   0x0000000106df2568 v__checker__Checker_stmts + 56
8   v                                   0x0000000106e0a29c v__checker__Checker_anon_fn + 1836
9   v                                   0x0000000106da60ff v__checker__Checker_expr + 943
10  v                                   0x0000000106e0cea7 v__checker__Checker_call_expr + 439
11  v                                   0x0000000106e14360 v__checker__Checker_spawn_expr + 32
12  v                                   0x0000000106da7b7a v__checker__Checker_expr + 7722
13  v                                   0x0000000106dc43cf v__checker__Checker_stmt + 1919
14  v                                   0x0000000106dd5ff7 v__checker__Checker_stmts_ending_with_expression + 631
15  v                                   0x0000000106df2568 v__checker__Checker_stmts + 56
16  v                                   0x0000000106df7ce8 v__checker__Checker_fn_decl + 22376
17  v                                   0x0000000106dc46b7 v__checker__Checker_stmt + 2663
18  v                                   0x0000000106dc3b23 v__checker__Checker_check + 4259
19  v                                   0x0000000106dc5573 v__checker__Checker_check_files + 371
20  v                                   0x0000000107030ba8 v__builder__Builder_middle_stages + 216
21  v                                   0x0000000107033098 v__builder__Builder_front_and_middle_stages + 120
22  v                                   0x000000010704a492 v__builder__cbuilder__gen_c + 66
23  v                                   0x000000010704a2b6 v__builder__cbuilder__build_c + 294
24  v                                   0x000000010704a15f v__builder__cbuilder__compile_c + 543
25  v                                   0x00000001070421d1 v__builder__Builder_rebuild + 81
26  v                                   0x00000001070419d8 v__builder__compile + 88
27  v                                   0x000000010704d5d9 main__rebuild + 121
28  v                                   0x000000010704c79a main__main + 2186
29  v                                   0x000000010705216b main + 59
30  dyld                                0x0000000110ed44fe start + 462

Possible Solution

No response

Additional Information/Context

// whole file
module main

import net
import time

struct Exchange {
mut:
    is_end  bool
    end_sig chan bool = chan bool{cap: 1}
    raddr   string
    // TLS
    lconn &net.TcpConn
}

fn new_exchange(lconn &net.TcpConn, remoteAddr string) Exchange {
    return Exchange{
        raddr: remoteAddr
        lconn: lconn
    }
}

pub fn (mut me Exchange) start() ! {
    // go me.start_2()
    go fn () {
        mut rconn := net.dial_tcp(me.raddr)!
        go me.exchange(me.lconn, mut rconn)
        go me.exchange(rconn, mut me.lconn)
        _ = <-me.end_sig
        me.lconn.close() or {} // ignore
        rconn.close() or {} // ignore
        println('all exchange end')
    }()
}

pub fn (mut me Exchange) start_2() ! {
    mut rconn := net.dial_tcp(me.raddr)!
    go me.exchange(me.lconn, mut rconn)
    go me.exchange(rconn, mut me.lconn)
    _ = <-me.end_sig
    me.lconn.close() or {} // ignore
    rconn.close() or {} // ignore
    println('all exchange end')
}

fn (mut me Exchange) exchange(from net.TcpConn, mut to net.TcpConn) {
    mut buf := []u8{len: 1024}
    mut num_read := 0
    mut num_write := 0
    for {
        num_read = from.read(mut buf) or {
            println('xxxx from.read: ${err}')
            -1
        }

        if num_read <= 0 {
            me.end()
            break
        }

        num_write = to.write_ptr(buf[0], num_read) or {
            println('to.write_ptr error: ${err}')
            -1
        }
        if num_read != num_write {
            println('xxxx write faild')
            me.end()
            break
        }
    }
}

fn (mut me Exchange) end() {
    if me.is_end {
        return
    }

    me.is_end = true
    me.end_sig <- true
}

struct ReverseProxy {
    local  string
    remote string
mut:
    running bool
}

fn new_reverse_proxy(local string, remote string) ReverseProxy {
    return ReverseProxy{
        local: local
        remote: remote
    }
}

fn (mut me ReverseProxy) serve() ! {
    mut server := net.listen_tcp(.ip, me.local) or {
        println('xxxx net.listen_tcp: ${err}')
        panic(err)
    }
    println('proxy listen: ${server.addr()!}')

    me.running = true

    for ; me.running; {
        mut lconn := server.accept()!
        if !me.running {
            break
        }
        println('accept new connect')
        mut e := new_exchange(lconn, me.remote)
        e.start() or { println('xxxx start: ${err}') }
    }
    println('serve end')
}

fn (mut me ReverseProxy) quit() {
    me.running = false
    mut rconn := net.dial_tcp(me.local) or { &net.TcpConn{} } // ignore
    rconn.close() or {} // ignore
}

fn main() {
    mut rp := new_reverse_proxy(':9923', '45.56.81.220:80')
    go fn (mut rproxy ReverseProxy) {
        time.sleep(10000 * time.millisecond)
        rproxy.quit()
    }(mut &rp)
    rp.serve() or { println('xxxx listen: ${err}') }
}

V version

0.4.5 065399e

Environment details (OS name and version, etc.)

Darwin 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:23 PDT 2021; root:xnu-8019.41.5~1/RELEASE_X86_64 x86_64

[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.

spytheman commented 2 months ago

This triggers the same or very similar compiler panic:

fn f() ! {
    go fn () {
        mut x := 123
        go g(mut x)
    }()
}

It does not happen without the mut x argument to go g(); then it is a normal checker error.