traefik / yaegi

Yaegi is Another Elegant Go Interpreter
https://pkg.go.dev/github.com/traefik/yaegi
Apache License 2.0
6.82k stars 342 forks source link

assignable error with Eval order #1579

Open he11olx opened 1 year ago

he11olx commented 1 year ago

The following program sample.go triggers an unexpected result

func main() {
    i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
    err := i.Use(stdlib.Symbols)
    if err != nil {
        panic(err)
    }

    var Script1 string = `package s1
var A int = 1
`
    var Script2 string = `package s2
var F = "f_valid"
var A = map[string]interface{}{}
`
    if _, err = i.Eval(Script1); err != nil {
        panic(err)
    }
    if _, err = i.Eval(Script2); err != nil {
        panic(err)
    }
    if _, err = i.Eval(Script1); err != nil {
        panic(err)
    }
}

Expected result

not panic

Got

2:5: panic
panic: reflect.Set: value of type int is not assignable to type string

Yaegi Version

v0.15.1

Additional Notes

It's ok when we change Eval order.

    if _, err = i.Eval(Script1); err != nil {
        panic(err)
    }
    if _, err = i.Eval(Script1); err != nil {
        panic(err)
    }
    if _, err = i.Eval(Script2); err != nil {
        panic(err)
    }
he11olx commented 12 months ago

Assuming we have three sections of code, s1, s2, and s3, which are loaded using Eval. Additionally, let's assume g is used to retrieve the value from the previous section s.

The combinations s123, s1g23, and s12g3 do not throw any errors. However, s1g2g3 throws an error. Interestingly, s1g21 and s1g2g1 do not throw any errors, but s12g1 and s121 throw errors.

func Test_yaegi_Assignable_s12g3(t *testing.T) {
    inter := interp.New(interp.Options{GoPath: build.Default.GOPATH})
    err := inter.Use(stdlib.Symbols)
    if err != nil {
        panic(fmt.Errorf("use stdlib.Symbols error: %v", err))
    }
    if _, err := inter.Eval("package s1\nvar A int64 = 1"); err != nil {
        t.Fatalf("eval s1: %v", err)
    }
    if _, err := inter.Eval("package s2\nvar B = \"f_b\"\nvar C = map[string]interface{}{\"k\":1}"); err != nil {
        t.Fatalf("eval s2: %v", err)
    }
    // get s2
    if _, err = inter.Eval("s2.C"); err != nil {
        t.Fatalf("GetVal s2 %v", err)
    }
    if _, err := inter.Eval("package s3\nvar A int64 = 1"); err != nil {
        t.Fatalf("eval s3: %v", err)
    }
}
// outpu: pass
func Test_yaegi_Assignable_s1g2g3(t *testing.T) {
    inter := interp.New(interp.Options{GoPath: build.Default.GOPATH})
    err := inter.Use(stdlib.Symbols)
    if err != nil {
        panic(fmt.Errorf("use stdlib.Symbols error: %v", err))
    }
    if _, err := inter.Eval("package s1\nvar A int64 = 1"); err != nil {
        t.Fatalf("eval s1: %v", err)
    }
    // get s1
    if _, err = inter.Eval("s1.A"); err != nil {
        t.Fatalf("GetVal s1 %v", err)
    }
    if _, err := inter.Eval("package s2\nvar B = \"f_b\"\nvar C = map[string]interface{}{\"k\":1}"); err != nil {
        t.Fatalf("eval s2: %v", err)
    }
    // get s2
    if _, err = inter.Eval("s2.C"); err != nil {
        t.Fatalf("GetVal s2 %v", err)
    }
    if _, err := inter.Eval("package s3\nvar A int64 = 1"); err != nil {
        t.Fatalf("eval s3: %v", err)
    }
}
// outpu: 
// 2:5: panic
//    eval s3: reflect.Set: value of type int64 is not assignable to type map[string]interface {}