From a6a3260399c75b9a04aede1e2bc957d857f3da8d Mon Sep 17 00:00:00 2001 From: Grant Nelson Date: Fri, 12 Jul 2024 14:30:00 -0600 Subject: [PATCH] Fixing cvtSliceArray --- .../src/internal/unsafeheader/unsafeheader.go | 16 ++++++++++++++++ .../internal/unsafeheader/unsafeheader_test.go | 10 ++++++++++ compiler/natives/src/reflect/reflect.go | 15 +++++++++++++++ compiler/prelude/prelude.js | 2 +- 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 compiler/natives/src/internal/unsafeheader/unsafeheader.go diff --git a/compiler/natives/src/internal/unsafeheader/unsafeheader.go b/compiler/natives/src/internal/unsafeheader/unsafeheader.go new file mode 100644 index 000000000..4a7e43342 --- /dev/null +++ b/compiler/natives/src/internal/unsafeheader/unsafeheader.go @@ -0,0 +1,16 @@ +//go:build js +// +build js + +package unsafeheader + +// Slice and String is Go's runtime representations which is different +// from GopherJS's runtime representations. By purging these types, +// it will prevent failures in JS where the code compiles fine but +// expects there to be a constructor which doesn't exist when casting +// from GopherJS's representation into Go's representation. + +//gopherjs:purge +type Slice struct{} + +//gopherjs:purge +type String struct{} diff --git a/compiler/natives/src/internal/unsafeheader/unsafeheader_test.go b/compiler/natives/src/internal/unsafeheader/unsafeheader_test.go index f20cf31fa..52e814636 100644 --- a/compiler/natives/src/internal/unsafeheader/unsafeheader_test.go +++ b/compiler/natives/src/internal/unsafeheader/unsafeheader_test.go @@ -5,6 +5,16 @@ package unsafeheader_test import "testing" +func TestTypeMatchesReflectType(t *testing.T) { + t.Skip("GopherJS uses different slice and string implementation than internal/unsafeheader.") +} + +//gopherjs:purge +func testHeaderMatchesReflect() + +//gopherjs:purge +func typeCompatible() + func TestWriteThroughHeader(t *testing.T) { t.Skip("GopherJS uses different slice and string implementation than internal/unsafeheader.") } diff --git a/compiler/natives/src/reflect/reflect.go b/compiler/natives/src/reflect/reflect.go index eef450356..db911d5d5 100644 --- a/compiler/natives/src/reflect/reflect.go +++ b/compiler/natives/src/reflect/reflect.go @@ -832,6 +832,21 @@ func cvtSliceArrayPtr(v Value, t Type) Value { return Value{t.common(), unsafe.Pointer(array.Unsafe()), v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Ptr)} } +// convertOp: []T -> [N]T +func cvtSliceArray(v Value, t Type) Value { + n := t.Len() + if n > v.Len() { + panic("reflect: cannot convert slice with length " + itoa.Itoa(v.Len()) + " to array with length " + itoa.Itoa(n)) + } + + slice := v.object() + dst := MakeSlice(SliceOf(t.Elem()), n, n).object() + js.Global.Call("$copySlice", dst, slice) + + arr := dst.Get("$array") + return Value{t.common(), unsafe.Pointer(arr.Unsafe()), v.flag&^(flagAddr|flagKindMask) | flag(Array)} +} + func Copy(dst, src Value) int { dk := dst.kind() if dk != Array && dk != Slice { diff --git a/compiler/prelude/prelude.js b/compiler/prelude/prelude.js index e925fc321..85db83727 100644 --- a/compiler/prelude/prelude.js +++ b/compiler/prelude/prelude.js @@ -185,7 +185,7 @@ var $sliceToNativeArray = slice => { return slice.$array.slice(slice.$offset, slice.$offset + slice.$length); }; -// Convert Go slice to a pointer to an underlying Go array. +// Convert Go slice to a pointer to an underlying Go array, `[]T -> *[N]T`. // // Note that an array pointer can be represented by an "unwrapped" native array // type, and it will be wrapped back into its Go type when necessary.