cmd/protoc-gen-go: add support for map fields

Generate the proper map[key]value type for map fields.
Include the protobuf_key and protobuf_val field tags.
Do not generate the map entry structs.

Fix an initialization order bug in protogen: While proto files cannot
contain circular dependencies, a single file can contain dependency
cycles. First create types for all the descriptors in a file, then add
in references (currently just field->message and field->enum) in a
second pass.

Change-Id: Ifedfa657d8dbb00413ba493adee1119b19c1b773
Reviewed-on: https://go-review.googlesource.com/135355
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/protogen/protogen.go b/protogen/protogen.go
index 5e1cd83..0064afa 100644
--- a/protogen/protogen.go
+++ b/protogen/protogen.go
@@ -400,6 +400,9 @@
 	for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
 		f.Enums = append(f.Enums, newEnum(gen, f, nil, edescs.Get(i)))
 	}
+	for _, message := range f.Messages {
+		message.init(gen)
+	}
 	return f, nil
 }
 
@@ -507,6 +510,20 @@
 	return message, nil
 }
 
+func (message *Message) init(gen *Plugin) error {
+	for _, child := range message.Messages {
+		if err := child.init(gen); err != nil {
+			return err
+		}
+	}
+	for _, field := range message.Fields {
+		if err := field.init(gen); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 // A Field describes a message field.
 type Field struct {
 	Desc protoreflect.FieldDescriptor
@@ -530,23 +547,28 @@
 		},
 		Path: pathAppend(message.Path, messageFieldField, int32(desc.Index())),
 	}
+	return field, nil
+}
+
+func (field *Field) init(gen *Plugin) error {
+	desc := field.Desc
 	switch desc.Kind() {
 	case protoreflect.MessageKind, protoreflect.GroupKind:
 		mname := desc.MessageType().FullName()
 		message, ok := gen.messagesByName[mname]
 		if !ok {
-			return nil, fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), mname)
+			return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), mname)
 		}
 		field.MessageType = message
 	case protoreflect.EnumKind:
-		ename := desc.EnumType().FullName()
+		ename := field.Desc.EnumType().FullName()
 		enum, ok := gen.enumsByName[ename]
 		if !ok {
-			return nil, fmt.Errorf("field %v: no descriptor for enum %v", desc.FullName(), ename)
+			return fmt.Errorf("field %v: no descriptor for enum %v", desc.FullName(), ename)
 		}
 		field.EnumType = enum
 	}
-	return field, nil
+	return nil
 }
 
 // An Enum describes an enum.