reflect/protoreflect: add FieldDescriptor.DefaultEnumValue method
Default values for enums are specified by name, not number. An enum
may contain multiple values with different names but the same number.
Representing the default as a protoreflect.Value containing an EnumNumber
can discard information.
Add a method returning the EnumValueDescriptor.
Change-Id: If8beee3f81d41c4f9af45423252603b86949c7a5
Reviewed-on: https://go-review.googlesource.com/c/145158
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go/internal_gengo/main.go b/cmd/protoc-gen-go/internal_gengo/main.go
index 8e57ebd..ed0d07f 100644
--- a/cmd/protoc-gen-go/internal_gengo/main.go
+++ b/cmd/protoc-gen-go/internal_gengo/main.go
@@ -497,8 +497,9 @@
case protoreflect.BytesKind:
g.P("var ", defVarName, " []byte = []byte(", strconv.Quote(string(def.Bytes())), ")")
case protoreflect.EnumKind:
+ evalueDesc := field.Desc.DefaultEnumValue()
enum := field.EnumType
- evalue := enum.Values[enum.Desc.Values().ByNumber(def.Enum()).Index()]
+ evalue := enum.Values[evalueDesc.Index()]
g.P("const ", defVarName, " ", field.EnumType.GoIdent, " = ", evalue.GoIdent)
case protoreflect.FloatKind, protoreflect.DoubleKind:
// Floating point numbers need extra handling for -Inf/Inf/NaN.
diff --git a/cmd/protoc-gen-go/testdata/proto2/enum.pb.go b/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
index 6e5cf27..5172108 100644
--- a/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
+++ b/cmd/protoc-gen-go/testdata/proto2/enum.pb.go
@@ -256,9 +256,11 @@
}
type EnumContainerMessage1 struct {
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ DefaultDuplicate1 *EnumType2 `protobuf:"varint,1,opt,name=default_duplicate1,json=defaultDuplicate1,enum=goproto.protoc.proto2.EnumType2,def=1" json:"default_duplicate1,omitempty"`
+ DefaultDuplicate2 *EnumType2 `protobuf:"varint,2,opt,name=default_duplicate2,json=defaultDuplicate2,enum=goproto.protoc.proto2.EnumType2,def=1" json:"default_duplicate2,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *EnumContainerMessage1) Reset() { *m = EnumContainerMessage1{} }
@@ -286,6 +288,23 @@
var xxx_messageInfo_EnumContainerMessage1 proto.InternalMessageInfo
+const Default_EnumContainerMessage1_DefaultDuplicate1 EnumType2 = EnumType2_duplicate1
+const Default_EnumContainerMessage1_DefaultDuplicate2 EnumType2 = EnumType2_duplicate2
+
+func (m *EnumContainerMessage1) GetDefaultDuplicate1() EnumType2 {
+ if m != nil && m.DefaultDuplicate1 != nil {
+ return *m.DefaultDuplicate1
+ }
+ return Default_EnumContainerMessage1_DefaultDuplicate1
+}
+
+func (m *EnumContainerMessage1) GetDefaultDuplicate2() EnumType2 {
+ if m != nil && m.DefaultDuplicate2 != nil {
+ return *m.DefaultDuplicate2
+ }
+ return Default_EnumContainerMessage1_DefaultDuplicate2
+}
+
type EnumContainerMessage1_EnumContainerMessage2 struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -335,21 +354,24 @@
func init() { proto.RegisterFile("proto2/enum.proto", fileDescriptor_de9f68860d540858) }
var fileDescriptor_de9f68860d540858 = []byte{
- // 248 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x41, 0x4b, 0xc3, 0x30,
- 0x18, 0x86, 0xcd, 0x3c, 0x88, 0x39, 0x68, 0xac, 0xec, 0x32, 0xf0, 0xb2, 0x8b, 0x30, 0xd8, 0x42,
- 0xbe, 0x3f, 0x20, 0xad, 0xe6, 0xa6, 0xdd, 0xc1, 0xaa, 0xe0, 0x65, 0x64, 0xe9, 0x67, 0x2c, 0xac,
- 0x49, 0x59, 0xbf, 0x08, 0xfe, 0x4f, 0x7f, 0x90, 0xac, 0x85, 0x59, 0x61, 0x7a, 0xca, 0xfb, 0xe6,
- 0x7d, 0x78, 0x0e, 0x1f, 0xbf, 0x68, 0xb6, 0x81, 0x02, 0x48, 0xf4, 0xb1, 0x5e, 0x74, 0x39, 0x19,
- 0xbb, 0xd0, 0x85, 0xbe, 0xda, 0xfe, 0x81, 0xe9, 0x17, 0xe3, 0x63, 0xed, 0x63, 0x7d, 0x1b, 0x3c,
- 0x99, 0xca, 0xe3, 0xf6, 0x01, 0xdb, 0xd6, 0x38, 0x54, 0x93, 0xea, 0xf0, 0x00, 0xd3, 0x6b, 0x2e,
- 0x72, 0x6c, 0x09, 0xcb, 0xdd, 0x5c, 0x7c, 0x36, 0x08, 0x69, 0x72, 0xc9, 0xcf, 0x73, 0xfd, 0x58,
- 0xe8, 0xbb, 0x15, 0xa4, 0xab, 0xe7, 0xf4, 0xfe, 0x49, 0x8b, 0xa3, 0x03, 0x60, 0x36, 0x04, 0xb3,
- 0xbf, 0x41, 0x35, 0x34, 0xaa, 0x7f, 0x8c, 0x6a, 0x68, 0x54, 0x7b, 0xe3, 0xec, 0x8a, 0x9f, 0xee,
- 0x91, 0xe4, 0x84, 0x1f, 0x2f, 0x73, 0x2d, 0xd8, 0x2e, 0x14, 0x2f, 0x4b, 0x31, 0x9a, 0xc9, 0x9f,
- 0x19, 0x92, 0x33, 0xce, 0xcb, 0xd8, 0x6c, 0x2a, 0x6b, 0x08, 0x95, 0x60, 0xbf, 0x3a, 0x08, 0x36,
- 0x19, 0x09, 0x96, 0xa5, 0xaf, 0x37, 0xae, 0xa2, 0xf7, 0xb8, 0x5e, 0xd8, 0x50, 0x4b, 0x17, 0x36,
- 0xc6, 0x3b, 0xd9, 0x9d, 0x70, 0x1d, 0xdf, 0xe4, 0x07, 0x48, 0x5b, 0x97, 0x7d, 0xb7, 0x73, 0x87,
- 0x7e, 0xee, 0x82, 0x24, 0x6c, 0xa9, 0x34, 0x64, 0xfa, 0x6f, 0xf8, 0x0e, 0x00, 0x00, 0xff, 0xff,
- 0x5b, 0x88, 0x8a, 0x80, 0x94, 0x01, 0x00, 0x00,
+ // 296 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0xd0, 0xc1, 0x4b, 0xfb, 0x30,
+ 0x14, 0x07, 0xf0, 0x5f, 0xb6, 0xc3, 0x0f, 0x73, 0x98, 0x59, 0x64, 0x30, 0x06, 0xc2, 0xd8, 0x45,
+ 0x19, 0xac, 0x21, 0xef, 0xe8, 0x45, 0x3a, 0xd7, 0x9b, 0x6e, 0xa0, 0x53, 0x41, 0x0f, 0x25, 0x6b,
+ 0xb3, 0x58, 0x68, 0x93, 0xb2, 0x26, 0x82, 0xff, 0x84, 0x7f, 0xb3, 0xac, 0x95, 0xae, 0x62, 0x15,
+ 0x3c, 0xe5, 0xbd, 0x97, 0x6f, 0x3e, 0x90, 0x87, 0xfb, 0xf9, 0xce, 0x58, 0x03, 0x4c, 0x6a, 0x97,
+ 0x79, 0x65, 0x4d, 0x07, 0xca, 0x94, 0x45, 0xd5, 0x46, 0xd5, 0x01, 0x93, 0xf7, 0x2e, 0x1e, 0x04,
+ 0xda, 0x65, 0x57, 0x46, 0x5b, 0x91, 0x68, 0xb9, 0xbb, 0x91, 0x45, 0x21, 0x94, 0xe4, 0xf4, 0x19,
+ 0xd3, 0x58, 0x6e, 0x85, 0x4b, 0x6d, 0x18, 0xbb, 0x3c, 0x4d, 0x22, 0x61, 0x25, 0x1f, 0xa2, 0x31,
+ 0x3a, 0xef, 0xc1, 0xd8, 0x6b, 0xd5, 0xbc, 0xbd, 0xb4, 0x7e, 0xcb, 0x25, 0x5c, 0xe0, 0xc3, 0x9b,
+ 0xdb, 0xfe, 0xa7, 0xb3, 0xa8, 0x47, 0xad, 0x38, 0x0c, 0x3b, 0x7f, 0xc6, 0xe1, 0x3b, 0x0e, 0xa3,
+ 0xa4, 0xfd, 0x4b, 0x30, 0x39, 0xc3, 0x64, 0x29, 0x0b, 0x2b, 0xe3, 0x9a, 0xf2, 0xe9, 0x09, 0x3e,
+ 0x5e, 0x06, 0x77, 0xeb, 0x60, 0x11, 0x82, 0x1f, 0x3e, 0xf8, 0xd7, 0xf7, 0x01, 0xf9, 0xd7, 0x12,
+ 0x9c, 0x37, 0x83, 0xf3, 0x9f, 0x83, 0xbc, 0x29, 0xf2, 0x5f, 0x44, 0xde, 0x14, 0x79, 0x2d, 0x4e,
+ 0x4f, 0xf1, 0x51, 0x1d, 0xa1, 0xff, 0x71, 0x77, 0xb5, 0x0c, 0x08, 0xda, 0x17, 0xeb, 0xc7, 0x15,
+ 0xe9, 0x4c, 0xd9, 0xe1, 0x1a, 0x68, 0x0f, 0x37, 0xd6, 0x4c, 0xd0, 0x97, 0x1e, 0x08, 0x1a, 0x75,
+ 0x08, 0x9a, 0xfb, 0x4f, 0x97, 0x2a, 0xb1, 0x2f, 0x6e, 0xe3, 0x45, 0x26, 0x63, 0xca, 0xa4, 0x42,
+ 0x2b, 0x56, 0x6e, 0x74, 0xe3, 0xb6, 0xec, 0x15, 0x58, 0x94, 0xc5, 0x55, 0x1f, 0xcd, 0x94, 0xd4,
+ 0x33, 0x65, 0x98, 0x95, 0x85, 0x8d, 0x85, 0x15, 0xd5, 0x18, 0x3e, 0x02, 0x00, 0x00, 0xff, 0xff,
+ 0x26, 0xf5, 0x57, 0x52, 0x4e, 0x02, 0x00, 0x00,
}
diff --git a/cmd/protoc-gen-go/testdata/proto2/enum.proto b/cmd/protoc-gen-go/testdata/proto2/enum.proto
index aa52b9b..849ff6c 100644
--- a/cmd/protoc-gen-go/testdata/proto2/enum.proto
+++ b/cmd/protoc-gen-go/testdata/proto2/enum.proto
@@ -23,6 +23,9 @@
}
message EnumContainerMessage1 {
+ optional EnumType2 default_duplicate1 = 1 [default=duplicate1];
+ optional EnumType2 default_duplicate2 = 2 [default=duplicate2];
+
// NestedEnumType1A comment.
enum NestedEnumType1A {
// NestedEnumType1A_VALUE comment.
diff --git a/reflect/protoreflect/type.go b/reflect/protoreflect/type.go
index 6c9e69f..5885270 100644
--- a/reflect/protoreflect/type.go
+++ b/reflect/protoreflect/type.go
@@ -325,6 +325,10 @@
// The Value type is determined by the Kind.
Default() Value
+ // DefaultEnumValue returns the EnummValueDescriptor for the default value
+ // of an enum field, and is nil for any other kind of field.
+ DefaultEnumValue() EnumValueDescriptor
+
// HasDefault reports whether this field has a default value.
HasDefault() bool
diff --git a/reflect/prototype/protofile_type.go b/reflect/prototype/protofile_type.go
index 27d4db1..d5b4250 100644
--- a/reflect/prototype/protofile_type.go
+++ b/reflect/prototype/protofile_type.go
@@ -192,30 +192,31 @@
}
type fieldDesc struct{ f *Field }
-func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true }
-func (t fieldDesc) Index() int { return t.f.index }
-func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax }
-func (t fieldDesc) Name() pref.Name { return t.f.Name }
-func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
-func (t fieldDesc) IsPlaceholder() bool { return false }
-func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t fieldDesc) Options() interface{} { return t.f.Options }
-func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
-func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
-func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
-func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
-func (t fieldDesc) IsPacked() bool { return fieldIsPacked(t) }
-func (t fieldDesc) IsMap() bool { return isMap(t) }
-func (t fieldDesc) IsWeak() bool { return t.f.Options.GetWeak() }
-func (t fieldDesc) Default() pref.Value { return t.f.dv.lazyInit(t, t.f.Default) }
-func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
-func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
-func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
-func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
-func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
-func (t fieldDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
-func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
-func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
+func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true }
+func (t fieldDesc) Index() int { return t.f.index }
+func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax }
+func (t fieldDesc) Name() pref.Name { return t.f.Name }
+func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
+func (t fieldDesc) IsPlaceholder() bool { return false }
+func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
+func (t fieldDesc) Options() interface{} { return t.f.Options }
+func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
+func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
+func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
+func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
+func (t fieldDesc) IsPacked() bool { return fieldIsPacked(t) }
+func (t fieldDesc) IsMap() bool { return isMap(t) }
+func (t fieldDesc) IsWeak() bool { return t.f.Options.GetWeak() }
+func (t fieldDesc) Default() pref.Value { return t.f.dv.value(t, t.f.Default) }
+func (t fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.f.dv.enum(t, t.f.Default) }
+func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
+func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
+func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
+func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
+func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
+func (t fieldDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
+func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
+func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
func fieldIsPacked(t fieldDesc) bool {
if t.f.Options != nil && t.f.Options.Packed != nil {
@@ -330,24 +331,25 @@
}
type extensionDesc struct{ x *Extension }
-func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true }
-func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax }
-func (t extensionDesc) Index() int { return t.x.index }
-func (t extensionDesc) Name() pref.Name { return t.x.Name }
-func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
-func (t extensionDesc) IsPlaceholder() bool { return false }
-func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
-func (t extensionDesc) Options() interface{} { return t.x.Options }
-func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
-func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
-func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
-func (t extensionDesc) JSONName() string { return "" }
-func (t extensionDesc) IsPacked() bool { return t.x.Options.GetPacked() }
-func (t extensionDesc) IsMap() bool { return false }
-func (t extensionDesc) IsWeak() bool { return false }
-func (t extensionDesc) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
-func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
-func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil }
+func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true }
+func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax }
+func (t extensionDesc) Index() int { return t.x.index }
+func (t extensionDesc) Name() pref.Name { return t.x.Name }
+func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
+func (t extensionDesc) IsPlaceholder() bool { return false }
+func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
+func (t extensionDesc) Options() interface{} { return t.x.Options }
+func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
+func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
+func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
+func (t extensionDesc) JSONName() string { return "" }
+func (t extensionDesc) IsPacked() bool { return t.x.Options.GetPacked() }
+func (t extensionDesc) IsMap() bool { return false }
+func (t extensionDesc) IsWeak() bool { return false }
+func (t extensionDesc) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
+func (t extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return t.x.dv.enum(t, t.x.Default) }
+func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
+func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil }
func (t extensionDesc) ExtendedType() pref.MessageDescriptor {
return t.x.xt.lazyInit(t, &t.x.ExtendedType)
}
@@ -444,6 +446,7 @@
type defaultValue struct {
once sync.Once
val pref.Value
+ eval pref.EnumValueDescriptor
buf []byte
}
@@ -460,7 +463,7 @@
zeroEnum = pref.ValueOf(pref.EnumNumber(0))
)
-func (p *defaultValue) lazyInit(t pref.FieldDescriptor, v pref.Value) pref.Value {
+func (p *defaultValue) lazyInit(t pref.FieldDescriptor, v pref.Value) {
p.once.Do(func() {
p.val = v
if v.IsValid() {
@@ -470,11 +473,14 @@
// value by name and extract the enum number.
// If this fails, validateMessage will later detect that the
// default value for an enum value is the wrong type.
- if s, ok := v.Interface().(string); ok {
- v := t.EnumType().Values().ByName(pref.Name(s))
- if v != nil {
- p.val = pref.ValueOf(v.Number())
+ switch v := v.Interface().(type) {
+ case string:
+ if ev := t.EnumType().Values().ByName(pref.Name(v)); ev != nil {
+ p.eval = ev
+ p.val = pref.ValueOf(p.eval.Number())
}
+ case pref.EnumNumber:
+ p.eval = t.EnumType().Values().ByNumber(v)
}
case pref.BytesKind:
// Store a copy of the default bytes, so that we can detect
@@ -521,9 +527,18 @@
// original to induce a race that can be detected by the detector.
panic(fmt.Sprintf("proto: detected mutation on the default bytes for %v", t.FullName()))
}
+}
+
+func (p *defaultValue) value(t pref.FieldDescriptor, v pref.Value) pref.Value {
+ p.lazyInit(t, v)
return p.val
}
+func (p *defaultValue) enum(t pref.FieldDescriptor, v pref.Value) pref.EnumValueDescriptor {
+ p.lazyInit(t, v)
+ return p.eval
+}
+
// messageReference resolves PlaceholderMessages that reference declarations
// within the FileDescriptor tree that parent is a member of.
type messageReference struct{ once sync.Once }
diff --git a/reflect/prototype/standalone_type.go b/reflect/prototype/standalone_type.go
index bb014b6..0802acd 100644
--- a/reflect/prototype/standalone_type.go
+++ b/reflect/prototype/standalone_type.go
@@ -65,12 +65,15 @@
func (t standaloneExtension) IsPacked() bool { return t.x.Options.GetPacked() }
func (t standaloneExtension) IsMap() bool { return false }
func (t standaloneExtension) IsWeak() bool { return false }
-func (t standaloneExtension) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
-func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
-func (t standaloneExtension) OneofType() pref.OneofDescriptor { return nil }
-func (t standaloneExtension) MessageType() pref.MessageDescriptor { return t.x.MessageType }
-func (t standaloneExtension) EnumType() pref.EnumDescriptor { return t.x.EnumType }
-func (t standaloneExtension) ExtendedType() pref.MessageDescriptor { return t.x.ExtendedType }
-func (t standaloneExtension) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
-func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
-func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
+func (t standaloneExtension) Default() pref.Value { return t.x.dv.value(t, t.x.Default) }
+func (t standaloneExtension) DefaultEnumValue() pref.EnumValueDescriptor {
+ return t.x.dv.enum(t, t.x.Default)
+}
+func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
+func (t standaloneExtension) OneofType() pref.OneofDescriptor { return nil }
+func (t standaloneExtension) MessageType() pref.MessageDescriptor { return t.x.MessageType }
+func (t standaloneExtension) EnumType() pref.EnumDescriptor { return t.x.EnumType }
+func (t standaloneExtension) ExtendedType() pref.MessageDescriptor { return t.x.ExtendedType }
+func (t standaloneExtension) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
+func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
+func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
diff --git a/reflect/prototype/type_test.go b/reflect/prototype/type_test.go
index cf961f1..93334d5 100644
--- a/reflect/prototype/type_test.go
+++ b/reflect/prototype/type_test.go
@@ -67,7 +67,11 @@
// TestDescriptorAccessors tests that descriptorAccessors is up-to-date.
func TestDescriptorAccessors(t *testing.T) {
- ignore := map[string]bool{"ProtoType": true, "DescriptorByName": true}
+ ignore := map[string]bool{
+ "DefaultEnumValue": true,
+ "DescriptorByName": true,
+ "ProtoType": true,
+ }
rt := reflect.TypeOf((*pref.Descriptor)(nil)).Elem()
for i := 0; i < rt.NumMethod(); i++ {
ignore[rt.Method(i).Name] = true