reflect: fix TypeAssert on nil interface values
In the Go language a type assertion of a nil interface value
will always report false:
var err error
v, ok := err.(error) // always reports (nil, false)
Consequently, assertion on a reflect.Value.Interface()
will also report false:
var err error
rv := ValueOf(&err).Elem()
v, ok := rv.Interface().(error) // reports (nil, false)
However, prior to this change, a TypeAssert would report true:
var err error
rv := ValueOf(&err).Elem()
v, ok := TypeAssert[error](rv) // reports (nil, true)
when it should report false.
This fixes TypeAssert to match the Go language by
pushing the typ != v.typ check to the very end after
we have validated that neither v nor T are interface kinds.
Fixes #74404
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index fb1a29d..cd3e306 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -8719,6 +8719,11 @@
testTypeAssert(t, any(int(1)), int(1), true)
testTypeAssert(t, any(int(1)), byte(0), false)
testTypeAssert(t, fmt.Stringer(vv), vv, true)
+
+ testTypeAssert(t, any(nil), any(nil), false)
+ testTypeAssert(t, any(nil), error(nil), false)
+ testTypeAssert(t, error(nil), any(nil), false)
+ testTypeAssert(t, error(nil), error(nil), false)
}
func testTypeAssert[T comparable, V any](t *testing.T, val V, wantVal T, wantOk bool) {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 68b97e9..effe2f2 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1514,46 +1514,46 @@
}
typ := abi.TypeFor[T]()
+
+ // Return the element inside the interface.
+ //
+ // T is a concrete type and v is an interface. For example:
+ //
+ // var v any = int(1)
+ // val := ValueOf(&v).Elem()
+ // TypeAssert[int](val) == val.Interface().(int)
+ //
+ // T is a interface and v is an interface, but the iface types are different. For example:
+ //
+ // var v any = &someError{}
+ // val := ValueOf(&v).Elem()
+ // TypeAssert[error](val) == val.Interface().(error)
+ //
+ // T is a interface and v is a nil interface value. For example:
+ //
+ // var v errror
+ // val := ValueOf(&v).Elem()
+ // TypeAssert[error](val) == val.Interface().(error)
+ if v.kind() == Interface {
+ v, ok := packIfaceValueIntoEmptyIface(v).(T)
+ return v, ok
+ }
+
+ // T is an interface, v is a concrete type. For example:
+ //
+ // TypeAssert[any](ValueOf(1)) == ValueOf(1).Interface().(any)
+ // TypeAssert[error](ValueOf(&someError{})) == ValueOf(&someError{}).Interface().(error)
+ if typ.Kind() == abi.Interface {
+ v, ok := packEface(v).(T)
+ return v, ok
+ }
+
+ // Both v and T must be concrete types.
+ // The only way for an type-assertion to match is if the types are equal.
if typ != v.typ() {
- // We can't just return false here:
- //
- // var zero T
- // return zero, false
- //
- // since this function should work in the same manner as v.Interface().(T) does.
- // Thus we have to handle two cases specially.
-
- // Return the element inside the interface.
- //
- // T is a concrete type and v is an interface. For example:
- //
- // var v any = int(1)
- // val := ValueOf(&v).Elem()
- // TypeAssert[int](val) == val.Interface().(int)
- //
- // T is a interface and v is an interface, but the iface types are different. For example:
- //
- // var v any = &someError{}
- // val := ValueOf(&v).Elem()
- // TypeAssert[error](val) == val.Interface().(error)
- if v.kind() == Interface {
- v, ok := packIfaceValueIntoEmptyIface(v).(T)
- return v, ok
- }
-
- // T is an interface, v is a concrete type. For example:
- //
- // TypeAssert[any](ValueOf(1)) == ValueOf(1).Interface().(any)
- // TypeAssert[error](ValueOf(&someError{})) == ValueOf(&someError{}).Interface().(error)
- if typ.Kind() == abi.Interface {
- v, ok := packEface(v).(T)
- return v, ok
- }
-
var zero T
return zero, false
}
-
if v.flag&flagIndir == 0 {
return *(*T)(unsafe.Pointer(&v.ptr)), true
}
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Auto-Submit | +1 |
Commit-Queue | +1 |
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// T is a interface and v is an interface, but the iface types are different. For example:
I think that this is not true anymore.
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// var v errror
```suggestion
// var v error
```
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Auto-Submit | +1 |
Commit-Queue | +1 |
// T is a interface and v is an interface, but the iface types are different. For example:
I think that this is not true anymore.
Done
```suggestion
// var v error
```
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Code-Review | +1 |
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Code-Review | +2 |
Thanks.
// Return the element inside the interface.
After the rearrange, this line perhaps read better with
// If v is an interface, return the element inside the interface.
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Auto-Submit | +1 |
Commit-Queue | +1 |
After the rearrange, this line perhaps read better with
// If v is an interface, return the element inside the interface.
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Code-Review | +1 |
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
2 is the latest approved patch-set.
The change was submitted with unreviewed changes in the following files:
```
The name of the file: src/reflect/value.go
Insertions: 4, Deletions: 4.
@@ -1515,7 +1515,7 @@
typ := abi.TypeFor[T]()
- // Return the element inside the interface.
+ // If v is an interface, return the element inside the interface.
//
// T is a concrete type and v is an interface. For example:
//
@@ -1523,7 +1523,7 @@
// val := ValueOf(&v).Elem()
// TypeAssert[int](val) == val.Interface().(int)
//
- // T is a interface and v is an interface. For example:
+ // T is a interface and v is a non-nil interface value. For example:
//
// var v any = &someError{}
// val := ValueOf(&v).Elem()
@@ -1531,7 +1531,7 @@
//
// T is a interface and v is a nil interface value. For example:
//
- // var v error
+ // var v error = nil
// val := ValueOf(&v).Elem()
// TypeAssert[error](val) == val.Interface().(error)
if v.kind() == Interface {
@@ -1539,7 +1539,7 @@
return v, ok
}
- // T is an interface, v is a concrete type. For example:
+ // If T is an interface and v is a concrete type. For example:
//
// TypeAssert[any](ValueOf(1)) == ValueOf(1).Interface().(any)
// TypeAssert[error](ValueOf(&someError{})) == ValueOf(&someError{}).Interface().(error)
```
reflect: fix TypeAssert on nil interface values
In the Go language a type assertion of a nil interface value
will always report false:
var err error
v, ok := err.(error) // always reports (nil, false)
Consequently, assertion on a reflect.Value.Interface()
will also report false:
var err error
rv := ValueOf(&err).Elem()
v, ok := rv.Interface().(error) // reports (nil, false)
However, prior to this change, a TypeAssert would report true:
var err error
rv := ValueOf(&err).Elem()
v, ok := TypeAssert[error](rv) // reports (nil, true)
when it should report false.
This fixes TypeAssert to match the Go language by
pushing the typ != v.typ check to the very end after
we have validated that neither v nor T are interface kinds.
Fixes #74404
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |