all: implement support for proto3 optional semantics

In the upcoming 3.12.x release of protoc, the proto3 language will be
amended to support true presence for scalars. This CL adds support
to both the generator and runtime to support these semantics.

Newly added public API:
	protogen.Plugin.SupportedFeatures
	protoreflect.FieldDescriptor.HasPresence
	protoreflect.FieldDescriptor.HasOptionalKeyword
	protoreflect.OneofDescriptor.IsSynthetic

Change-Id: I7c86bf66d0ae56642109beb5f2132184593747ad
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/230698
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/codec_message.go b/internal/impl/codec_message.go
index 5259f2f..29ed59b 100644
--- a/internal/impl/codec_message.go
+++ b/internal/impl/codec_message.go
@@ -63,7 +63,8 @@
 		fd := fields.Get(i)
 
 		fs := si.fieldsByNumber[fd.Number()]
-		if fd.ContainingOneof() != nil {
+		isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
+		if isOneof {
 			fs = si.oneofsByName[fd.ContainingOneof().Name()]
 		}
 		ft := fs.Type
@@ -77,7 +78,7 @@
 		var funcs pointerCoderFuncs
 		var childMessage *MessageInfo
 		switch {
-		case fd.ContainingOneof() != nil:
+		case isOneof:
 			fieldOffset = offsetOf(fs, mi.Exporter)
 		case fd.IsWeak():
 			fieldOffset = si.weakOffset
@@ -102,17 +103,16 @@
 			funcs:      funcs,
 			mi:         childMessage,
 			validation: newFieldValidationInfo(mi, si, fd, ft),
-			isPointer: (fd.Cardinality() == pref.Repeated ||
-				fd.Kind() == pref.MessageKind ||
-				fd.Kind() == pref.GroupKind ||
-				fd.Syntax() != pref.Proto3),
+			isPointer:  fd.Cardinality() == pref.Repeated || fd.HasPresence(),
 			isRequired: fd.Cardinality() == pref.Required,
 		}
 		mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
 		mi.coderFields[cf.num] = cf
 	}
 	for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
-		mi.initOneofFieldCoders(oneofs.Get(i), si)
+		if od := oneofs.Get(i); !od.IsSynthetic() {
+			mi.initOneofFieldCoders(od, si)
+		}
 	}
 	if messageset.IsMessageSet(mi.Desc) {
 		if !mi.extensionOffset.IsValid() {
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index 93c318f..61757ce 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -155,6 +155,8 @@
 func (x placeholderExtension) Kind() pref.Kind                            { return 0 }
 func (x placeholderExtension) HasJSONName() bool                          { return false }
 func (x placeholderExtension) JSONName() string                           { return "" }
+func (x placeholderExtension) HasPresence() bool                          { return false }
+func (x placeholderExtension) HasOptionalKeyword() bool                   { return false }
 func (x placeholderExtension) IsExtension() bool                          { return true }
 func (x placeholderExtension) IsWeak() bool                               { return false }
 func (x placeholderExtension) IsPacked() bool                             { return false }
diff --git a/internal/impl/message_reflect.go b/internal/impl/message_reflect.go
index 28114ff..3eb2b13 100644
--- a/internal/impl/message_reflect.go
+++ b/internal/impl/message_reflect.go
@@ -53,7 +53,7 @@
 		fs := si.fieldsByNumber[fd.Number()]
 		var fi fieldInfo
 		switch {
-		case fd.ContainingOneof() != nil:
+		case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
 			fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
 		case fd.IsMap():
 			fi = fieldInfoForMap(fd, fs, mi.Exporter)
@@ -72,7 +72,7 @@
 	mi.oneofs = map[pref.Name]*oneofInfo{}
 	for i := 0; i < md.Oneofs().Len(); i++ {
 		od := md.Oneofs().Get(i)
-		mi.oneofs[od.Name()] = makeOneofInfo(od, si.oneofsByName[od.Name()], mi.Exporter, si.oneofWrappersByType)
+		mi.oneofs[od.Name()] = makeOneofInfo(od, si, mi.Exporter)
 	}
 
 	mi.denseFields = make([]*fieldInfo, fds.Len()*2)
@@ -84,7 +84,7 @@
 
 	for i := 0; i < fds.Len(); {
 		fd := fds.Get(i)
-		if od := fd.ContainingOneof(); od != nil {
+		if od := fd.ContainingOneof(); od != nil && !od.IsSynthetic() {
 			mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
 			i += od.Fields().Len()
 		} else {
diff --git a/internal/impl/message_reflect_field.go b/internal/impl/message_reflect_field.go
index 7b87d47..ea6f755 100644
--- a/internal/impl/message_reflect_field.go
+++ b/internal/impl/message_reflect_field.go
@@ -221,7 +221,7 @@
 
 func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
 	ft := fs.Type
-	nullable := fd.Syntax() == pref.Proto2
+	nullable := fd.HasPresence()
 	isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
 	if nullable {
 		if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
@@ -290,9 +290,9 @@
 			rv.Set(conv.GoValueOf(v))
 			if isBytes && rv.Len() == 0 {
 				if nullable {
-					rv.Set(emptyBytes) // preserve presence in proto2
+					rv.Set(emptyBytes) // preserve presence
 				} else {
-					rv.Set(nilBytes) // do not preserve presence in proto3
+					rv.Set(nilBytes) // do not preserve presence
 				}
 			}
 		},
@@ -426,11 +426,25 @@
 	which     func(pointer) pref.FieldNumber
 }
 
-func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, x exporter, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
-	fieldOffset := offsetOf(fs, x)
-	return &oneofInfo{
-		oneofDesc: od,
-		which: func(p pointer) pref.FieldNumber {
+func makeOneofInfo(od pref.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
+	oi := &oneofInfo{oneofDesc: od}
+	if od.IsSynthetic() {
+		fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
+		fieldOffset := offsetOf(fs, x)
+		oi.which = func(p pointer) pref.FieldNumber {
+			if p.IsNil() {
+				return 0
+			}
+			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
+			if rv.IsNil() { // valid on either *T or []byte
+				return 0
+			}
+			return od.Fields().Get(0).Number()
+		}
+	} else {
+		fs := si.oneofsByName[od.Name()]
+		fieldOffset := offsetOf(fs, x)
+		oi.which = func(p pointer) pref.FieldNumber {
 			if p.IsNil() {
 				return 0
 			}
@@ -442,7 +456,8 @@
 			if rv.IsNil() {
 				return 0
 			}
-			return wrappersByType[rv.Type().Elem()]
-		},
+			return si.oneofWrappersByType[rv.Type().Elem()]
+		}
 	}
+	return oi
 }
diff --git a/internal/impl/validate.go b/internal/impl/validate.go
index 39d62fd..57de9cc 100644
--- a/internal/impl/validate.go
+++ b/internal/impl/validate.go
@@ -108,7 +108,7 @@
 func newFieldValidationInfo(mi *MessageInfo, si structInfo, fd pref.FieldDescriptor, ft reflect.Type) validationInfo {
 	var vi validationInfo
 	switch {
-	case fd.ContainingOneof() != nil:
+	case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
 		switch fd.Kind() {
 		case pref.MessageKind:
 			vi.typ = validationTypeMessage