The empty interface (interface{}), and its variants (such as []interface{} and map[string]interface{}), are commonly used in Go to (json) Unmarshal arbitrary data. Within Yaegi, all interface types are wrapped in a valueInterface struct in order to retain all the information needed for a consistent internal state (as reflect is not enough to achieve that). However, this wrapping ends up being problematic when it comes to the type assertions related to the aforementioned Unmarshaling.
Therefore, this PR is an attempt to consider the empty interface (and its variants) as an exception within Yaegi, that should never be wrapped within a valueInterface, and to treat it similarly to the other basic Go types. The assumption is that the wrapping should not be needed, as there is no information about implemented methods to maintain.
Fixes #984
Fixes #829
Fixes #1015
89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
)
|
|
|
|
type TestStruct struct{}
|
|
|
|
func (t TestStruct) String() string {
|
|
return "hello world"
|
|
}
|
|
|
|
type DummyStringer interface{
|
|
String() string
|
|
}
|
|
|
|
func main() {
|
|
aType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
|
|
|
var t interface{}
|
|
t = time.Nanosecond
|
|
s, ok := t.(fmt.Stringer)
|
|
if !ok {
|
|
fmt.Println("time.Nanosecond does not implement fmt.Stringer")
|
|
return
|
|
}
|
|
fmt.Println(s.String())
|
|
fmt.Println(t.(fmt.Stringer).String())
|
|
bType := reflect.TypeOf(time.Nanosecond)
|
|
fmt.Println(bType.Implements(aType))
|
|
|
|
// not redundant with the above, because it goes through a slightly different code path.
|
|
if _, ok := t.(fmt.Stringer); !ok {
|
|
fmt.Println("time.Nanosecond does not implement fmt.Stringer")
|
|
return
|
|
} else {
|
|
fmt.Println("time.Nanosecond implements fmt.Stringer")
|
|
}
|
|
|
|
t = 42
|
|
foo, ok := t.(fmt.Stringer)
|
|
if !ok {
|
|
fmt.Println("42 does not implement fmt.Stringer")
|
|
} else {
|
|
fmt.Println("42 implements fmt.Stringer")
|
|
return
|
|
}
|
|
_ = foo
|
|
|
|
if _, ok := t.(fmt.Stringer); !ok {
|
|
fmt.Println("42 does not implement fmt.Stringer")
|
|
} else {
|
|
fmt.Println("42 implements fmt.Stringer")
|
|
return
|
|
}
|
|
|
|
// TODO(mpl): restore when fixed
|
|
// var tt interface{}
|
|
var tt DummyStringer
|
|
tt = TestStruct{}
|
|
ss, ok := tt.(fmt.Stringer)
|
|
if !ok {
|
|
fmt.Println("TestStuct does not implement fmt.Stringer")
|
|
return
|
|
}
|
|
fmt.Println(ss.String())
|
|
fmt.Println(tt.(fmt.Stringer).String())
|
|
|
|
if _, ok := tt.(fmt.Stringer); !ok {
|
|
fmt.Println("TestStuct does not implement fmt.Stringer")
|
|
return
|
|
} else {
|
|
fmt.Println("TestStuct implements fmt.Stringer")
|
|
}
|
|
}
|
|
|
|
// Output:
|
|
// 1ns
|
|
// 1ns
|
|
// true
|
|
// time.Nanosecond implements fmt.Stringer
|
|
// 42 does not implement fmt.Stringer
|
|
// 42 does not implement fmt.Stringer
|
|
// hello world
|
|
// hello world
|
|
// TestStuct implements fmt.Stringer
|