internal/lib/reflect: call variadic check

This commit is contained in:
visualfc
2024-11-26 09:50:40 +08:00
parent fadd64c1e9
commit c2138037d2
5 changed files with 407 additions and 111 deletions

View File

@@ -1125,14 +1125,11 @@ func (t *rtype) Implements(u Type) bool {
}
func (t *rtype) AssignableTo(u Type) bool {
/*
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.common()
return directlyAssignable(uu, t.common()) || implements(uu, t.common())
*/
panic("todo: reflect.rtype.AssignableTo")
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.common()
return directlyAssignable(uu, t.common()) || implements(uu, t.common())
}
func (t *rtype) ConvertibleTo(u Type) bool {
@@ -1150,92 +1147,9 @@ func (t *rtype) Comparable() bool {
}
// implements reports whether the type V implements the interface type T.
func implements(T, V *abi.Type) bool {
if T.Kind() != abi.Interface {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
if len(t.Methods) == 0 {
return true
}
/*
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
// are different, so the code is duplicated.
// In both cases the algorithm is a linear scan over the two
// lists - T's methods and V's methods - simultaneously.
// Since method tables are stored in a unique sorted order
// (alphabetical, with no duplicate method names), the scan
// through V's methods must hit a match for each of T's
// methods along the way, or else V does not implement T.
// This lets us run the scan in overall linear time instead of
// the quadratic time a naive search would require.
// See also ../runtime/iface.go.
if V.Kind() == abi.Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
for j := 0; j < len(v.Methods); j++ {
tm := &t.Methods[i]
tmName := t.nameOff(tm.Name)
vm := &v.Methods[j]
vmName := nameOffFor(V, vm.Name)
if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Typ) == t.typeOff(tm.Typ) {
if !tmName.IsExported() {
tmPkgPath := pkgPath(tmName)
if tmPkgPath == "" {
tmPkgPath = t.PkgPath.Name()
}
vmPkgPath := pkgPath(vmName)
if vmPkgPath == "" {
vmPkgPath = v.PkgPath.Name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.Methods) {
return true
}
}
}
return false
}
v := V.Uncommon()
if v == nil {
return false
}
i := 0
vmethods := v.Methods()
for j := 0; j < int(v.Mcount); j++ {
tm := &t.Methods[i]
tmName := t.nameOff(tm.Name)
vm := vmethods[j]
vmName := nameOffFor(V, vm.Name)
if vmName.Name() == tmName.Name() && typeOffFor(V, vm.Mtyp) == t.typeOff(tm.Typ) {
if !tmName.IsExported() {
tmPkgPath := pkgPath(tmName)
if tmPkgPath == "" {
tmPkgPath = t.PkgPath.Name()
}
vmPkgPath := pkgPath(vmName)
if vmPkgPath == "" {
vmPkgPath = nameOffFor(V, v.PkgPath).Name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.Methods) {
return true
}
}
}
return false
*/
panic("todo: reflect.implements")
}
//
//go:linkname implements github.com/goplus/llgo/internal/runtime.Implements
func implements(T, V *abi.Type) bool
// specialChannelAssignability reports whether a value x of channel type V
// can be directly assigned (using memmove) to another channel type T.

View File

@@ -1843,7 +1843,6 @@ func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Va
// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.
return Value{dst, nil, flag(Interface)}
}
/* TODO(xsw):
x := valueInterface(v, false)
if target == nil {
target = unsafe_New(dst)
@@ -1854,13 +1853,10 @@ func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Va
ifaceE2I(dst, x, target)
}
return Value{dst, target, flagIndir | flag(Interface)}
*/
}
// Failed.
// TODO(xsw):
// panic(context + ": value of type " + stringFor(v.typ()) + " is not assignable to type " + stringFor(dst))
panic("todo: reflect.Value.assignTo")
panic(context + ": value of type " + stringFor(v.typ()) + " is not assignable to type " + stringFor(dst))
}
// memmove copies size bytes to dst from src. No write barriers are used.
@@ -2219,23 +2215,21 @@ func (v Value) call(op string, in []Value) (out []Value) {
panic("reflect: " + op + " using zero Value argument")
}
}
// TODO AssignableTo
// for i := 0; i < n; i++ {
// if xt, targ := in[i].Type(), ft.In(i); !xt.AssignableTo(toRType(targ)) {
// panic("reflect: " + op + " using " + xt.String() + " as type " + stringFor(targ))
// }
// }
for i := 0; i < n; i++ {
if xt, targ := in[i].Type(), ft.In[i]; !xt.AssignableTo(toRType(targ)) {
panic("reflect: " + op + " using " + xt.String() + " as type " + stringFor(targ))
}
}
if !isSlice && isVariadic {
// prepare slice for remaining values
m := len(in) - n
slice := MakeSlice(toRType(ft.In[n]), m, m)
// elem := toRType(ft.In[n]).Elem() // FIXME cast to slice type and Elem()
elem := toRType(ft.In[n].Elem()) // FIXME cast to slice type and Elem()
for i := 0; i < m; i++ {
x := in[n+i]
// TODO AssignableTo
// if xt := x.Type(); !xt.AssignableTo(elem) {
// panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
// }
if xt := x.Type(); !xt.AssignableTo(elem) {
panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
}
slice.Index(i).Set(x)
}
origIn := in
@@ -2637,3 +2631,7 @@ func MakeSlice(typ Type, len, cap int) Value {
s := unsafeheaderSlice{Data: unsafe_NewArray(&(typ.Elem().(*rtype).t), cap), Len: len, Cap: cap}
return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)}
}
func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) {
panic("todo: reflect.ifaceE2I")
}