diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-03-14 14:31:50 -0700 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2021-04-21 00:54:39 +0000 |
commit | 760d3b2a16544aab553ca7ec6e6ed3bf4dc9aa3f (patch) | |
tree | a9eac9132e1fa610ecc7af7a4f754cf6dba67dca /src/reflect/value.go | |
parent | c18744377afa1f9c2310c122e6932fa663f9294a (diff) | |
download | go-760d3b2a16544aab553ca7ec6e6ed3bf4dc9aa3f.tar.gz go-760d3b2a16544aab553ca7ec6e6ed3bf4dc9aa3f.zip |
reflect: allow conversion from slice to array ptr
Note that this removes an invariant:
v.Type().ConvertibleTo(t) might return true,
yet v.Convert(t) might panic nevertheless.
This is a fairly unavoidable consequence of the decision
to add the first-ever conversion that can panic.
ConvertibleTo describes a relationship between types,
but whether the conversion panics now depends on the value,
not just the type.
If this turns out to be a problem, we can add v.ConvertibleTo(t),
or something similar, to allow callers to avoid the panic.
This is the last of the changes needed to complete the implementation.
Fixes #395
Change-Id: I79b7e4dd87a67a47723e00a65d0b1ac6090371b7
Reviewed-on: https://go-review.googlesource.com/c/go/+/301652
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/reflect/value.go')
-rw-r--r-- | src/reflect/value.go | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go index 6f1a3c02d6..418dff781f 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -6,6 +6,7 @@ package reflect import ( "internal/abi" + "internal/itoa" "internal/unsafeheader" "math" "runtime" @@ -2770,7 +2771,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value // Convert returns the value v converted to type t. // If the usual Go conversion rules do not allow conversion -// of the value v to type t, Convert panics. +// of the value v to type t, or if converting v to type t panics, Convert panics. func (v Value) Convert(t Type) Value { if v.flag&flagMethod != 0 { v = makeMethodValue("Convert", v) @@ -2841,6 +2842,11 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { return cvtRunesString } } + // "x is a slice, T is a pointer-to-array type, + // and the slice and array types have identical element types." + if dst.Kind() == Ptr && dst.Elem().Kind() == Array && src.Elem() == dst.Elem().Elem() { + return cvtSliceArrayPtr + } case Chan: if dst.Kind() == Chan && specialChannelAssignability(dst, src) { @@ -3034,6 +3040,16 @@ func cvtStringRunes(v Value, t Type) Value { return makeRunes(v.flag.ro(), []rune(v.String()), t) } +// convertOp: []T -> *[N]T +func cvtSliceArrayPtr(v Value, t Type) Value { + n := t.Elem().Len() + h := (*unsafeheader.Slice)(v.ptr) + if n > h.Len { + panic("reflect: cannot convert slice with length " + itoa.Itoa(h.Len) + " to array pointer with length " + itoa.Itoa(n)) + } + return Value{t.common(), h.Data, v.flag&^(flagIndir|flagAddr|flagKindMask) | flag(Ptr)} +} + // convertOp: direct copy func cvtDirect(v Value, typ Type) Value { f := v.flag |