Browse Source

Return true values of struct fields or reflect slice elements, rather than pointers to them. Closes #378.

Dmitry Panov 3 years ago
parent
commit
9037c2b61c
4 changed files with 23 additions and 15 deletions
  1. 1 1
      object_goarray_reflect.go
  2. 2 2
      object_gomap_reflect.go
  3. 4 11
      object_goreflect.go
  4. 16 1
      runtime.go

+ 1 - 1
object_goarray_reflect.go

@@ -50,7 +50,7 @@ func (o *objectGoArrayReflect) _getIdx(idx int) Value {
 	if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
 		return _null
 	}
-	return o.val.runtime.ToValue(v.Interface())
+	return o.val.runtime.toValue(v.Interface(), v)
 }
 
 func (o *objectGoArrayReflect) getIdx(idx valueInt, receiver Value) Value {

+ 2 - 2
object_gomap_reflect.go

@@ -41,7 +41,7 @@ func (o *objectGoMapReflect) _get(n Value) Value {
 		return nil
 	}
 	if v := o.value.MapIndex(key); v.IsValid() {
-		return o.val.runtime.ToValue(v.Interface())
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil
@@ -53,7 +53,7 @@ func (o *objectGoMapReflect) _getStr(name string) Value {
 		return nil
 	}
 	if v := o.value.MapIndex(key); v.IsValid() {
-		return o.val.runtime.ToValue(v.Interface())
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil

+ 4 - 11
object_goreflect.go

@@ -155,22 +155,15 @@ func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
 	return reflect.Value{}
 }
 
-func (o *objectGoReflect) getAddr(v reflect.Value) reflect.Value {
-	if (v.Kind() == reflect.Struct || v.Kind() == reflect.Slice) && v.CanAddr() {
-		return v.Addr()
-	}
-	return v
-}
-
 func (o *objectGoReflect) _get(name string) Value {
 	if o.value.Kind() == reflect.Struct {
 		if v := o._getField(name); v.IsValid() {
-			return o.val.runtime.ToValue(o.getAddr(v).Interface())
+			return o.val.runtime.toValue(v.Interface(), v)
 		}
 	}
 
 	if v := o._getMethod(name); v.IsValid() {
-		return o.val.runtime.ToValue(v.Interface())
+		return o.val.runtime.toValue(v.Interface(), v)
 	}
 
 	return nil
@@ -181,7 +174,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
 	if o.value.Kind() == reflect.Struct {
 		if v := o._getField(n); v.IsValid() {
 			return &valueProperty{
-				value:      o.val.runtime.ToValue(o.getAddr(v).Interface()),
+				value:      o.val.runtime.toValue(v.Interface(), v),
 				writable:   v.CanSet(),
 				enumerable: true,
 			}
@@ -190,7 +183,7 @@ func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
 
 	if v := o._getMethod(n); v.IsValid() {
 		return &valueProperty{
-			value:      o.val.runtime.ToValue(v.Interface()),
+			value:      o.val.runtime.toValue(v.Interface(), v),
 			enumerable: true,
 		}
 	}

+ 16 - 1
runtime.go

@@ -1624,6 +1624,10 @@ Note that the underlying type is not lost, calling Export() returns the original
 reflect based types.
 */
 func (r *Runtime) ToValue(i interface{}) Value {
+	return r.toValue(i, reflect.Value{})
+}
+
+func (r *Runtime) toValue(i interface{}, origValue reflect.Value) Value {
 	switch i := i.(type) {
 	case nil:
 		return _null
@@ -1739,7 +1743,18 @@ func (r *Runtime) ToValue(i interface{}) Value {
 		return obj
 	}
 
-	origValue := reflect.ValueOf(i)
+	if !origValue.IsValid() {
+		origValue = reflect.ValueOf(i)
+	} else {
+		// If origValue was a result of an Index(), or Field(), or such, its Kind may be Interface:
+		// 	a := []interface{}{(*S)(nil)}
+		//	a0 := reflect.ValueOf(a).Index(0) // a0.Kind() is reflect.Interface
+		//	a1 := reflect.ValueOf(a[0]) // a1.Kind() is reflect.Ptr
+		// Need to "dereference" it to make it consistent with plain value being passed.
+		for origValue.Kind() == reflect.Interface {
+			origValue = origValue.Elem()
+		}
+	}
 	value := origValue
 	for value.Kind() == reflect.Ptr {
 		value = reflect.Indirect(value)