internal/impl: change Go representation of extension lists to []T

Change-Id: Iebcefe0330c8f858c7735f9362abfd87043ee39d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/192458
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/codec_tables.go b/internal/impl/codec_tables.go
index 31fc412..a332922 100644
--- a/internal/impl/codec_tables.go
+++ b/internal/impl/codec_tables.go
@@ -431,10 +431,13 @@
 func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) valueCoderFuncs {
 	switch {
 	case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
-		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+		if ft.Kind() == reflect.Ptr {
+			ft = ft.Elem()
+		}
+		if ft.Kind() != reflect.Slice {
 			break
 		}
-		ft := ft.Elem().Elem()
+		ft := ft.Elem()
 		switch fd.Kind() {
 		case pref.BoolKind:
 			if ft.Kind() == reflect.Bool {
@@ -512,10 +515,13 @@
 			return coderGroupSliceValue
 		}
 	case fd.Cardinality() == pref.Repeated && fd.IsPacked():
-		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+		if ft.Kind() == reflect.Ptr {
+			ft = ft.Elem()
+		}
+		if ft.Kind() != reflect.Slice {
 			break
 		}
-		ft := ft.Elem().Elem()
+		ft := ft.Elem()
 		switch fd.Kind() {
 		case pref.BoolKind:
 			if ft.Kind() == reflect.Bool {
diff --git a/internal/impl/convert_list.go b/internal/impl/convert_list.go
index 19748b4..fa3a400 100644
--- a/internal/impl/convert_list.go
+++ b/internal/impl/convert_list.go
@@ -11,27 +11,36 @@
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
+func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
+	switch {
+	case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Slice:
+		return &listPtrConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
+	case t.Kind() == reflect.Slice:
+		return &listConverter{t, newSingularConverter(t.Elem(), fd)}
+	}
+	panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
+}
+
 type listConverter struct {
 	goType reflect.Type
 	c      Converter
 }
 
-func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
-	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
-		panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
-	}
-	return &listConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
-}
-
 func (c *listConverter) PBValueOf(v reflect.Value) pref.Value {
 	if v.Type() != c.goType {
 		panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
 	}
-	return pref.ValueOf(&listReflect{v, c.c})
+	pv := reflect.New(c.goType)
+	pv.Elem().Set(v)
+	return pref.ValueOf(&listReflect{pv, c.c})
 }
 
 func (c *listConverter) GoValueOf(v pref.Value) reflect.Value {
-	return v.List().(*listReflect).v
+	rv := v.List().(*listReflect).v
+	if rv.IsNil() {
+		return reflect.Zero(c.goType)
+	}
+	return rv.Elem()
 }
 
 func (c *listConverter) IsValidPB(v pref.Value) bool {
@@ -39,7 +48,7 @@
 	if !ok {
 		return false
 	}
-	return list.v.Type() == c.goType
+	return list.v.Type().Elem() == c.goType
 }
 
 func (c *listConverter) IsValidGo(v reflect.Value) bool {
@@ -47,10 +56,46 @@
 }
 
 func (c *listConverter) New() pref.Value {
-	return c.PBValueOf(reflect.New(c.goType.Elem()))
+	return pref.ValueOf(&listReflect{reflect.New(c.goType), c.c})
 }
 
 func (c *listConverter) Zero() pref.Value {
+	return pref.ValueOf(&listReflect{reflect.Zero(reflect.PtrTo(c.goType)), c.c})
+}
+
+type listPtrConverter struct {
+	goType reflect.Type
+	c      Converter
+}
+
+func (c *listPtrConverter) PBValueOf(v reflect.Value) pref.Value {
+	if v.Type() != c.goType {
+		panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
+	}
+	return pref.ValueOf(&listReflect{v, c.c})
+}
+
+func (c *listPtrConverter) GoValueOf(v pref.Value) reflect.Value {
+	return v.List().(*listReflect).v
+}
+
+func (c *listPtrConverter) IsValidPB(v pref.Value) bool {
+	list, ok := v.Interface().(*listReflect)
+	if !ok {
+		return false
+	}
+	return list.v.Type() == c.goType
+}
+
+func (c *listPtrConverter) IsValidGo(v reflect.Value) bool {
+	return v.Type() == c.goType
+}
+
+func (c *listPtrConverter) New() pref.Value {
+	return c.PBValueOf(reflect.New(c.goType.Elem()))
+}
+
+func (c *listPtrConverter) Zero() pref.Value {
 	return c.PBValueOf(reflect.Zero(c.goType))
 }
 
diff --git a/internal/impl/extension.go b/internal/impl/extension.go
index 8192223..c64f8f5 100644
--- a/internal/impl/extension.go
+++ b/internal/impl/extension.go
@@ -151,7 +151,7 @@
 		xi.initFromLegacy()
 	} else if xi.desc.Cardinality() == pref.Repeated {
 		// Cardinality is initialized lazily, so we defer consulting it until here.
-		xi.goType = reflect.PtrTo(reflect.SliceOf(xi.goType))
+		xi.goType = reflect.SliceOf(xi.goType)
 	}
 	xi.conv = NewConverter(xi.goType, xi.desc)
 	xi.tdesc.ExtensionDescriptor = xi.desc
diff --git a/internal/impl/legacy_extension.go b/internal/impl/legacy_extension.go
index 02e021b..b845f35 100644
--- a/internal/impl/legacy_extension.go
+++ b/internal/impl/legacy_extension.go
@@ -71,10 +71,6 @@
 	switch extType.Kind() {
 	case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
 		extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
-	case reflect.Ptr:
-		if extType.Elem().Kind() == reflect.Slice {
-			extType = extType.Elem() // *[]T -> []T for repeated fields
-		}
 	}
 
 	// Reconstruct the legacy enum full name.
@@ -154,8 +150,6 @@
 	tt := reflect.TypeOf(xi.ExtensionType)
 	if isOptional {
 		tt = tt.Elem()
-	} else if isRepeated {
-		tt = reflect.PtrTo(tt)
 	}
 	xi.desc = xd
 	xi.goType = tt
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index 08daace..3ff3f3c 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -392,16 +392,16 @@
 		7:  m1a,
 		8:  EnumProto2(0xbeef),
 		9:  m2a,
-		10: &[]bool{true},
-		11: &[]int32{-1000},
-		12: &[]uint32{1280},
-		13: &[]float32{1.6180},
-		14: &[]string{"zero"},
-		15: &[][]byte{[]byte("zero")},
-		16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
-		17: &[]*proto2_20180125.Message_ChildMessage{m1b},
-		18: &[]EnumProto2{0xdead},
-		19: &[]*EnumMessages{m2b},
+		10: []bool{true},
+		11: []int32{-1000},
+		12: []uint32{1280},
+		13: []float32{1.6180},
+		14: []string{"zero"},
+		15: [][]byte{[]byte("zero")},
+		16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO},
+		17: []*proto2_20180125.Message_ChildMessage{m1b},
+		18: []EnumProto2{0xdead},
+		19: []*EnumMessages{m2b},
 	}
 	for i, xt := range extensionTypes {
 		m.Set(xt.TypeDescriptor(), xt.ValueOf(setValues[i]))
@@ -423,16 +423,16 @@
 		7:  m1a,
 		8:  EnumProto2(0xbeef),
 		9:  m2a,
-		10: &[]bool{true, false},
-		11: &[]int32{-1000, -54321},
-		12: &[]uint32{1280, 6400},
-		13: &[]float32{1.6180, 2.71828},
-		14: &[]string{"zero", "goodbye, \"world!\"\n"},
-		15: &[][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
-		16: &[]proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
-		17: &[]*proto2_20180125.Message_ChildMessage{m1b, m1a},
-		18: &[]EnumProto2{0xdead, 0xbeef},
-		19: &[]*EnumMessages{m2b, m2a},
+		10: []bool{true, false},
+		11: []int32{-1000, -54321},
+		12: []uint32{1280, 6400},
+		13: []float32{1.6180, 2.71828},
+		14: []string{"zero", "goodbye, \"world!\"\n"},
+		15: [][]byte{[]byte("zero"), []byte("live\xde\xad\xbe\xefchicken")},
+		16: []proto2_20180125.Message_ChildEnum{proto2_20180125.Message_BRAVO, proto2_20180125.Message_CHARLIE},
+		17: []*proto2_20180125.Message_ChildMessage{m1b, m1a},
+		18: []EnumProto2{0xdead, 0xbeef},
+		19: []*EnumMessages{m2b, m2a},
 	}
 	for i, xt := range extensionTypes {
 		xd := xt.TypeDescriptor()