internal/proto: implement SetDefaults with reflection

We cannot start replacing the implementation of v1 directly with reflection
since the scaffolding to avoid cyclic dependencies on descriptor proto
is not yet complete.

However, we can start re-writing functionality in a seperate package as if
they were replacing the version in the proto package.

For the time being, we just copy-paste the relevant tests in the proto
package to ensure the behavior is the same in both implementations.

Change-Id: Ibc9360edb4c8f43bbe60359b848bb2f998c22bf9
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/167761
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/proto/common.go b/internal/proto/common.go
new file mode 100644
index 0000000..7258bae
--- /dev/null
+++ b/internal/proto/common.go
@@ -0,0 +1,17 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+// TODO: This file exists to provide the illusion to other source files that
+// they live within the real proto package by providing functions and types
+// that they would otherwise be able to call directly.
+
+import (
+	"github.com/golang/protobuf/proto"
+
+	_ "github.com/golang/protobuf/v2/runtime/protolegacy"
+)
+
+type Message = proto.Message
diff --git a/internal/proto/defaults.go b/internal/proto/defaults.go
new file mode 100644
index 0000000..580d762
--- /dev/null
+++ b/internal/proto/defaults.go
@@ -0,0 +1,65 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import (
+	pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+	"github.com/golang/protobuf/v2/runtime/protoimpl"
+)
+
+// SetDefaults sets unset protocol buffer fields to their default values.
+// It only modifies fields that are both unset and have defined defaults.
+// It recursively sets default values in any non-nil sub-messages.
+// It does not descend into extension fields that are sub-messages.
+func SetDefaults(m Message) {
+	setDefaults(protoimpl.X.MessageOf(m))
+}
+
+func setDefaults(m pref.Message) {
+	fieldTypes := m.Type().Fields()
+	knownFields := m.KnownFields()
+	for i := 0; i < fieldTypes.Len(); i++ {
+		fd := fieldTypes.Get(i)
+		num := fd.Number()
+		if !knownFields.Has(num) {
+			if fd.HasDefault() {
+				v := fd.Default()
+				if fd.Kind() == pref.BytesKind {
+					v = pref.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
+				}
+				knownFields.Set(num, v)
+			}
+			continue
+		}
+		switch {
+		// Handle singular message.
+		case fd.Cardinality() != pref.Repeated:
+			if k := fd.Kind(); k == pref.MessageKind || k == pref.GroupKind {
+				setDefaults(knownFields.Get(num).Message())
+			}
+		// Handle list of messages.
+		case !fd.IsMap():
+			if k := fd.Kind(); k == pref.MessageKind || k == pref.GroupKind {
+				ls := knownFields.Get(num).List()
+				for i := 0; i < ls.Len(); i++ {
+					setDefaults(ls.Get(i).Message())
+				}
+			}
+		// Handle map of messages.
+		default:
+			k := fd.MessageType().Fields().ByNumber(2).Kind()
+			if k == pref.MessageKind || k == pref.GroupKind {
+				ms := knownFields.Get(num).Map()
+				ms.Range(func(_ pref.MapKey, v pref.Value) bool {
+					setDefaults(v.Message())
+					return true
+				})
+			}
+		}
+	}
+
+	// NOTE: Historically, this function has never set the defaults for
+	// extension fields, nor recursively visited sub-messages of such fields.
+}
diff --git a/proto/all_test.go b/proto/all_test.go
index a16c056..abd3ce0 100644
--- a/proto/all_test.go
+++ b/proto/all_test.go
@@ -18,6 +18,7 @@
 	"testing"
 	"time"
 
+	protoV1a "github.com/golang/protobuf/internal/proto"
 	. "github.com/golang/protobuf/proto"
 	pb3 "github.com/golang/protobuf/proto/proto3_proto"
 	. "github.com/golang/protobuf/proto/test_proto"
@@ -1371,6 +1372,38 @@
 	}
 }
 
+func TestAllSetDefaults2(t *testing.T) {
+	// Exercise SetDefaults with all scalar field types.
+	m := &Defaults{
+		// NaN != NaN, so override that here.
+		F_Nan: Float32(1.7),
+	}
+	expected := &Defaults{
+		F_Bool:    Bool(true),
+		F_Int32:   Int32(32),
+		F_Int64:   Int64(64),
+		F_Fixed32: Uint32(320),
+		F_Fixed64: Uint64(640),
+		F_Uint32:  Uint32(3200),
+		F_Uint64:  Uint64(6400),
+		F_Float:   Float32(314159),
+		F_Double:  Float64(271828),
+		F_String:  String(`hello, "world!"` + "\n"),
+		F_Bytes:   []byte("Bignose"),
+		F_Sint32:  Int32(-32),
+		F_Sint64:  Int64(-64),
+		F_Enum:    Defaults_GREEN.Enum(),
+		F_Pinf:    Float32(float32(math.Inf(1))),
+		F_Ninf:    Float32(float32(math.Inf(-1))),
+		F_Nan:     Float32(1.7),
+		StrZero:   String(""),
+	}
+	protoV1a.SetDefaults(m)
+	if !Equal(m, expected) {
+		t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected)
+	}
+}
+
 func TestSetDefaultsWithSetField(t *testing.T) {
 	// Check that a set value is not overridden.
 	m := &Defaults{
@@ -1382,6 +1415,17 @@
 	}
 }
 
+func TestSetDefaultsWithSetField2(t *testing.T) {
+	// Check that a set value is not overridden.
+	m := &Defaults{
+		F_Int32: Int32(12),
+	}
+	protoV1a.SetDefaults(m)
+	if v := m.GetF_Int32(); v != 12 {
+		t.Errorf("m.FInt32 = %v, want 12", v)
+	}
+}
+
 func TestSetDefaultsWithSubMessage(t *testing.T) {
 	m := &OtherMessage{
 		Key: Int64(123),
@@ -1402,6 +1446,26 @@
 	}
 }
 
+func TestSetDefaultsWithSubMessage2(t *testing.T) {
+	m := &OtherMessage{
+		Key: Int64(123),
+		Inner: &InnerMessage{
+			Host: String("gopher"),
+		},
+	}
+	expected := &OtherMessage{
+		Key: Int64(123),
+		Inner: &InnerMessage{
+			Host: String("gopher"),
+			Port: Int32(4000),
+		},
+	}
+	protoV1a.SetDefaults(m)
+	if !Equal(m, expected) {
+		t.Errorf("\n got %v\nwant %v", m, expected)
+	}
+}
+
 func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) {
 	m := &MyMessage{
 		RepInner: []*InnerMessage{{}},
@@ -1417,6 +1481,21 @@
 	}
 }
 
+func TestSetDefaultsWithRepeatedSubMessage2(t *testing.T) {
+	m := &MyMessage{
+		RepInner: []*InnerMessage{{}},
+	}
+	expected := &MyMessage{
+		RepInner: []*InnerMessage{{
+			Port: Int32(4000),
+		}},
+	}
+	protoV1a.SetDefaults(m)
+	if !Equal(m, expected) {
+		t.Errorf("\n got %v\nwant %v", m, expected)
+	}
+}
+
 func TestSetDefaultWithRepeatedNonMessage(t *testing.T) {
 	m := &MyMessage{
 		Pet: []string{"turtle", "wombat"},
@@ -1428,6 +1507,17 @@
 	}
 }
 
+func TestSetDefaultWithRepeatedNonMessage2(t *testing.T) {
+	m := &MyMessage{
+		Pet: []string{"turtle", "wombat"},
+	}
+	expected := Clone(m)
+	protoV1a.SetDefaults(m)
+	if !Equal(m, expected) {
+		t.Errorf("\n got %v\nwant %v", m, expected)
+	}
+}
+
 func TestMaximumTagNumber(t *testing.T) {
 	m := &MaxTag{
 		LastField: String("natural goat essence"),
diff --git a/proto/proto3_test.go b/proto/proto3_test.go
index 943ca20..a09f0fb 100644
--- a/proto/proto3_test.go
+++ b/proto/proto3_test.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"testing"
 
+	protoV1a "github.com/golang/protobuf/internal/proto"
 	"github.com/golang/protobuf/proto"
 	pb "github.com/golang/protobuf/proto/proto3_proto"
 	tpb "github.com/golang/protobuf/proto/test_proto"
@@ -108,6 +109,37 @@
 	}
 }
 
+func TestProto3SetDefaults2(t *testing.T) {
+	in := &pb.Message{
+		Terrain: map[string]*pb.Nested{
+			"meadow": new(pb.Nested),
+		},
+		Proto2Field: new(tpb.SubDefaults),
+		Proto2Value: map[string]*tpb.SubDefaults{
+			"badlands": new(tpb.SubDefaults),
+		},
+	}
+
+	got := proto.Clone(in).(*pb.Message)
+	protoV1a.SetDefaults(got)
+
+	// There are no defaults in proto3.  Everything should be the zero value, but
+	// we need to remember to set defaults for nested proto2 messages.
+	want := &pb.Message{
+		Terrain: map[string]*pb.Nested{
+			"meadow": new(pb.Nested),
+		},
+		Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)},
+		Proto2Value: map[string]*tpb.SubDefaults{
+			"badlands": &tpb.SubDefaults{N: proto.Int64(7)},
+		},
+	}
+
+	if !proto.Equal(got, want) {
+		t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want)
+	}
+}
+
 func TestUnknownFieldPreservation(t *testing.T) {
 	b1 := "\x0a\x05David"      // Known tag 1
 	b2 := "\xc2\x0c\x06Google" // Unknown tag 200