libgo patch committed: Canonicalize types returned by StructOf, et. al.

Message ID CAOyqgcW-KOF--yJG65S8_-ezhV29Fv8COnWDnc1YemtVmnoJVw@mail.gmail.com
State New
Headers show
Series
  • libgo patch committed: Canonicalize types returned by StructOf, et. al.
Related show

Commit Message

Ian Lance Taylor June 5, 2018, 8:23 p.m.
This libgo patch by Massimiliano Ghilardi changes the reflect package
to canonicalize types returned by StructOf() and friends.

Since gccgo does not currently merge identical types at link time, the
reflect function canonicalize() exists to choose a canonical specimen
for each set of identical types. In this way, user code has the
guarantee that identical types will always compare as ==.

This patch changes the functions MapOf, SliceOf, StructOf, etc., to
call canonicalize on the types they create, before storing the types
in internal lookup caches and returning them.

This fixes known cases where canonicalize is needed but was missing.
Supersedes https://golang.org/cl/112575 and mostly fixes
https://golang.org/issue/25284.

Ian

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 261203)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-8e74a218e11ef6eaaf7014a3ad1cd0b13359c607
+8b6c7f3f9762366bab96ea95b966e93e2593be13
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/go/reflect/all_test.go
===================================================================
--- libgo/go/reflect/all_test.go	(revision 261203)
+++ libgo/go/reflect/all_test.go	(working copy)
@@ -3928,8 +3928,8 @@  func TestOverflow(t *testing.T) {
 	}
 }
 
-func checkSameType(t *testing.T, x, y interface{}) {
-	if TypeOf(x) != TypeOf(y) {
+func checkSameType(t *testing.T, x Type, y interface{}) {
+	if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) {
 		t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))
 	}
 }
@@ -4058,7 +4058,7 @@  func TestArrayOf(t *testing.T) {
 
 	// check that type already in binary is found
 	type T int
-	checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
+	checkSameType(t, ArrayOf(5, TypeOf(T(1))), [5]T{})
 }
 
 func TestArrayOfGC(t *testing.T) {
@@ -4195,7 +4195,7 @@  func TestSliceOf(t *testing.T) {
 
 	// check that type already in binary is found
 	type T1 int
-	checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{})
+	checkSameType(t, SliceOf(TypeOf(T1(1))), []T1{})
 }
 
 func TestSliceOverflow(t *testing.T) {
@@ -4410,7 +4410,7 @@  func TestStructOf(t *testing.T) {
 		})
 	})
 	// check that type already in binary is found
-	checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{})
+	checkSameType(t, StructOf(fields[2:3]), struct{ Y uint64 }{})
 }
 
 func TestStructOfExportRules(t *testing.T) {
@@ -4963,7 +4963,7 @@  func TestChanOf(t *testing.T) {
 
 	// check that type already in binary is found
 	type T1 int
-	checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
+	checkSameType(t, ChanOf(BothDir, TypeOf(T1(1))), (chan T1)(nil))
 }
 
 func TestChanOfDir(t *testing.T) {
@@ -4974,8 +4974,8 @@  func TestChanOfDir(t *testing.T) {
 
 	// check that type already in binary is found
 	type T1 int
-	checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil))
-	checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil))
+	checkSameType(t, ChanOf(RecvDir, TypeOf(T1(1))), (<-chan T1)(nil))
+	checkSameType(t, ChanOf(SendDir, TypeOf(T1(1))), (chan<- T1)(nil))
 
 	// check String form of ChanDir
 	if crt.ChanDir().String() != "<-chan" {
@@ -5051,7 +5051,7 @@  func TestMapOf(t *testing.T) {
 	}
 
 	// check that type already in binary is found
-	checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil))
+	checkSameType(t, MapOf(TypeOf(V(0)), TypeOf(K(""))), map[V]K(nil))
 
 	// check that invalid key type panics
 	shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) })
@@ -5181,7 +5181,7 @@  func TestFuncOf(t *testing.T) {
 		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
 	}
 	for _, tt := range testCases {
-		checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want)
+		checkSameType(t, FuncOf(tt.in, tt.out, tt.variadic), tt.want)
 	}
 
 	// check that variadic requires last element be a slice.
Index: libgo/go/reflect/type.go
===================================================================
--- libgo/go/reflect/type.go	(revision 261203)
+++ libgo/go/reflect/type.go	(working copy)
@@ -1475,8 +1475,10 @@  func ChanOf(dir ChanDir, t Type) Type {
 	ch.uncommonType = nil
 	ch.ptrToThis = nil
 
-	ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
-	return ti.(Type)
+	// Canonicalize before storing in lookupCache
+	ti := toType(&ch.rtype)
+	lookupCache.Store(ckey, ti.(*rtype))
+	return ti
 }
 
 func ismapkey(*rtype) bool // implemented in runtime
@@ -1537,8 +1539,10 @@  func MapOf(key, elem Type) Type {
 	mt.reflexivekey = isReflexive(ktyp)
 	mt.needkeyupdate = needKeyUpdate(ktyp)
 
-	ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
-	return ti.(Type)
+	// Canonicalize before storing in lookupCache
+	ti := toType(&mt.rtype)
+	lookupCache.Store(ckey, ti.(*rtype))
+	return ti
 }
 
 // FuncOf returns the function type with the given argument and result types.
@@ -1621,7 +1625,10 @@  func FuncOf(in, out []Type, variadic boo
 	ft.string = &str
 	ft.uncommonType = nil
 	ft.ptrToThis = nil
-	return addToCache(&ft.rtype)
+
+	// Canonicalize before storing in funcLookupCache
+	tc := toType(&ft.rtype)
+	return addToCache(tc.(*rtype))
 }
 
 // funcStr builds a string representation of a funcType.
@@ -1855,8 +1862,10 @@  func SliceOf(t Type) Type {
 	slice.uncommonType = nil
 	slice.ptrToThis = nil
 
-	ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
-	return ti.(Type)
+	// Canonicalize before storing in lookupCache
+	ti := toType(&slice.rtype)
+	lookupCache.Store(ckey, ti.(*rtype))
+	return ti
 }
 
 // The structLookupCache caches StructOf lookups.
@@ -2172,7 +2181,9 @@  func StructOf(fields []StructField) Type
 	typ.uncommonType = nil
 	typ.ptrToThis = nil
 
-	return addToCache(&typ.rtype)
+	// Canonicalize before storing in structLookupCache
+	ti := toType(&typ.rtype)
+	return addToCache(ti.(*rtype))
 }
 
 func runtimeStructField(field StructField) structField {
@@ -2400,8 +2411,10 @@  func ArrayOf(count int, elem Type) Type
 		}
 	}
 
-	ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
-	return ti.(Type)
+	// Canonicalize before storing in lookupCache
+	ti := toType(&array.rtype)
+	lookupCache.Store(ckey, ti.(*rtype))
+	return ti
 }
 
 func appendVarint(x []byte, v uintptr) []byte {