reflect: make sure to clear unusable hash/equal function

Otherwise we wind up copying the one from the prototype, which is wrong.

Also rewrite the hash/equal functions to look like the ones in Go 1.8,
mainly a matter of changing names and using arrayAt.

Change-Id: I92f5c45efb53528d87124d04bef31bdb822f16f4
Reviewed-on: https://go-review.googlesource.com/41133
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 00349ba..905c867 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -2074,9 +2074,11 @@
 // This limitation may be lifted in a future version.
 func StructOf(fields []StructField) Type {
 	var (
-		hash     = uint32(0)
-		size     uintptr
-		typalign int8
+		hash       = uint32(0)
+		size       uintptr
+		typalign   int8
+		comparable = true
+		hashable   = true
 
 		fs   = make([]structField, len(fields))
 		repr = make([]byte, 0, 64)
@@ -2157,6 +2159,9 @@
 			repr = append(repr, ';')
 		}
 
+		comparable = comparable && (ft.equalfn != nil)
+		hashable = hashable && (ft.hashfn != nil)
+
 		f.offset = align(size, uintptr(ft.fieldAlign))
 		if int8(ft.fieldAlign) > typalign {
 			typalign = int8(ft.fieldAlign)
@@ -2241,24 +2246,32 @@
 		typ.gcdata = (*byte)(unsafe.Pointer(&gc[0]))
 	}
 
-	typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
-		ret := seed
-		for _, ft := range typ.fields {
-			o := unsafe.Pointer(uintptr(p) + ft.offset)
-			ret = ft.typ.hashfn(o, ret)
+	if hashable {
+		typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
+			o := seed
+			for _, ft := range typ.fields {
+				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				o = ft.typ.hashfn(pi, o)
+			}
+			return o
 		}
-		return ret
+	} else {
+		typ.hashfn = nil
 	}
 
-	typ.equalfn = func(p, q unsafe.Pointer) bool {
-		for _, ft := range typ.fields {
-			pi := unsafe.Pointer(uintptr(p) + ft.offset)
-			qi := unsafe.Pointer(uintptr(q) + ft.offset)
-			if !ft.typ.equalfn(pi, qi) {
-				return false
+	if comparable {
+		typ.equalfn = func(p, q unsafe.Pointer) bool {
+			for _, ft := range typ.fields {
+				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				qi := unsafe.Pointer(uintptr(q) + ft.offset)
+				if !ft.typ.equalfn(pi, qi) {
+					return false
+				}
 			}
+			return true
 		}
-		return true
+	} else {
+		typ.equalfn = nil
 	}
 
 	typ.kind &^= kindDirectIface
@@ -2382,24 +2395,35 @@
 
 	array.kind &^= kindDirectIface
 
-	array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
-		ret := seed
-		for i := 0; i < count; i++ {
-			ret = typ.hashfn(p, ret)
-			p = unsafe.Pointer(uintptr(p) + typ.size)
+	esize := typ.size
+
+	if typ.equalfn == nil {
+		array.equalfn = nil
+	} else {
+		eequal := typ.equalfn
+		array.equalfn = func(p, q unsafe.Pointer) bool {
+			for i := 0; i < count; i++ {
+				pi := arrayAt(p, i, esize)
+				qi := arrayAt(q, i, esize)
+				if !eequal(pi, qi) {
+					return false
+				}
+			}
+			return true
 		}
-		return ret
 	}
 
-	array.equalfn = func(p1, p2 unsafe.Pointer) bool {
-		for i := 0; i < count; i++ {
-			if !typ.equalfn(p1, p2) {
-				return false
+	if typ.hashfn == nil {
+		array.hashfn = nil
+	} else {
+		ehash := typ.hashfn
+		array.hashfn = func(ptr unsafe.Pointer, seed uintptr) uintptr {
+			o := seed
+			for i := 0; i < count; i++ {
+				o = ehash(arrayAt(ptr, i, esize), o)
 			}
-			p1 = unsafe.Pointer(uintptr(p1) + typ.size)
-			p2 = unsafe.Pointer(uintptr(p2) + typ.size)
+			return o
 		}
-		return true
 	}
 
 	return cachePut(ckey, &array.rtype)