internal/impl: treat a nil oneof wrapper as if it were unset
The old implementation had the behavior where a nil wrapper value:
m := new(foopb.Message)
m.OneofField = (*foopb.Message_OneofUint32)(nil)
was functionally equivalent to it being directly set to nil:
m := new(foopb.Message)
m.OneofField = nil
preserve this semantic in both the table-drive implementation
and the reflection implementation.
Change-Id: Ie44d51e044d4822e61d0e646fbc44aa8d9b90c1f
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189559
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/impl/codec_field.go b/internal/impl/codec_field.go
index 16873e4..af6ce05 100644
--- a/internal/impl/codec_field.go
+++ b/internal/impl/codec_field.go
@@ -30,7 +30,7 @@
return pointer{}, false
}
v = v.Elem() // interface -> *struct
- if v.Elem().Type() != ot {
+ if v.IsNil() || v.Elem().Type() != ot {
return pointer{}, false
}
return pointerOfValue(v).Apply(zeroOffset), true
diff --git a/internal/impl/message_reflect_field.go b/internal/impl/message_reflect_field.go
index 10cacc7..6f7051b 100644
--- a/internal/impl/message_reflect_field.go
+++ b/internal/impl/message_reflect_field.go
@@ -56,7 +56,7 @@
return false
}
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
- if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+ if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
return false
}
return true
@@ -64,6 +64,8 @@
clear: func(p pointer) {
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+ // NOTE: We intentionally don't check for rv.Elem().IsNil()
+ // so that (*OneofWrapperType)(nil) gets cleared to nil.
return
}
rv.Set(reflect.Zero(rv.Type()))
@@ -73,7 +75,7 @@
return conv.Zero()
}
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
- if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+ if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
return conv.Zero()
}
rv = rv.Elem().Elem().Field(0)
@@ -81,7 +83,7 @@
},
set: func(p pointer, v pref.Value) {
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
- if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+ if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
rv.Set(reflect.New(ot))
}
rv = rv.Elem().Elem().Field(0)
@@ -92,7 +94,7 @@
panic("invalid Mutable on field with non-composite type")
}
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
- if rv.IsNil() || rv.Elem().Type().Elem() != ot {
+ if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
rv.Set(reflect.New(ot))
}
rv = rv.Elem().Elem().Field(0)