reflect: canonicalize types returned by StructOf() and friends

Background: 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 ==

Change: arrange reflect 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 issue 25284.

Updates golang/go#25284

Change-Id: I5a71bf5ff4bbb2585a5b84072cb59af9e9d16518
Reviewed-on: https://go-review.googlesource.com/115577
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 3070aac..3378640 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -3928,8 +3928,8 @@
 	}
 }
 
-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 @@
 
 	// 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 @@
 
 	// 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 @@
 		})
 	})
 	// 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 @@
 
 	// 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 @@
 
 	// 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 @@
 	}
 
 	// 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 @@
 		{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.
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 6b082c1..458c456 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -1475,8 +1475,10 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		}
 	}
 
-	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 {