reflect/protoreflect: add List.AppendMutable and Map.Mutable

Add methods to add a new, mutable message to a list or map, matching the
existing Message.Mutable.

These methods are purely a convenience, as each can be implemented in
terms of the existing interface.

Change-Id: I889c20fe37ea0f2a566555212e99e6378fb9fe1d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/220117
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/convert_list.go b/internal/impl/convert_list.go
index 1c86942..fe9384a 100644
--- a/internal/impl/convert_list.go
+++ b/internal/impl/convert_list.go
@@ -119,6 +119,14 @@
 func (ls *listReflect) Append(v pref.Value) {
 	ls.v.Elem().Set(reflect.Append(ls.v.Elem(), ls.conv.GoValueOf(v)))
 }
+func (ls *listReflect) AppendMutable() pref.Value {
+	if _, ok := ls.conv.(*messageConverter); !ok {
+		panic("invalid AppendMutable on list with non-message type")
+	}
+	v := ls.NewElement()
+	ls.Append(v)
+	return v
+}
 func (ls *listReflect) Truncate(i int) {
 	ls.v.Elem().Set(ls.v.Elem().Slice(0, i))
 }
diff --git a/internal/impl/convert_map.go b/internal/impl/convert_map.go
index fcb1450..3ef36d3 100644
--- a/internal/impl/convert_map.go
+++ b/internal/impl/convert_map.go
@@ -89,6 +89,17 @@
 	rk := ms.keyConv.GoValueOf(k.Value())
 	ms.v.SetMapIndex(rk, reflect.Value{})
 }
+func (ms *mapReflect) Mutable(k pref.MapKey) pref.Value {
+	if _, ok := ms.valConv.(*messageConverter); !ok {
+		panic("invalid Mutable on map with non-message value type")
+	}
+	v := ms.Get(k)
+	if !v.IsValid() {
+		v = ms.NewValue()
+		ms.Set(k, v)
+	}
+	return v
+}
 func (ms *mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
 	iter := mapRange(ms.v)
 	for iter.Next() {
diff --git a/reflect/protoreflect/value.go b/reflect/protoreflect/value.go
index 5ea914d..2149446 100644
--- a/reflect/protoreflect/value.go
+++ b/reflect/protoreflect/value.go
@@ -200,7 +200,10 @@
 	// Append is a mutating operation and unsafe for concurrent use.
 	Append(Value)
 
-	// TODO(blocks): Should there be a AppendMutable method?
+	// AppendMutable appends a new, empty, mutable message value to the end
+	// of the list and returns it.
+	// It panics if the list does not contain a message type.
+	AppendMutable() Value
 
 	// Truncate truncates the list to a smaller length.
 	//
@@ -258,7 +261,11 @@
 	// Set is a mutating operation and unsafe for concurrent use.
 	Set(MapKey, Value)
 
-	// TODO(blocks): Should there be a Mutable method?
+	// Mutable retrieves a mutable reference to the entry for the given key.
+	// If no entry exists for the key, it creates a new, empty, mutable value
+	// and stores it as the entry for the key.
+	// It panics if the map value is not a message.
+	Mutable(MapKey) Value
 
 	// NewValue returns a new value assignable as a map value.
 	// For enums, this returns the first enum value.
diff --git a/testing/prototest/prototest.go b/testing/prototest/prototest.go
index 050a61d..0c6b700 100644
--- a/testing/prototest/prototest.go
+++ b/testing/prototest/prototest.go
@@ -296,16 +296,37 @@
 		t.Errorf("non-existent map key in %q: Map.Get(%v).IsValid() = %v, want %v", name, formatValue(missingKey.Value()), got, want)
 	}
 	mapv.Clear(missingKey) // noop
+
+	// Mutable.
+	if fd.MapValue().Message() == nil {
+		if !panics(func() {
+			mapv.Mutable(newMapKey(fd, 1))
+		}) {
+			t.Errorf("Mutable on %q succeeds, want panic", name)
+		}
+	} else {
+		k := newMapKey(fd, 1)
+		v := mapv.Mutable(k)
+		if got, want := mapv.Len(), 1; got != want {
+			t.Errorf("after Mutable on %q, Map.Len() = %v, want %v", name, got, want)
+		}
+		populateMessage(v.Message(), 1, nil)
+		if !valueEqual(mapv.Get(k), v) {
+			t.Errorf("after Mutable on %q, changing new mutable value does not change map entry", name)
+		}
+		mapv.Clear(k)
+	}
 }
 
 type testMap map[interface{}]pref.Value
 
-func (m testMap) Get(k pref.MapKey) pref.Value    { return m[k.Interface()] }
-func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
-func (m testMap) Has(k pref.MapKey) bool          { return m.Get(k).IsValid() }
-func (m testMap) Clear(k pref.MapKey)             { delete(m, k.Interface()) }
-func (m testMap) Len() int                        { return len(m) }
-func (m testMap) NewValue() pref.Value            { panic("unimplemented") }
+func (m testMap) Get(k pref.MapKey) pref.Value     { return m[k.Interface()] }
+func (m testMap) Set(k pref.MapKey, v pref.Value)  { m[k.Interface()] = v }
+func (m testMap) Has(k pref.MapKey) bool           { return m.Get(k).IsValid() }
+func (m testMap) Clear(k pref.MapKey)              { delete(m, k.Interface()) }
+func (m testMap) Mutable(k pref.MapKey) pref.Value { panic("unimplemented") }
+func (m testMap) Len() int                         { return len(m) }
+func (m testMap) NewValue() pref.Value             { panic("unimplemented") }
 func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
 	for k, v := range m {
 		if !f(pref.ValueOf(k).MapKey(), v) {
@@ -383,19 +404,39 @@
 			t.Errorf("after truncating %q to %d:\nMessage.Get(%v) = %v, want %v", name, n, num, formatValue(got), formatValue(want))
 		}
 	}
+
+	// AppendMutable.
+	if fd.Message() == nil {
+		if !panics(func() {
+			list.AppendMutable()
+		}) {
+			t.Errorf("AppendMutable on %q succeeds, want panic", name)
+		}
+	} else {
+		v := list.AppendMutable()
+		if got, want := list.Len(), 1; got != want {
+			t.Errorf("after AppendMutable on %q, list.Len() = %v, want %v", name, got, want)
+		}
+		populateMessage(v.Message(), 1, nil)
+		if !valueEqual(list.Get(0), v) {
+			t.Errorf("after AppendMutable on %q, changing new mutable value does not change list item 0", name)
+		}
+		want.Truncate(0)
+	}
 }
 
 type testList struct {
 	a []pref.Value
 }
 
-func (l *testList) Append(v pref.Value)     { l.a = append(l.a, v) }
-func (l *testList) Get(n int) pref.Value    { return l.a[n] }
-func (l *testList) Len() int                { return len(l.a) }
-func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
-func (l *testList) Truncate(n int)          { l.a = l.a[:n] }
-func (l *testList) NewElement() pref.Value  { panic("unimplemented") }
-func (l *testList) IsValid() bool           { return true }
+func (l *testList) Append(v pref.Value)       { l.a = append(l.a, v) }
+func (l *testList) AppendMutable() pref.Value { panic("unimplemented") }
+func (l *testList) Get(n int) pref.Value      { return l.a[n] }
+func (l *testList) Len() int                  { return len(l.a) }
+func (l *testList) Set(n int, v pref.Value)   { l.a[n] = v }
+func (l *testList) Truncate(n int)            { l.a = l.a[:n] }
+func (l *testList) NewElement() pref.Value    { panic("unimplemented") }
+func (l *testList) IsValid() bool             { return true }
 
 // testFieldFloat exercises some interesting floating-point scalar field values.
 func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
@@ -605,9 +646,6 @@
 		mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
 		return pref.ValueOfMap(mapv)
 	case fd.Message() != nil:
-		//if n == 0 {
-		//	return m.New().Get(fd)
-		//}
 		return populateMessage(m.NewField(fd).Message(), n, stack)
 	default:
 		return newScalarValue(fd, n)
diff --git a/types/dynamicpb/dynamic.go b/types/dynamicpb/dynamic.go
index 991624a..f206c18 100644
--- a/types/dynamicpb/dynamic.go
+++ b/types/dynamicpb/dynamic.go
@@ -314,13 +314,14 @@
 	desc pref.FieldDescriptor
 }
 
-func (x emptyList) Len() int                { return 0 }
-func (x emptyList) Get(n int) pref.Value    { panic(errors.New("out of range")) }
-func (x emptyList) Set(n int, v pref.Value) { panic(errors.New("modification of immutable list")) }
-func (x emptyList) Append(v pref.Value)     { panic(errors.New("modification of immutable list")) }
-func (x emptyList) Truncate(n int)          { panic(errors.New("modification of immutable list")) }
-func (x emptyList) NewElement() pref.Value  { return newListEntry(x.desc) }
-func (x emptyList) IsValid() bool           { return false }
+func (x emptyList) Len() int                  { return 0 }
+func (x emptyList) Get(n int) pref.Value      { panic(errors.New("out of range")) }
+func (x emptyList) Set(n int, v pref.Value)   { panic(errors.New("modification of immutable list")) }
+func (x emptyList) Append(v pref.Value)       { panic(errors.New("modification of immutable list")) }
+func (x emptyList) AppendMutable() pref.Value { panic(errors.New("modification of immutable list")) }
+func (x emptyList) Truncate(n int)            { panic(errors.New("modification of immutable list")) }
+func (x emptyList) NewElement() pref.Value    { return newListEntry(x.desc) }
+func (x emptyList) IsValid() bool             { return false }
 
 type dynamicList struct {
 	desc pref.FieldDescriptor
@@ -345,6 +346,15 @@
 	x.list = append(x.list, v)
 }
 
+func (x *dynamicList) AppendMutable() pref.Value {
+	if x.desc.Message() == nil {
+		panic(errors.New("%v: invalid AppendMutable on list with non-message type", x.desc.FullName()))
+	}
+	v := x.NewElement()
+	x.Append(v)
+	return v
+}
+
 func (x *dynamicList) Truncate(n int) {
 	// Zero truncated elements to avoid keeping data live.
 	for i := n; i < len(x.list); i++ {
@@ -374,7 +384,18 @@
 }
 func (x *dynamicMap) Has(k pref.MapKey) bool { return x.Get(k).IsValid() }
 func (x *dynamicMap) Clear(k pref.MapKey)    { delete(x.mapv, k.Interface()) }
-func (x *dynamicMap) Len() int               { return len(x.mapv) }
+func (x *dynamicMap) Mutable(k pref.MapKey) pref.Value {
+	if x.desc.MapValue().Message() == nil {
+		panic(errors.New("%v: invalid Mutable on map with non-message value type", x.desc.FullName()))
+	}
+	v := x.Get(k)
+	if !v.IsValid() {
+		v = x.NewValue()
+		x.Set(k, v)
+	}
+	return v
+}
+func (x *dynamicMap) Len() int { return len(x.mapv) }
 func (x *dynamicMap) NewValue() pref.Value {
 	if md := x.desc.MapValue().Message(); md != nil {
 		return pref.ValueOfMessage(NewMessage(md).ProtoReflect())