proto: add IsInitialized

Move all checks for required fields into a proto.IsInitialized function.

Initial testing makes me confident that we can provide a fast-path
implementation of IsInitialized which will perform more than
acceptably.  (In the degenerate-but-common case where a message
transitively contains no required fields, this check can be nearly
zero cost.)

Unifying checks into a single function provides consistent behavior
between the wire, text, and json codecs.

Performing the check after decoding eliminates the wire decoder bug
where a split message is incorrectly seen as missing required fields.

Performing the check after decoding also provides consistent and
arguably more correct behavior when the target message was partially
prepopulated.

Change-Id: I9478b7bebb263af00c0d9f66a1f26e31ff553522
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170787
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/proto/decode.go b/proto/decode.go
index 2b871c4..11fed46 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -42,10 +42,18 @@
 // Unmarshal parses the wire-format message in b and places the result in m.
 func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
 	// TODO: Reset m?
-	if err := o.unmarshalMessageFast(b, m); err != errInternalNoFast {
+	err := o.unmarshalMessageFast(b, m)
+	if err == errInternalNoFast {
+		err = o.unmarshalMessage(b, m.ProtoReflect())
+	}
+	var nerr errors.NonFatal
+	if !nerr.Merge(err) {
 		return err
 	}
-	return o.unmarshalMessage(b, m.ProtoReflect())
+	if !o.AllowPartial {
+		nerr.Merge(IsInitialized(m))
+	}
+	return nerr.E
 }
 
 func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
@@ -100,9 +108,6 @@
 		}
 		b = b[tagLen+valLen:]
 	}
-	if !o.AllowPartial {
-		checkRequiredFields(m, &nerr)
-	}
 	return nerr.E
 }
 
@@ -204,9 +209,6 @@
 	if !haveVal {
 		switch valField.Kind() {
 		case protoreflect.GroupKind, protoreflect.MessageKind:
-			if !o.AllowPartial {
-				checkRequiredFields(val.Message(), &nerr)
-			}
 		default:
 			val = valField.Default()
 		}