The following program sample.go triggers an unexpected result
package main
import (
"fmt"
"github.com/traefik/yaegi/interp"
"github.com/traefik/yaegi/stdlib"
)
func main() {
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
src := "" +
"import (\"errors\"; \"fmt\")\n" +
"type MyErr struct{}\n" +
"func (e *MyErr) Error() string { return \"x\" }\n" +
"func F() bool {\n" +
" err := fmt.Errorf(\"wrap: %w\", &MyErr{})\n" +
" var target *MyErr\n" +
" return errors.As(err, &target)\n" +
"}\n"
if _, err := i.Eval(src); err != nil {
panic(err)
}
v, err := i.Eval("F()")
fmt.Printf("v=%v err=%v\n", v, err)
}
Expected result
errors.As should behave like compiled Go for interpreted error types.
In the repro:
- errors.As(fmt.Errorf("wrap: %w", &MyErr{}), &target)
should return true
- target should be set to the wrapped *MyErr
- no panic/error should occur
Got
errors.As does not match compiled Go behavior.
In the repro:
- errors.As(fmt.Errorf("wrap: %w", &MyErr{}), &target)
does not return true
- instead evaluation fails with:
errors: *target must be interface or implement error
Yaegi Version
v0.16.1
Additional Notes
This reproduces with pure yaegi (interp.New(...) + stdlib.Symbols) and does not depend on any host integration.
The issue appears to be in interpreted type / reflect identity handling rather than in %w unwrapping itself, because:
var err error = &MyErr{} works
errors.As(err, &targetErrorInterface) works
- but
errors.As(err, &targetConcreteInterpretedType) fails
Related observation:
reflect.TypeOf((*MyErr)(nil)).Implements(error) evaluates to false in interpreted code
- interpreted interface types appear as
interp.valueInterface
The following program
sample.gotriggers an unexpected resultExpected result
Got
Yaegi Version
v0.16.1
Additional Notes
This reproduces with pure yaegi (
interp.New(...)+stdlib.Symbols) and does not depend on any host integration.The issue appears to be in interpreted type / reflect identity handling rather than in
%wunwrapping itself, because:var err error = &MyErr{}workserrors.As(err, &targetErrorInterface)workserrors.As(err, &targetConcreteInterpretedType)failsRelated observation:
reflect.TypeOf((*MyErr)(nil)).Implements(error)evaluates to false in interpreted codeinterp.valueInterface