runtime: implement interface equality
Code copied from Konstantin Itskov and modified by Ayke van Laethem. For details: https://github.com/tinygo-org/tinygo/pull/569
Этот коммит содержится в:
родитель
e977276044
коммит
ac330f4a70
2 изменённых файлов: 105 добавлений и 8 удалений
|
@ -5,7 +5,10 @@ package runtime
|
||||||
// Interfaces are represented as a pair of {typecode, value}, where value can be
|
// Interfaces are represented as a pair of {typecode, value}, where value can be
|
||||||
// anything (including non-pointers).
|
// anything (including non-pointers).
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
type _interface struct {
|
type _interface struct {
|
||||||
typecode uintptr
|
typecode uintptr
|
||||||
|
@ -23,17 +26,55 @@ func decomposeInterface(i _interface) (uintptr, unsafe.Pointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true iff both interfaces are equal.
|
// Return true iff both interfaces are equal.
|
||||||
func interfaceEqual(x, y _interface) bool {
|
func interfaceEqual(x, y interface{}) bool {
|
||||||
if x.typecode != y.typecode {
|
return reflectValueEqual(reflect.ValueOf(x), reflect.ValueOf(y))
|
||||||
// Different dynamic type so always unequal.
|
}
|
||||||
|
|
||||||
|
func reflectValueEqual(x, y reflect.Value) bool {
|
||||||
|
if x.Type() == 0 || y.Type() == 0 {
|
||||||
|
// One of them is nil.
|
||||||
|
return x.Type() == y.Type()
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.Type() != y.Type() {
|
||||||
|
// The type is not the same, which means the interfaces are definitely
|
||||||
|
// not the same.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if x.typecode == 0 {
|
|
||||||
// Both interfaces are nil, so they are equal.
|
switch x.Type().Kind() {
|
||||||
return true
|
case reflect.Bool:
|
||||||
|
return x.Bool() == y.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return x.Int() == y.Int()
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return x.Uint() == y.Uint()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return x.Float() == y.Float()
|
||||||
|
case reflect.Complex64, reflect.Complex128:
|
||||||
|
return x.Complex() == y.Complex()
|
||||||
|
case reflect.String:
|
||||||
|
return x.String() == y.String()
|
||||||
|
case reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
|
||||||
|
return x.Pointer() == y.Pointer()
|
||||||
|
case reflect.Array:
|
||||||
|
for i := 0; i < x.Len(); i++ {
|
||||||
|
if !reflectValueEqual(x.Index(i), y.Index(i)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Struct:
|
||||||
|
for i := 0; i < x.NumField(); i++ {
|
||||||
|
if !reflectValueEqual(x.Field(i), y.Field(i)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
runtimePanic("comparing un-comparable type")
|
||||||
|
return false // unreachable
|
||||||
}
|
}
|
||||||
// TODO: depends on reflection.
|
|
||||||
panic("unimplemented: interface equality")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// interfaceTypeAssert is called when a type assert without comma-ok still
|
// interfaceTypeAssert is called when a type assert without comma-ok still
|
||||||
|
|
56
testdata/interface.go
предоставленный
56
testdata/interface.go
предоставленный
|
@ -30,6 +30,62 @@ func main() {
|
||||||
// Try putting a linked list in an interface:
|
// Try putting a linked list in an interface:
|
||||||
// https://github.com/tinygo-org/tinygo/issues/309
|
// https://github.com/tinygo-org/tinygo/issues/309
|
||||||
itf = linkedList{}
|
itf = linkedList{}
|
||||||
|
|
||||||
|
var n int
|
||||||
|
var f float32
|
||||||
|
var interfaceEqualTests = []struct {
|
||||||
|
equal bool
|
||||||
|
lhs interface{}
|
||||||
|
rhs interface{}
|
||||||
|
}{
|
||||||
|
{true, true, true},
|
||||||
|
{true, int(1), int(1)},
|
||||||
|
{true, int8(1), int8(1)},
|
||||||
|
{true, int16(1), int16(1)},
|
||||||
|
{true, int32(1), int32(1)},
|
||||||
|
{true, int64(1), int64(1)},
|
||||||
|
{true, uint(1), uint(1)},
|
||||||
|
{false, uint(1), uint(2)},
|
||||||
|
{true, uint8(1), uint8(1)},
|
||||||
|
{true, uint16(1), uint16(1)},
|
||||||
|
{true, uint32(1), uint32(1)},
|
||||||
|
{true, uint64(1), uint64(1)},
|
||||||
|
{true, float32(1.1), float32(1.1)},
|
||||||
|
{true, float64(1.1), float64(1.1)},
|
||||||
|
{true, complex(100, 8), complex(100, 8)},
|
||||||
|
{false, complex(100, 8), complex(101, 8)},
|
||||||
|
{false, complex(100, 8), complex(100, 9)},
|
||||||
|
{true, complex64(8), complex64(8)},
|
||||||
|
{true, complex128(8), complex128(8)},
|
||||||
|
{true, "string", "string"},
|
||||||
|
{false, "string", "stringx"},
|
||||||
|
{true, [2]int16{-5, 201}, [2]int16{-5, 201}},
|
||||||
|
{false, [2]int16{-5, 201}, [2]int16{-5, 202}},
|
||||||
|
{false, [2]int16{-5, 201}, [2]int16{5, 201}},
|
||||||
|
{true, &n, &n},
|
||||||
|
{false, &n, new(int)},
|
||||||
|
{false, new(int), new(int)},
|
||||||
|
{false, &n, &f},
|
||||||
|
{true, struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
}{3, 5}, struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
}{3, 5}},
|
||||||
|
{false, struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
}{3, 5}, struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
}{3, 6}},
|
||||||
|
}
|
||||||
|
for i, tc := range interfaceEqualTests {
|
||||||
|
if (tc.lhs == tc.rhs) != tc.equal {
|
||||||
|
println("test", i, "of interfaceEqualTests failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printItf(val interface{}) {
|
func printItf(val interface{}) {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче