cmd/compile: cleanup algtype code

Add AlgKind enum type to represent AFOO values.

Add IsComparable, IsRegularMemory, IncomparableField helper methods to
codify common higher-level idioms.

Passes toolstash -cmp.

Change-Id: I54c544953997a8ccc72396b3058897edcbbea392
Reviewed-on: https://go-review.googlesource.com/21420
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index ae8af76..996bd6911 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -83,16 +83,17 @@
 			t = Types[TBOOL]
 		}
 		if t != nil {
-			var badtype *Type
 			switch {
 			case !okforeq[t.Etype]:
 				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
-			case t.Etype == TARRAY && !t.IsArray():
+			case t.IsSlice():
 				nilonly = "slice"
-			case t.Etype == TARRAY && t.IsArray() && algtype1(t, nil) == ANOEQ:
+			case t.IsArray() && !t.IsComparable():
 				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
-			case t.IsStruct() && algtype1(t, &badtype) == ANOEQ:
-				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), badtype)
+			case t.IsStruct():
+				if f := t.IncomparableField(); f != nil {
+					Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), f.Type)
+				}
 			case t.Etype == TFUNC:
 				nilonly = "func"
 			case t.IsMap():
@@ -139,7 +140,7 @@
 						}
 					case nilonly != "" && !isnil(n1):
 						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
-					case t.IsInterface() && !n1.Type.IsInterface() && algtype1(n1.Type, nil) == ANOEQ:
+					case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable():
 						Yyerror("invalid case %v in switch (incomparable type)", Nconv(n1, FmtLong))
 					}