Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add naive implementation of reflect.Value.Array #3800

Open
p4u opened this issue Jun 19, 2023 · 2 comments
Open

Add naive implementation of reflect.Value.Array #3800

p4u opened this issue Jun 19, 2023 · 2 comments
Labels
duplicate This issue or pull request already exists enhancement New feature or request reflection Needs further work on reflection

Comments

@p4u
Copy link

p4u commented Jun 19, 2023

reflect.Value on type Array is currently not implemented, there is a TODO from @dgryski:

// TODO(dgryski): can't do this yet because the resulting value needs type slice of v.elem(), not array of v.elem().
// need to be able to look up this "new" type so pointer equality of types still works

However, I have tested this workaround solution (with Gob) and works:

https://github.com/tinygo-org/tinygo/pull/3570/files#diff-fb7a84f457b2d4466b5d32940ffc6095d12b649f88bd3e5e762a87631e7a917aR557

I would propose to add the naive Array implementation until the good one is implemented and remove the Panic. This would enhance compatibility with Gob and other encoders/decoders.

@p4u
Copy link
Author

p4u commented Jun 19, 2023

Here is the diff that should apply to the last dev source code. Let me know if you would accept this and want me to send a PR.

diff --git a/compiler/interface.go b/compiler/interface.go
index da998214..0a77c88c 100644
--- a/compiler/interface.go
+++ b/compiler/interface.go
@@ -209,6 +209,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
 				types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
 				types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
 				types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
+				types.NewVar(token.NoPos, nil, "sliceOf", types.Typ[types.UnsafePointer]),
 			)
 		case *types.Map:
 			typeFieldTypes = append(typeFieldTypes,
@@ -317,6 +318,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
 				c.getTypeCode(types.NewPointer(typ)),                   // ptrTo
 				c.getTypeCode(typ.Elem()),                              // elementType
 				llvm.ConstInt(c.uintptrType, uint64(typ.Len()), false), // length
+				c.getTypeCode(types.NewSlice(typ.Elem())),              // slicePtr
 			}
 		case *types.Map:
 			typeFields = []llvm.Value{
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 12f3c2c1..7e6412a2 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -29,6 +29,7 @@
 //     ptrTo        *typeStruct
 //     elem         *typeStruct // element type of the array
 //     arrayLen     uintptr     // length of the array (this is part of the type)
+//     slicePtr     *typeStruct // pointer to []T type
 // - map types (this is still missing the key and element types)
 //     meta         uint8
 //     nmethods     uint16 (0)
@@ -427,6 +428,7 @@ type arrayType struct {
 	ptrTo     *rawType
 	elem      *rawType
 	arrayLen  uintptr
+	slicePtr  *rawType
 }
 
 type mapType struct {
@@ -949,7 +951,7 @@ func (t *rawType) AssignableTo(u Type) bool {
 	}
 
 	if u.Kind() == Interface {
-	//	panic("reflect: unimplemented: AssignableTo with interface")
+		//	panic("reflect: unimplemented: AssignableTo with interface")
 	}
 	return false
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 92d26409..edc7821a 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -555,8 +555,29 @@ func (v Value) Slice(i, j int) Value {
 		}
 
 	case Array:
-		// TODO(dgryski): can't do this yet because the resulting value needs type slice of v.elem(), not array of v.elem().
+		// Currently this case works but its not ideal.
+		// TODO(dgryski): can't do this properly yet because the resulting value needs type slice of v.elem(), not array of v.elem().
 		// need to be able to look up this "new" type so pointer equality of types still works
+		v.checkAddressable()
+		buf, length := buflen(v)
+		i, j := uintptr(i), uintptr(j)
+		if j < i || length < j {
+			slicePanic()
+		}
+
+		elemSize := v.typecode.underlying().elem().Size()
+
+		var hdr sliceHeader
+		hdr.len = j - i
+		hdr.cap = length - i
+		hdr.data = unsafe.Add(buf, i*elemSize)
+
+		sliceType := (*arrayType)(unsafe.Pointer(v.typecode.underlying())).slicePtr
+		return Value{
+			typecode: sliceType,
+			value:    unsafe.Pointer(&hdr),
+			flags:    v.flags,
+		}
 
 	case String:
 		i, j := uintptr(i), uintptr(j)

@dgryski
Copy link
Member

dgryski commented Jul 6, 2023

The commit from the closed PR you link to was moved to #3761 and is currently on hold until we deal with the space increase.

@deadprogram deadprogram added duplicate This issue or pull request already exists enhancement New feature or request reflection Needs further work on reflection labels Aug 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists enhancement New feature or request reflection Needs further work on reflection
Projects
None yet
Development

No branches or pull requests

3 participants