x/mobile/bind: forward declare protocol/class for interface types

Fixes golang/go#13004

Change-Id: I114cf3d7d970485d0609b1d7b497e232010e64df
Reviewed-on: https://go-review.googlesource.com/16155
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/bind/genobjc.go b/bind/genobjc.go
index 73f84d2..d586dc0 100644
--- a/bind/genobjc.go
+++ b/bind/genobjc.go
@@ -34,16 +34,34 @@
 	pkgName    string
 	namePrefix string
 	funcs      []*types.Func
-	names      []*types.TypeName
 	constants  []*types.Const
 	vars       []*types.Var
+
+	interfaces []interfaceInfo
+	structs    []structInfo
+	otherNames []*types.TypeName
+}
+
+type interfaceInfo struct {
+	obj     *types.TypeName
+	t       *types.Interface
+	summary ifaceSummary
+}
+
+type structInfo struct {
+	obj *types.TypeName
+	t   *types.Struct
 }
 
 func (g *objcGen) init() {
 	g.pkgName = g.pkg.Name()
 	g.namePrefix = g.prefix + strings.Title(g.pkgName)
 	g.funcs = nil
-	g.names = nil
+	g.constants = nil
+	g.vars = nil
+	g.interfaces = nil
+	g.structs = nil
+	g.otherNames = nil
 
 	scope := g.pkg.Scope()
 	hasExported := false
@@ -59,7 +77,15 @@
 				g.funcs = append(g.funcs, obj)
 			}
 		case *types.TypeName:
-			g.names = append(g.names, obj)
+			named := obj.Type().(*types.Named)
+			switch t := named.Underlying().(type) {
+			case *types.Struct:
+				g.structs = append(g.structs, structInfo{obj, t})
+			case *types.Interface:
+				g.interfaces = append(g.interfaces, interfaceInfo{obj, t, makeIfaceSummary(t)})
+			default:
+				g.otherNames = append(g.otherNames, obj)
+			}
 		case *types.Const:
 			if _, ok := obj.Type().(*types.Basic); !ok {
 				g.errorf("unsupported exported const for %s: %T", obj.Name(), obj)
@@ -91,33 +117,32 @@
 	g.Printf("#ifndef __%s%s_H__\n", g.prefix, strings.Title(g.pkgName))
 	g.Printf("#define __%s%s_H__\n", g.prefix, strings.Title(g.pkgName))
 	g.Printf("\n")
-	g.Printf("#include <Foundation/Foundation.h>")
-	g.Printf("\n\n")
+	g.Printf("#include <Foundation/Foundation.h>\n")
+	g.Printf("\n")
 
-	// @class names
-	for _, obj := range g.names {
-		named := obj.Type().(*types.Named)
-		switch t := named.Underlying().(type) {
-		case *types.Struct:
-			g.Printf("@class %s%s;\n\n", g.namePrefix, obj.Name())
-		case *types.Interface:
-			if !makeIfaceSummary(t).implementable {
-				g.Printf("@class %s%s;\n\n", g.namePrefix, obj.Name())
-			}
+	// Forward declaration of @class and @protocol
+	for _, s := range g.structs {
+		g.Printf("@class %s%s;\n", g.namePrefix, s.obj.Name())
+	}
+	for _, i := range g.interfaces {
+		g.Printf("@protocol %s%s;\n", g.namePrefix, i.obj.Name())
+		if i.summary.implementable {
+			g.Printf("@class %s%s;\n", g.namePrefix, i.obj.Name())
+			// Forward declaration for other cases will be handled at the beginning of genM.
 		}
 	}
+	if len(g.structs) > 0 || len(g.interfaces) > 0 {
+		g.Printf("\n")
+	}
 
 	// @interfaces
-	for _, obj := range g.names {
-		named := obj.Type().(*types.Named)
-		switch t := named.Underlying().(type) {
-		case *types.Struct:
-			g.genStructH(obj, t)
-			g.Printf("\n")
-		case *types.Interface:
-			g.genInterfaceH(obj, t)
-			g.Printf("\n")
-		}
+	for _, s := range g.structs {
+		g.genStructH(s.obj, s.t)
+		g.Printf("\n")
+	}
+	for _, i := range g.interfaces {
+		g.genInterfaceH(i.obj, i.t)
+		g.Printf("\n")
 	}
 
 	// const
@@ -186,22 +211,32 @@
 	g.Printf("\n")
 
 	g.Printf("#define _DESCRIPTOR_ %q\n\n", g.pkgName)
-	for i, obj := range g.funcs {
-		g.Printf("#define _CALL_%s_ %d\n", obj.Name(), i+1)
-	}
-	g.Printf("\n")
 
-	// struct, interface.
-	var interfaces []*types.TypeName
-	for _, obj := range g.names {
-		named := obj.Type().(*types.Named)
-		switch t := named.Underlying().(type) {
-		case *types.Struct:
-			g.genStructM(obj, t)
-		case *types.Interface:
-			if g.genInterfaceM(obj, t) {
-				interfaces = append(interfaces, obj)
-			}
+	// forward declarations skipped from genH
+	for _, i := range g.interfaces {
+		if i.summary.implementable {
+			g.Printf("@class %s%s;\n\n", g.namePrefix, i.obj.Name())
+		}
+	}
+	for _, i := range g.interfaces {
+		if i.summary.implementable {
+			// @interface Interface -- similar to what genStructH does.
+			g.genInterfaceInterface(i.obj, i.summary, true)
+			g.Printf("\n")
+		}
+	}
+
+	// struct
+	for _, s := range g.structs {
+		g.genStructM(s.obj, s.t)
+		g.Printf("\n")
+	}
+
+	// interface
+	var needProxy []*types.TypeName
+	for _, i := range g.interfaces {
+		if g.genInterfaceM(i.obj, i.t) {
+			needProxy = append(needProxy, i.obj)
 		}
 		g.Printf("\n")
 	}
@@ -224,16 +259,22 @@
 	}
 
 	// global functions.
+	for i, obj := range g.funcs {
+		g.Printf("#define _CALL_%s_ %d\n", obj.Name(), i+1)
+	}
+
+	g.Printf("\n")
+
 	for _, obj := range g.funcs {
 		g.genFuncM(obj)
 		g.Printf("\n")
 	}
 
 	// register proxy functions.
-	if len(interfaces) > 0 {
+	if len(needProxy) > 0 {
 		g.Printf("__attribute__((constructor)) static void init() {\n")
 		g.Indent()
-		for _, obj := range interfaces {
+		for _, obj := range needProxy {
 			g.Printf("go_seq_register_proxy(\"go.%s.%s\", proxy%s%s);\n", g.pkgName, obj.Name(), g.namePrefix, obj.Name())
 		}
 		g.Outdent()
@@ -616,7 +657,6 @@
 		g.Printf("- %s;\n", s.asMethod(g))
 	}
 	g.Printf("@end\n")
-	g.Printf("\n")
 }
 
 func (g *objcGen) genInterfaceH(obj *types.TypeName, t *types.Interface) {
@@ -643,11 +683,6 @@
 	}
 	g.Printf("\n")
 
-	if summary.implementable {
-		// @interface Interface -- similar to what genStructH does.
-		g.genInterfaceInterface(obj, summary, true)
-	}
-
 	// @implementation Interface -- similar to what genStructM does.
 	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
 	g.Printf("}\n")
diff --git a/bind/objc/testpkg/go_testpkg/go_testpkg.go b/bind/objc/testpkg/go_testpkg/go_testpkg.go
index d6d3dbf..577513a 100644
--- a/bind/objc/testpkg/go_testpkg/go_testpkg.go
+++ b/bind/objc/testpkg/go_testpkg/go_testpkg.go
@@ -339,6 +339,38 @@
 func var_getStringVar(out, in *seq.Buffer) {
 	out.WriteString(testpkg.StringVar)
 }
+
+const (
+	proxyStructThatStartsWithLetterBeforeZ_Descriptor     = "go.testpkg.StructThatStartsWithLetterBeforeZ"
+	proxyStructThatStartsWithLetterBeforeZ_Value_Get_Code = 0x00f
+	proxyStructThatStartsWithLetterBeforeZ_Value_Set_Code = 0x01f
+)
+
+type proxyStructThatStartsWithLetterBeforeZ seq.Ref
+
+func proxyStructThatStartsWithLetterBeforeZ_Value_Set(out, in *seq.Buffer) {
+	ref := in.ReadRef()
+	var v testpkg.Z
+	v_ref := in.ReadRef()
+	if v_ref.Num < 0 { // go object
+		v = v_ref.Get().(testpkg.Z)
+	} else { // foreign object
+		v = (*proxyZ)(v_ref)
+	}
+	ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value = v
+}
+
+func proxyStructThatStartsWithLetterBeforeZ_Value_Get(out, in *seq.Buffer) {
+	ref := in.ReadRef()
+	v := ref.Get().(*testpkg.StructThatStartsWithLetterBeforeZ).Value
+	out.WriteGoRef(v)
+}
+
+func init() {
+	seq.Register(proxyStructThatStartsWithLetterBeforeZ_Descriptor, proxyStructThatStartsWithLetterBeforeZ_Value_Set_Code, proxyStructThatStartsWithLetterBeforeZ_Value_Set)
+	seq.Register(proxyStructThatStartsWithLetterBeforeZ_Descriptor, proxyStructThatStartsWithLetterBeforeZ_Value_Get_Code, proxyStructThatStartsWithLetterBeforeZ_Value_Get)
+}
+
 func var_setStructVar(out, in *seq.Buffer) {
 	// Must be a Go object
 	v_ref := in.ReadRef()
@@ -360,6 +392,12 @@
 	testpkg.UnregisterI(param_idx)
 }
 
+const (
+	proxyZ_Descriptor = "go.testpkg.Z"
+)
+
+type proxyZ seq.Ref
+
 func init() {
 	seq.Register("testpkg", 1, proxy_BytesAppend)
 	seq.Register("testpkg", 2, proxy_CallIError)
diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h b/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
index 9646611..542e11a 100644
--- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
+++ b/bind/objc/testpkg/objc_testpkg/GoTestpkg.h
@@ -9,14 +9,12 @@
 #include <Foundation/Foundation.h>
 
 @class GoTestpkgNode;
-
 @class GoTestpkgS;
-
-@protocol GoTestpkgI
-- (BOOL)error:(BOOL)triggerError error:(NSError**)error;
-- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error;
-- (int64_t)times:(int32_t)v;
-@end
+@class GoTestpkgStructThatStartsWithLetterBeforeZ;
+@protocol GoTestpkgI;
+@class GoTestpkgI;
+@protocol GoTestpkgZ;
+@class GoTestpkgZ;
 
 @interface GoTestpkgNode : NSObject {
 }
@@ -42,6 +40,24 @@
 - (NSString*)tryTwoStrings:(NSString*)first second:(NSString*)second;
 @end
 
+@interface GoTestpkgStructThatStartsWithLetterBeforeZ : NSObject {
+}
+@property(strong, readonly) id _ref;
+
+- (id)initWithRef:(id)ref;
+- (id<GoTestpkgZ>)value;
+- (void)setValue:(id<GoTestpkgZ>)v;
+@end
+
+@protocol GoTestpkgI
+- (BOOL)error:(BOOL)triggerError error:(NSError**)error;
+- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error;
+- (int64_t)times:(int32_t)v;
+@end
+
+@protocol GoTestpkgZ
+@end
+
 FOUNDATION_EXPORT const BOOL GoTestpkgABool;
 FOUNDATION_EXPORT const double GoTestpkgAFloat;
 FOUNDATION_EXPORT NSString* const GoTestpkgAString;
diff --git a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m b/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
index 81e56f0..aa8980e 100644
--- a/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
+++ b/bind/objc/testpkg/objc_testpkg/GoTestpkg.m
@@ -15,28 +15,9 @@
 
 #define _DESCRIPTOR_ "testpkg"
 
-#define _CALL_BytesAppend_ 1
-#define _CALL_CallIError_ 2
-#define _CALL_CallIStringError_ 3
-#define _CALL_CallSSum_ 4
-#define _CALL_CollectS_ 5
-#define _CALL_GC_ 6
-#define _CALL_Hello_ 7
-#define _CALL_Hi_ 8
-#define _CALL_Int_ 9
-#define _CALL_Multiply_ 10
-#define _CALL_NewI_ 11
-#define _CALL_NewNode_ 12
-#define _CALL_NewS_ 13
-#define _CALL_RegisterI_ 14
-#define _CALL_ReturnsError_ 15
-#define _CALL_Sum_ 16
-#define _CALL_UnregisterI_ 17
+@class GoTestpkgI;
 
-#define _GO_testpkg_I_DESCRIPTOR_ "go.testpkg.I"
-#define _GO_testpkg_I_Error_ (0x10a)
-#define _GO_testpkg_I_StringError_ (0x20a)
-#define _GO_testpkg_I_Times_ (0x30a)
+@class GoTestpkgZ;
 
 @interface GoTestpkgI : NSObject <GoTestpkgI> {
 }
@@ -48,112 +29,13 @@
 - (int64_t)times:(int32_t)v;
 @end
 
-@implementation GoTestpkgI {
+@interface GoTestpkgZ : NSObject <GoTestpkgZ> {
 }
+@property(strong, readonly) id _ref;
 
-- (id)initWithRef:(id)ref {
-	self = [super init];
-	if (self) { __ref = ref; }
-	return self;
-}
-
-- (BOOL)error:(BOOL)triggerError error:(NSError**)error {
-	GoSeq in_ = {};
-	GoSeq out_ = {};
-	go_seq_writeRef(&in_, self._ref);
-	go_seq_writeBool(&in_, triggerError);
-	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Error_, &in_, &out_);
-	NSString* _error = go_seq_readUTF8(&out_);
-	if ([_error length] != 0 && error != nil) {
-		NSMutableDictionary* details = [NSMutableDictionary dictionary];
-		[details setValue:_error forKey:NSLocalizedDescriptionKey];
-		*error = [NSError errorWithDomain:errDomain code:1 userInfo:details];
-	}
-	go_seq_free(&in_);
-	go_seq_free(&out_);
-	return ([_error length] == 0);
-}
-
-- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error {
-	GoSeq in_ = {};
-	GoSeq out_ = {};
-	go_seq_writeRef(&in_, self._ref);
-	go_seq_writeUTF8(&in_, s);
-	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_StringError_, &in_, &out_);
-	NSString* ret0__val = go_seq_readUTF8(&out_);
-	if (ret0_ != NULL) {
-		*ret0_ = ret0__val;
-	}
-	NSString* _error = go_seq_readUTF8(&out_);
-	if ([_error length] != 0 && error != nil) {
-		NSMutableDictionary* details = [NSMutableDictionary dictionary];
-		[details setValue:_error forKey:NSLocalizedDescriptionKey];
-		*error = [NSError errorWithDomain:errDomain code:1 userInfo:details];
-	}
-	go_seq_free(&in_);
-	go_seq_free(&out_);
-	return ([_error length] == 0);
-}
-
-- (int64_t)times:(int32_t)v {
-	GoSeq in_ = {};
-	GoSeq out_ = {};
-	go_seq_writeRef(&in_, self._ref);
-	go_seq_writeInt32(&in_, v);
-	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Times_, &in_, &out_);
-	int64_t ret0_ = go_seq_readInt64(&out_);
-	go_seq_free(&in_);
-	go_seq_free(&out_);
-	return ret0_;
-}
-
+- (id)initWithRef:(id)ref;
 @end
 
-static void proxyGoTestpkgI(id obj, int code, GoSeq* in, GoSeq* out) {
-	switch (code) {
-	case _GO_testpkg_I_Error_: {
-		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
-		BOOL triggerError = go_seq_readBool(in);
-		NSError* error = NULL;
-		BOOL returnVal = [o error:triggerError error:&error];
-		if (returnVal) {
-			go_seq_writeUTF8(out, NULL);
-		} else {
-			NSString* errorDesc = [error localizedDescription];
-			if (errorDesc == NULL || errorDesc.length == 0) {
-				errorDesc = @"gobind: unknown error";
-			}
-			go_seq_writeUTF8(out, errorDesc);
-		}
-	} break;
-	case _GO_testpkg_I_StringError_: {
-		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
-		NSString* s = go_seq_readUTF8(in);
-		NSString* ret0_;
-		NSError* error = NULL;
-		BOOL returnVal = [o stringError:s ret0_:&ret0_ error:&error];
-		go_seq_writeUTF8(out, ret0_);
-		if (returnVal) {
-			go_seq_writeUTF8(out, NULL);
-		} else {
-			NSString* errorDesc = [error localizedDescription];
-			if (errorDesc == NULL || errorDesc.length == 0) {
-				errorDesc = @"gobind: unknown error";
-			}
-			go_seq_writeUTF8(out, errorDesc);
-		}
-	} break;
-	case _GO_testpkg_I_Times_: {
-		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
-		int32_t v = go_seq_readInt32(in);
-		int64_t returnVal = [o times:v];
-		go_seq_writeInt64(out, returnVal);
-	} break;
-	default:
-		NSLog(@"unknown code %x for _GO_testpkg_I_DESCRIPTOR_", code);
-	}
-}
-
 #define _GO_testpkg_Node_DESCRIPTOR_ "go.testpkg.Node"
 #define _GO_testpkg_Node_FIELD_V_GET_ (0x00f)
 #define _GO_testpkg_Node_FIELD_V_SET_ (0x01f)
@@ -298,6 +180,182 @@
 
 @end
 
+#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_ "go.testpkg.StructThatStartsWithLetterBeforeZ"
+#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_GET_ (0x00f)
+#define _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_SET_ (0x01f)
+
+@implementation GoTestpkgStructThatStartsWithLetterBeforeZ {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+- (id<GoTestpkgZ>)value {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_send(_GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_, _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_GET_, &in_, &out_);
+	GoSeqRef* ret__ref = go_seq_readRef(&out_);
+	id<GoTestpkgZ> ret_ = ret__ref.obj;
+	if (ret_ == NULL) {
+		ret_ = [[GoTestpkgZ alloc] initWithRef:ret__ref];
+	}
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret_;
+}
+
+- (void)setValue:(id<GoTestpkgZ>)v {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	if ([(id<NSObject>)(v) isKindOfClass:[GoTestpkgZ class]]) {
+		id<goSeqRefInterface> v_proxy = (id<goSeqRefInterface>)(v);
+		go_seq_writeRef(&in_, v_proxy._ref);
+	} else {
+		go_seq_writeObjcRef(&in_, v);
+	}
+	go_seq_send(_GO_testpkg_StructThatStartsWithLetterBeforeZ_DESCRIPTOR_, _GO_testpkg_StructThatStartsWithLetterBeforeZ_FIELD_Value_SET_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+@end
+
+#define _GO_testpkg_I_DESCRIPTOR_ "go.testpkg.I"
+#define _GO_testpkg_I_Error_ (0x10a)
+#define _GO_testpkg_I_StringError_ (0x20a)
+#define _GO_testpkg_I_Times_ (0x30a)
+
+@implementation GoTestpkgI {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+- (BOOL)error:(BOOL)triggerError error:(NSError**)error {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_writeBool(&in_, triggerError);
+	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Error_, &in_, &out_);
+	NSString* _error = go_seq_readUTF8(&out_);
+	if ([_error length] != 0 && error != nil) {
+		NSMutableDictionary* details = [NSMutableDictionary dictionary];
+		[details setValue:_error forKey:NSLocalizedDescriptionKey];
+		*error = [NSError errorWithDomain:errDomain code:1 userInfo:details];
+	}
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ([_error length] == 0);
+}
+
+- (BOOL)stringError:(NSString*)s ret0_:(NSString**)ret0_ error:(NSError**)error {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_writeUTF8(&in_, s);
+	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_StringError_, &in_, &out_);
+	NSString* ret0__val = go_seq_readUTF8(&out_);
+	if (ret0_ != NULL) {
+		*ret0_ = ret0__val;
+	}
+	NSString* _error = go_seq_readUTF8(&out_);
+	if ([_error length] != 0 && error != nil) {
+		NSMutableDictionary* details = [NSMutableDictionary dictionary];
+		[details setValue:_error forKey:NSLocalizedDescriptionKey];
+		*error = [NSError errorWithDomain:errDomain code:1 userInfo:details];
+	}
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ([_error length] == 0);
+}
+
+- (int64_t)times:(int32_t)v {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_writeInt32(&in_, v);
+	go_seq_send(_GO_testpkg_I_DESCRIPTOR_, _GO_testpkg_I_Times_, &in_, &out_);
+	int64_t ret0_ = go_seq_readInt64(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret0_;
+}
+
+@end
+
+static void proxyGoTestpkgI(id obj, int code, GoSeq* in, GoSeq* out) {
+	switch (code) {
+	case _GO_testpkg_I_Error_: {
+		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
+		BOOL triggerError = go_seq_readBool(in);
+		NSError* error = NULL;
+		BOOL returnVal = [o error:triggerError error:&error];
+		if (returnVal) {
+			go_seq_writeUTF8(out, NULL);
+		} else {
+			NSString* errorDesc = [error localizedDescription];
+			if (errorDesc == NULL || errorDesc.length == 0) {
+				errorDesc = @"gobind: unknown error";
+			}
+			go_seq_writeUTF8(out, errorDesc);
+		}
+	} break;
+	case _GO_testpkg_I_StringError_: {
+		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
+		NSString* s = go_seq_readUTF8(in);
+		NSString* ret0_;
+		NSError* error = NULL;
+		BOOL returnVal = [o stringError:s ret0_:&ret0_ error:&error];
+		go_seq_writeUTF8(out, ret0_);
+		if (returnVal) {
+			go_seq_writeUTF8(out, NULL);
+		} else {
+			NSString* errorDesc = [error localizedDescription];
+			if (errorDesc == NULL || errorDesc.length == 0) {
+				errorDesc = @"gobind: unknown error";
+			}
+			go_seq_writeUTF8(out, errorDesc);
+		}
+	} break;
+	case _GO_testpkg_I_Times_: {
+		id<GoTestpkgI> o = (id<GoTestpkgI>)(obj);
+		int32_t v = go_seq_readInt32(in);
+		int64_t returnVal = [o times:v];
+		go_seq_writeInt64(out, returnVal);
+	} break;
+	default:
+		NSLog(@"unknown code %x for _GO_testpkg_I_DESCRIPTOR_", code);
+	}
+}
+
+#define _GO_testpkg_Z_DESCRIPTOR_ "go.testpkg.Z"
+
+@implementation GoTestpkgZ {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+@end
+
+static void proxyGoTestpkgZ(id obj, int code, GoSeq* in, GoSeq* out) {
+	switch (code) {
+	default:
+		NSLog(@"unknown code %x for _GO_testpkg_Z_DESCRIPTOR_", code);
+	}
+}
+
 const BOOL GoTestpkgABool = YES;
 const double GoTestpkgAFloat = 0.12345;
 NSString* const GoTestpkgAString = @"a string";
@@ -409,6 +467,24 @@
 
 @end
 
+#define _CALL_BytesAppend_ 1
+#define _CALL_CallIError_ 2
+#define _CALL_CallIStringError_ 3
+#define _CALL_CallSSum_ 4
+#define _CALL_CollectS_ 5
+#define _CALL_GC_ 6
+#define _CALL_Hello_ 7
+#define _CALL_Hi_ 8
+#define _CALL_Int_ 9
+#define _CALL_Multiply_ 10
+#define _CALL_NewI_ 11
+#define _CALL_NewNode_ 12
+#define _CALL_NewS_ 13
+#define _CALL_RegisterI_ 14
+#define _CALL_ReturnsError_ 15
+#define _CALL_Sum_ 16
+#define _CALL_UnregisterI_ 17
+
 NSData* GoTestpkgBytesAppend(NSData* a, NSData* b) {
 	GoSeq in_ = {};
 	GoSeq out_ = {};
@@ -648,4 +724,5 @@
 
 __attribute__((constructor)) static void init() {
 	go_seq_register_proxy("go.testpkg.I", proxyGoTestpkgI);
+	go_seq_register_proxy("go.testpkg.Z", proxyGoTestpkgZ);
 }
diff --git a/bind/objc/testpkg/testpkg.go b/bind/objc/testpkg/testpkg.go
index 2a152c8..8d69073 100644
--- a/bind/objc/testpkg/testpkg.go
+++ b/bind/objc/testpkg/testpkg.go
@@ -178,3 +178,11 @@
 func NewNode(name string) *Node {
 	return &Node{V: name}
 }
+
+// issue 13004
+type StructThatStartsWithLetterBeforeZ struct {
+	Value Z
+}
+
+type Z interface {
+}
diff --git a/bind/testdata/basictypes.objc.m.golden b/bind/testdata/basictypes.objc.m.golden
index adc275c..959e5c9 100644
--- a/bind/testdata/basictypes.objc.m.golden
+++ b/bind/testdata/basictypes.objc.m.golden
@@ -15,12 +15,6 @@
 
 #define _DESCRIPTOR_ "basictypes"
 
-#define _CALL_Bool_ 1
-#define _CALL_ByteArrays_ 2
-#define _CALL_Error_ 3
-#define _CALL_ErrorPair_ 4
-#define _CALL_Ints_ 5
-
 const BOOL GoBasictypesABool = YES;
 const double GoBasictypesAFloat = 0.2015;
 const int32_t GoBasictypesARune = 32;
@@ -28,6 +22,12 @@
 const int64_t GoBasictypesAnInt = 7LL;
 const int64_t GoBasictypesAnInt2 = 9223372036854775807LL;
 
+#define _CALL_Bool_ 1
+#define _CALL_ByteArrays_ 2
+#define _CALL_Error_ 3
+#define _CALL_ErrorPair_ 4
+#define _CALL_Ints_ 5
+
 BOOL GoBasictypesBool(BOOL p0) {
 	GoSeq in_ = {};
 	GoSeq out_ = {};
diff --git a/bind/testdata/interfaces.objc.h.golden b/bind/testdata/interfaces.objc.h.golden
index 6454b96..bdf25ea 100644
--- a/bind/testdata/interfaces.objc.h.golden
+++ b/bind/testdata/interfaces.objc.h.golden
@@ -8,9 +8,16 @@
 
 #include <Foundation/Foundation.h>
 
-@class GoInterfacesI1;
-
-@class GoInterfacesI2;
+@protocol GoInterfacesError;
+@class GoInterfacesError;
+@protocol GoInterfacesI;
+@class GoInterfacesI;
+@protocol GoInterfacesI1;
+@protocol GoInterfacesI2;
+@protocol GoInterfacesI3;
+@class GoInterfacesI3;
+@protocol GoInterfacesWithParam;
+@class GoInterfacesWithParam;
 
 @protocol GoInterfacesError
 - (BOOL)err:(NSError**)error;
@@ -28,7 +35,6 @@
 - (void)j;
 @end
 
-
 @interface GoInterfacesI2 : NSObject {
 }
 @property(strong, readonly) id _ref;
@@ -37,7 +43,6 @@
 - (void)g;
 @end
 
-
 @protocol GoInterfacesI3
 - (GoInterfacesI1*)f;
 @end
diff --git a/bind/testdata/interfaces.objc.m.golden b/bind/testdata/interfaces.objc.m.golden
index 70e8901..7719a88 100644
--- a/bind/testdata/interfaces.objc.m.golden
+++ b/bind/testdata/interfaces.objc.m.golden
@@ -15,12 +15,13 @@
 
 #define _DESCRIPTOR_ "interfaces"
 
-#define _CALL_Add3_ 1
-#define _CALL_CallErr_ 2
-#define _CALL_Seven_ 3
+@class GoInterfacesError;
 
-#define _GO_interfaces_Error_DESCRIPTOR_ "go.interfaces.Error"
-#define _GO_interfaces_Error_Err_ (0x10a)
+@class GoInterfacesI;
+
+@class GoInterfacesI3;
+
+@class GoInterfacesWithParam;
 
 @interface GoInterfacesError : NSObject <GoInterfacesError> {
 }
@@ -30,6 +31,33 @@
 - (BOOL)err:(NSError**)error;
 @end
 
+@interface GoInterfacesI : NSObject <GoInterfacesI> {
+}
+@property(strong, readonly) id _ref;
+
+- (id)initWithRef:(id)ref;
+- (int32_t)rand;
+@end
+
+@interface GoInterfacesI3 : NSObject <GoInterfacesI3> {
+}
+@property(strong, readonly) id _ref;
+
+- (id)initWithRef:(id)ref;
+- (GoInterfacesI1*)f;
+@end
+
+@interface GoInterfacesWithParam : NSObject <GoInterfacesWithParam> {
+}
+@property(strong, readonly) id _ref;
+
+- (id)initWithRef:(id)ref;
+- (void)hasParam:(BOOL)p0;
+@end
+
+#define _GO_interfaces_Error_DESCRIPTOR_ "go.interfaces.Error"
+#define _GO_interfaces_Error_Err_ (0x10a)
+
 @implementation GoInterfacesError {
 }
 
@@ -81,14 +109,6 @@
 #define _GO_interfaces_I_DESCRIPTOR_ "go.interfaces.I"
 #define _GO_interfaces_I_Rand_ (0x10a)
 
-@interface GoInterfacesI : NSObject <GoInterfacesI> {
-}
-@property(strong, readonly) id _ref;
-
-- (id)initWithRef:(id)ref;
-- (int32_t)rand;
-@end
-
 @implementation GoInterfacesI {
 }
 
@@ -174,14 +194,6 @@
 #define _GO_interfaces_I3_DESCRIPTOR_ "go.interfaces.I3"
 #define _GO_interfaces_I3_F_ (0x10a)
 
-@interface GoInterfacesI3 : NSObject <GoInterfacesI3> {
-}
-@property(strong, readonly) id _ref;
-
-- (id)initWithRef:(id)ref;
-- (GoInterfacesI1*)f;
-@end
-
 @implementation GoInterfacesI3 {
 }
 
@@ -228,14 +240,6 @@
 #define _GO_interfaces_WithParam_DESCRIPTOR_ "go.interfaces.WithParam"
 #define _GO_interfaces_WithParam_HasParam_ (0x10a)
 
-@interface GoInterfacesWithParam : NSObject <GoInterfacesWithParam> {
-}
-@property(strong, readonly) id _ref;
-
-- (id)initWithRef:(id)ref;
-- (void)hasParam:(BOOL)p0;
-@end
-
 @implementation GoInterfacesWithParam {
 }
 
@@ -269,6 +273,10 @@
 	}
 }
 
+#define _CALL_Add3_ 1
+#define _CALL_CallErr_ 2
+#define _CALL_Seven_ 3
+
 int32_t GoInterfacesAdd3(id<GoInterfacesI> r) {
 	GoSeq in_ = {};
 	GoSeq out_ = {};
diff --git a/bind/testdata/issue10788.objc.h.golden b/bind/testdata/issue10788.objc.h.golden
index ce2129a..eea9159 100644
--- a/bind/testdata/issue10788.objc.h.golden
+++ b/bind/testdata/issue10788.objc.h.golden
@@ -9,11 +9,8 @@
 #include <Foundation/Foundation.h>
 
 @class GoIssue10788TestStruct;
-
-@protocol GoIssue10788TestInterface
-- (void)doSomeWork:(GoIssue10788TestStruct*)s;
-- (void)multipleUnnamedParams:(int)p0 p1:(NSString*)p1 p2:(int64_t)p2;
-@end
+@protocol GoIssue10788TestInterface;
+@class GoIssue10788TestInterface;
 
 @interface GoIssue10788TestStruct : NSObject {
 }
@@ -24,4 +21,9 @@
 - (void)setValue:(NSString*)v;
 @end
 
+@protocol GoIssue10788TestInterface
+- (void)doSomeWork:(GoIssue10788TestStruct*)s;
+- (void)multipleUnnamedParams:(int)p0 p1:(NSString*)p1 p2:(int64_t)p2;
+@end
+
 #endif
diff --git a/bind/testdata/issue10788.objc.m.golden b/bind/testdata/issue10788.objc.m.golden
index e8e6a56..53ce9b7 100644
--- a/bind/testdata/issue10788.objc.m.golden
+++ b/bind/testdata/issue10788.objc.m.golden
@@ -15,10 +15,7 @@
 
 #define _DESCRIPTOR_ "issue10788"
 
-
-#define _GO_issue10788_TestInterface_DESCRIPTOR_ "go.issue10788.TestInterface"
-#define _GO_issue10788_TestInterface_DoSomeWork_ (0x10a)
-#define _GO_issue10788_TestInterface_MultipleUnnamedParams_ (0x20a)
+@class GoIssue10788TestInterface;
 
 @interface GoIssue10788TestInterface : NSObject <GoIssue10788TestInterface> {
 }
@@ -29,6 +26,46 @@
 - (void)multipleUnnamedParams:(int)p0 p1:(NSString*)p1 p2:(int64_t)p2;
 @end
 
+#define _GO_issue10788_TestStruct_DESCRIPTOR_ "go.issue10788.TestStruct"
+#define _GO_issue10788_TestStruct_FIELD_Value_GET_ (0x00f)
+#define _GO_issue10788_TestStruct_FIELD_Value_SET_ (0x01f)
+
+@implementation GoIssue10788TestStruct {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+- (NSString*)value {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_GET_, &in_, &out_);
+	NSString* ret_ = go_seq_readUTF8(&out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+	return ret_;
+}
+
+- (void)setValue:(NSString*)v {
+	GoSeq in_ = {};
+	GoSeq out_ = {};
+	go_seq_writeRef(&in_, self._ref);
+	go_seq_writeUTF8(&in_, v);
+	go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_SET_, &in_, &out_);
+	go_seq_free(&in_);
+	go_seq_free(&out_);
+}
+
+@end
+
+#define _GO_issue10788_TestInterface_DESCRIPTOR_ "go.issue10788.TestInterface"
+#define _GO_issue10788_TestInterface_DoSomeWork_ (0x10a)
+#define _GO_issue10788_TestInterface_MultipleUnnamedParams_ (0x20a)
+
 @implementation GoIssue10788TestInterface {
 }
 
@@ -90,41 +127,6 @@
 	}
 }
 
-#define _GO_issue10788_TestStruct_DESCRIPTOR_ "go.issue10788.TestStruct"
-#define _GO_issue10788_TestStruct_FIELD_Value_GET_ (0x00f)
-#define _GO_issue10788_TestStruct_FIELD_Value_SET_ (0x01f)
-
-@implementation GoIssue10788TestStruct {
-}
-
-- (id)initWithRef:(id)ref {
-	self = [super init];
-	if (self) { __ref = ref; }
-	return self;
-}
-
-- (NSString*)value {
-	GoSeq in_ = {};
-	GoSeq out_ = {};
-	go_seq_writeRef(&in_, self._ref);
-	go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_GET_, &in_, &out_);
-	NSString* ret_ = go_seq_readUTF8(&out_);
-	go_seq_free(&in_);
-	go_seq_free(&out_);
-	return ret_;
-}
-
-- (void)setValue:(NSString*)v {
-	GoSeq in_ = {};
-	GoSeq out_ = {};
-	go_seq_writeRef(&in_, self._ref);
-	go_seq_writeUTF8(&in_, v);
-	go_seq_send(_GO_issue10788_TestStruct_DESCRIPTOR_, _GO_issue10788_TestStruct_FIELD_Value_SET_, &in_, &out_);
-	go_seq_free(&in_);
-	go_seq_free(&out_);
-}
-
-@end
 
 __attribute__((constructor)) static void init() {
 	go_seq_register_proxy("go.issue10788.TestInterface", proxyGoIssue10788TestInterface);
diff --git a/bind/testdata/issue12328.objc.m.golden b/bind/testdata/issue12328.objc.m.golden
index ffe7d08..75323b7 100644
--- a/bind/testdata/issue12328.objc.m.golden
+++ b/bind/testdata/issue12328.objc.m.golden
@@ -15,7 +15,6 @@
 
 #define _DESCRIPTOR_ "issue12328"
 
-
 #define _GO_issue12328_T_DESCRIPTOR_ "go.issue12328.T"
 #define _GO_issue12328_T_FIELD_Err_GET_ (0x00f)
 #define _GO_issue12328_T_FIELD_Err_SET_ (0x01f)
@@ -52,3 +51,4 @@
 
 @end
 
+
diff --git a/bind/testdata/issue12403.objc.h.golden b/bind/testdata/issue12403.objc.h.golden
index 51883b9..5e7eba5 100644
--- a/bind/testdata/issue12403.objc.h.golden
+++ b/bind/testdata/issue12403.objc.h.golden
@@ -8,6 +8,9 @@
 
 #include <Foundation/Foundation.h>
 
+@protocol GoIssue12403Parsable;
+@class GoIssue12403Parsable;
+
 @protocol GoIssue12403Parsable
 - (NSString*)fromJSON:(NSString*)jstr;
 - (BOOL)toJSON:(NSString**)ret0_ error:(NSError**)error;
diff --git a/bind/testdata/issue12403.objc.m.golden b/bind/testdata/issue12403.objc.m.golden
index 1ddc8f1..cbc8011 100644
--- a/bind/testdata/issue12403.objc.m.golden
+++ b/bind/testdata/issue12403.objc.m.golden
@@ -15,10 +15,7 @@
 
 #define _DESCRIPTOR_ "issue12403"
 
-
-#define _GO_issue12403_Parsable_DESCRIPTOR_ "go.issue12403.Parsable"
-#define _GO_issue12403_Parsable_FromJSON_ (0x10a)
-#define _GO_issue12403_Parsable_ToJSON_ (0x20a)
+@class GoIssue12403Parsable;
 
 @interface GoIssue12403Parsable : NSObject <GoIssue12403Parsable> {
 }
@@ -29,6 +26,10 @@
 - (BOOL)toJSON:(NSString**)ret0_ error:(NSError**)error;
 @end
 
+#define _GO_issue12403_Parsable_DESCRIPTOR_ "go.issue12403.Parsable"
+#define _GO_issue12403_Parsable_FromJSON_ (0x10a)
+#define _GO_issue12403_Parsable_ToJSON_ (0x20a)
+
 @implementation GoIssue12403Parsable {
 }
 
@@ -101,6 +102,7 @@
 	}
 }
 
+
 __attribute__((constructor)) static void init() {
 	go_seq_register_proxy("go.issue12403.Parsable", proxyGoIssue12403Parsable);
 }
diff --git a/bind/testdata/structs.objc.m.golden b/bind/testdata/structs.objc.m.golden
index 7427baf..7d1a900 100644
--- a/bind/testdata/structs.objc.m.golden
+++ b/bind/testdata/structs.objc.m.golden
@@ -15,9 +15,6 @@
 
 #define _DESCRIPTOR_ "structs"
 
-#define _CALL_Identity_ 1
-#define _CALL_IdentityWithError_ 2
-
 #define _GO_structs_S_DESCRIPTOR_ "go.structs.S"
 #define _GO_structs_S_FIELD_X_GET_ (0x00f)
 #define _GO_structs_S_FIELD_X_SET_ (0x01f)
@@ -113,6 +110,9 @@
 
 @end
 
+#define _CALL_Identity_ 1
+#define _CALL_IdentityWithError_ 2
+
 GoStructsS* GoStructsIdentity(GoStructsS* s) {
 	GoSeq in_ = {};
 	GoSeq out_ = {};
diff --git a/bind/testdata/vars.objc.h.golden b/bind/testdata/vars.objc.h.golden
index ac1cdf6..da431d0 100644
--- a/bind/testdata/vars.objc.h.golden
+++ b/bind/testdata/vars.objc.h.golden
@@ -9,9 +9,8 @@
 #include <Foundation/Foundation.h>
 
 @class GoVarsS;
-
-@protocol GoVarsI
-@end
+@protocol GoVarsI;
+@class GoVarsI;
 
 @interface GoVarsS : NSObject {
 }
@@ -20,6 +19,9 @@
 - (id)initWithRef:(id)ref;
 @end
 
+@protocol GoVarsI
+@end
+
 @interface GoVars : NSObject 
 + (BOOL) aBool;
 + (void) setABool:(BOOL)v;
diff --git a/bind/testdata/vars.objc.m.golden b/bind/testdata/vars.objc.m.golden
index 89595c9..6261133 100644
--- a/bind/testdata/vars.objc.m.golden
+++ b/bind/testdata/vars.objc.m.golden
@@ -15,8 +15,7 @@
 
 #define _DESCRIPTOR_ "vars"
 
-
-#define _GO_vars_I_DESCRIPTOR_ "go.vars.I"
+@class GoVarsI;
 
 @interface GoVarsI : NSObject <GoVarsI> {
 }
@@ -25,6 +24,21 @@
 - (id)initWithRef:(id)ref;
 @end
 
+#define _GO_vars_S_DESCRIPTOR_ "go.vars.S"
+
+@implementation GoVarsS {
+}
+
+- (id)initWithRef:(id)ref {
+	self = [super init];
+	if (self) { __ref = ref; }
+	return self;
+}
+
+@end
+
+#define _GO_vars_I_DESCRIPTOR_ "go.vars.I"
+
 @implementation GoVarsI {
 }
 
@@ -43,19 +57,6 @@
 	}
 }
 
-#define _GO_vars_S_DESCRIPTOR_ "go.vars.S"
-
-@implementation GoVarsS {
-}
-
-- (id)initWithRef:(id)ref {
-	self = [super init];
-	if (self) { __ref = ref; }
-	return self;
-}
-
-@end
-
 @implementation GoVars
 + (void) setABool:(BOOL)v {
 	GoSeq in_ = {};
@@ -305,6 +306,7 @@
 
 @end
 
+
 __attribute__((constructor)) static void init() {
 	go_seq_register_proxy("go.vars.I", proxyGoVarsI);
 }