#1728·yaegi

Select on chan read from a func never calls the func

Author: pancstaCreated Jul 8, 2026Updated Jul 8, 2026

The following program sample.go triggers an unexpected result

go
package main

import (
	"reflect"
	// _ "github.com/dominikbraun/graph"

	"github.com/traefik/yaegi/interp"
	"github.com/traefik/yaegi/stdlib"

	symhelpers "tb/protos/dyn_handlers/symbols"
)

func main() {
	// lock-free critical section
	Eval(`
		dynEnd := make(chan struct{})
	
		newRandCh := func(i int) chan bool {
			fmt.Println("newRandCh")
			ch := make(chan bool)
			go func(){
				time.Sleep(time.Duration(i) * time.Second)
				ch <- true
			}()
	
			return ch
		}
	
		ret := func() bool {
			fmt.Println("eval start")
			go func() {
				i := 0
				for {
					fmt.Println("eval loop")
	
					select {
						case v, ok := <-newRandCh(1):
							fmt.Println("newRandCh", v, ok)
							close(dynEnd)
						case v, ok := <-newRandCh(2):
							fmt.Println("newRandCh", v, ok)
							close(dynEnd)
					}
	
				// 	time.Sleep(time.Second)
				// 	i++
				// 	if i > 10 {
				// 		close(dynEnd)
				// 		fmt.Println("loop end")
				// 		return
				// 	}
				}
			}()
	
			return true
		}()
		close(end)
		<-dynEnd
		ret
	`)
	select{}
}

func Eval(code string) bool {
	i := interp.New(interp.Options{})

	if err := i.Use(stdlib.Symbols); err != nil {
		panic(err)
	}
	end := make(chan struct{})
	i.Use(symhelpers.Symbols)
	i.Use(interp.Exports{
		"main/main": map[string]reflect.Value{
			"end": reflect.ValueOf(end),
		},
	})
	// required import
	_, err := i.Eval(`import (
		. "main"
	
		// stdlib deps
		"fmt"
		"time"
	)
	`)
	if err != nil {
		panic(err)
	}

	go func() {
		_, err := i.Eval(code)
		if err != nil {
			panic(err)
		}
	}()
	<-end

	return true
}

Expected result

bash
eval start
eval loop
newRandCh

Got

bash
eval start
eval loop

Yaegi Version

v0.16.1

Additional Notes

Channels have to initialized before the select statement, like so:

go
					ch1 := newRandCh(1)
					select {
						case v, ok := <-ch1:
							fmt.Println("newRandCh", v, ok)
							close(dynEnd)
						case v, ok := <-newRandCh(2):
							fmt.Println("newRandCh", v, ok)
							close(dynEnd)
					}