2
0
mirror of synced 2025-02-22 06:28:04 +00:00

bind: support fields with type error

Fixes golang/go#12328

Change-Id: I42872d26acb1c44522a64405cfa2d0f10fb24485
Reviewed-on: https://go-review.googlesource.com/13919
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw 2015-08-25 16:39:49 -04:00
parent 905c19f8c0
commit 11fe695b54
16 changed files with 439 additions and 64 deletions

View File

@ -28,6 +28,7 @@ var tests = []string{
"testdata/structs.go",
"testdata/interfaces.go",
"testdata/issue10788.go",
"testdata/issue12328.go",
"testdata/try.go",
}

View File

@ -181,18 +181,11 @@ func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
g.Printf("type proxy%s seq.Ref\n\n", obj.Name())
for _, f := range fields {
seqTyp := seqType(f.Type())
g.Printf("func proxy%s_%s_Set(out, in *seq.Buffer) {\n", obj.Name(), f.Name())
g.Indent()
g.Printf("ref := in.ReadRef()\n")
g.Printf("v := in.Read%s()\n", seqTyp)
if seqTyp == "Ref" {
g.Printf("ref.Get().(*%s.%s).%s = v.Get().(%s)\n", g.pkg.Name(), obj.Name(), f.Name(), g.typeString(f.Type()))
} else {
// TODO(crawshaw): other kinds of non-ptr types.
g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name(), f.Name())
}
g.genRead("v", "in", f.Type())
g.Printf("ref.Get().(*%s.%s).%s = v\n", g.pkg.Name(), obj.Name(), f.Name())
g.Outdent()
g.Printf("}\n\n")
@ -200,11 +193,7 @@ func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
g.Indent()
g.Printf("ref := in.ReadRef()\n")
g.Printf("v := ref.Get().(*%s.%s).%s\n", g.pkg.Name(), obj.Name(), f.Name())
if seqTyp == "Ref" {
g.Printf("out.WriteGoRef(v)\n")
} else {
g.Printf("out.Write%s(v)\n", seqTyp)
}
g.genWrite("v", "out", f.Type())
g.Outdent()
g.Printf("}\n\n")
}
@ -433,13 +422,15 @@ func (g *goGen) gen() error {
}
}
g.Printf("func init() {\n")
g.Indent()
for i, name := range funcs {
g.Printf("seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1, name)
if len(funcs) > 0 {
g.Printf("func init() {\n")
g.Indent()
for i, name := range funcs {
g.Printf("seq.Register(%q, %d, proxy_%s)\n", g.pkg.Name(), i+1, name)
}
g.Outdent()
g.Printf("}\n")
}
g.Outdent()
g.Printf("}\n")
if len(g.err) > 0 {
return g.err

View File

@ -287,7 +287,7 @@ func (g *javaGen) genInterface(o *types.TypeName) {
}
func isErrorType(T types.Type) bool {
return T == types.Universe.Lookup("error").Type()
return types.Identical(T, types.Universe.Lookup("error").Type())
}
func isJavaPrimitive(T types.Type) bool {
@ -305,6 +305,12 @@ func isJavaPrimitive(T types.Type) bool {
// javaType returns a string that can be used as a Java type.
func (g *javaGen) javaType(T types.Type) string {
if isErrorType(T) {
// The error type is usually translated into an exception in
// Java, however the type can be exposed in other ways, such
// as an exported field.
return "String"
}
switch T := T.(type) {
case *types.Basic:
switch T.Kind() {
@ -347,7 +353,11 @@ func (g *javaGen) javaType(T types.Type) string {
case *types.Named:
n := T.Obj()
if n.Pkg() != g.pkg {
panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), n.Pkg().Name(), g.pkg.Name()))
nPkgName := "<nilpkg>"
if nPkg := n.Pkg(); nPkg != nil {
nPkgName = nPkg.Name()
}
panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), nPkgName, g.pkg.Name()))
}
// TODO(crawshaw): more checking here
return n.Name()

View File

@ -329,6 +329,42 @@ func (g *objcGen) genFuncM(obj *types.Func) {
g.Printf("}\n")
}
func (g *objcGen) genGetter(desc string, f *types.Var) {
t := f.Type()
if isErrorType(t) {
t = types.Typ[types.String]
}
s := &funcSummary{
name: f.Name(),
ret: g.objcType(t),
retParams: []paramInfo{{typ: t, name: "ret_"}},
}
g.Printf("- %s {\n", s.asMethod(g))
g.Indent()
g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_GET_", s, true)
g.Outdent()
g.Printf("}\n\n")
}
func (g *objcGen) genSetter(desc string, f *types.Var) {
t := f.Type()
if isErrorType(t) {
t = types.Typ[types.String]
}
s := &funcSummary{
name: "set" + f.Name(),
ret: "void",
params: []paramInfo{{typ: t, name: "v"}},
}
g.Printf("- %s {\n", s.asMethod(g))
g.Indent()
g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_SET_", s, true)
g.Outdent()
g.Printf("}\n\n")
}
func (g *objcGen) genFunc(pkgDesc, callDesc string, s *funcSummary, isMethod bool) {
g.Printf("GoSeq in_ = {};\n")
g.Printf("GoSeq out_ = {};\n")
@ -596,8 +632,7 @@ func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) {
// accessors to exported fields.
for _, f := range exportedFields(t) {
// TODO(hyangah): error type field?
name, typ := f.Name(), g.objcType(f.Type())
name, typ := f.Name(), g.objcFieldType(f.Type())
g.Printf("- (%s)%s;\n", typ, name)
g.Printf("- (void)set%s:(%s)v;\n", name, typ)
}
@ -636,32 +671,8 @@ func (g *objcGen) genStructM(obj *types.TypeName, t *types.Struct) {
g.Printf("}\n\n")
for _, f := range fields {
// getter
// TODO(hyangah): support error type fields?
s := &funcSummary{
name: f.Name(),
ret: g.objcType(f.Type()),
}
s.retParams = append(s.retParams, paramInfo{typ: f.Type(), name: "ret_"})
g.Printf("- %s {\n", s.asMethod(g))
g.Indent()
g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_GET_", s, true)
g.Outdent()
g.Printf("}\n\n")
// setter
s = &funcSummary{
name: "set" + f.Name(),
ret: "void",
}
s.params = append(s.params, paramInfo{typ: f.Type(), name: "v"})
g.Printf("- %s {\n", s.asMethod(g))
g.Indent()
g.genFunc(desc+"_DESCRIPTOR_", desc+"_FIELD_"+f.Name()+"_SET_", s, true)
g.Outdent()
g.Printf("}\n\n")
g.genGetter(desc, f)
g.genSetter(desc, f)
}
for _, m := range methods {
@ -699,6 +710,13 @@ func (g *objcGen) refTypeBase(typ types.Type) string {
return g.objcType(typ)
}
func (g *objcGen) objcFieldType(t types.Type) string {
if isErrorType(t) {
return "NSString*"
}
return g.objcType(t)
}
func (g *objcGen) objcType(typ types.Type) string {
if isErrorType(typ) {
return "NSError*"

View File

@ -286,4 +286,12 @@ public class SeqTest extends AndroidTestCase {
String got = a.String();
assertEquals("want Node A points to Node B", "A:B:<end>", got);
}
public void testErrorField() {
final String want = "an error message";
Testpkg.Node n = Testpkg.NewNode("ErrTest");
n.setErr(want);
String got = n.getErr();
assertEquals("want back the error message we set", want, got);
}
}

View File

@ -138,6 +138,7 @@ func UnnamedParams(_, _ int, p0 string) int {
type Node struct {
V string
Next *Node
Err error
}
func NewNode(name string) *Node {

View File

@ -128,6 +128,12 @@ func proxy_NewI(out, in *seq.Buffer) {
out.WriteGoRef(res)
}
func proxy_NewNode(out, in *seq.Buffer) {
param_name := in.ReadString()
res := testpkg.NewNode(param_name)
out.WriteGoRef(res)
}
func proxy_NewS(out, in *seq.Buffer) {
param_x := in.ReadFloat64()
param_y := in.ReadFloat64()
@ -135,6 +141,51 @@ func proxy_NewS(out, in *seq.Buffer) {
out.WriteGoRef(res)
}
const (
proxyNode_Descriptor = "go.testpkg.Node"
proxyNode_V_Get_Code = 0x00f
proxyNode_V_Set_Code = 0x01f
proxyNode_Err_Get_Code = 0x10f
proxyNode_Err_Set_Code = 0x11f
)
type proxyNode seq.Ref
func proxyNode_V_Set(out, in *seq.Buffer) {
ref := in.ReadRef()
v := in.ReadString()
ref.Get().(*testpkg.Node).V = v
}
func proxyNode_V_Get(out, in *seq.Buffer) {
ref := in.ReadRef()
v := ref.Get().(*testpkg.Node).V
out.WriteString(v)
}
func proxyNode_Err_Set(out, in *seq.Buffer) {
ref := in.ReadRef()
v := in.ReadError()
ref.Get().(*testpkg.Node).Err = v
}
func proxyNode_Err_Get(out, in *seq.Buffer) {
ref := in.ReadRef()
v := ref.Get().(*testpkg.Node).Err
if v == nil {
out.WriteString("")
} else {
out.WriteString(v.Error())
}
}
func init() {
seq.Register(proxyNode_Descriptor, proxyNode_V_Set_Code, proxyNode_V_Set)
seq.Register(proxyNode_Descriptor, proxyNode_V_Get_Code, proxyNode_V_Get)
seq.Register(proxyNode_Descriptor, proxyNode_Err_Set_Code, proxyNode_Err_Set)
seq.Register(proxyNode_Descriptor, proxyNode_Err_Get_Code, proxyNode_Err_Get)
}
func proxy_RegisterI(out, in *seq.Buffer) {
param_idx := in.ReadInt32()
var param_i testpkg.I
@ -242,9 +293,10 @@ func init() {
seq.Register("testpkg", 8, proxy_Int)
seq.Register("testpkg", 9, proxy_Multiply)
seq.Register("testpkg", 10, proxy_NewI)
seq.Register("testpkg", 11, proxy_NewS)
seq.Register("testpkg", 12, proxy_RegisterI)
seq.Register("testpkg", 13, proxy_ReturnsError)
seq.Register("testpkg", 14, proxy_Sum)
seq.Register("testpkg", 15, proxy_UnregisterI)
seq.Register("testpkg", 11, proxy_NewNode)
seq.Register("testpkg", 12, proxy_NewS)
seq.Register("testpkg", 13, proxy_RegisterI)
seq.Register("testpkg", 14, proxy_ReturnsError)
seq.Register("testpkg", 15, proxy_Sum)
seq.Register("testpkg", 16, proxy_UnregisterI)
}

View File

@ -9,6 +9,8 @@
#include <Foundation/Foundation.h>
@class GoTestpkgNode;
@class GoTestpkgS;
@protocol GoTestpkgI
@ -16,6 +18,17 @@
- (int64_t)Times:(int32_t)v;
@end
@interface GoTestpkgNode : NSObject {
}
@property(strong, readonly) id ref;
- (id)initWithRef:(id)ref;
- (NSString*)V;
- (void)setV:(NSString*)v;
- (NSString*)Err;
- (void)setErr:(NSString*)v;
@end
@interface GoTestpkgS : NSObject {
}
@property(strong, readonly) id ref;
@ -49,6 +62,8 @@ FOUNDATION_EXPORT int64_t GoTestpkgMultiply(int32_t idx, int32_t val);
FOUNDATION_EXPORT id<GoTestpkgI> GoTestpkgNewI();
FOUNDATION_EXPORT GoTestpkgNode* GoTestpkgNewNode(NSString* name);
FOUNDATION_EXPORT GoTestpkgS* GoTestpkgNewS(double x, double y);
FOUNDATION_EXPORT void GoTestpkgRegisterI(int32_t idx, id<GoTestpkgI> i);

View File

@ -25,11 +25,12 @@ static NSString* errDomain = @"go.golang.org/x/mobile/bind/objc/testpkg";
#define _CALL_Int_ 8
#define _CALL_Multiply_ 9
#define _CALL_NewI_ 10
#define _CALL_NewS_ 11
#define _CALL_RegisterI_ 12
#define _CALL_ReturnsError_ 13
#define _CALL_Sum_ 14
#define _CALL_UnregisterI_ 15
#define _CALL_NewNode_ 11
#define _CALL_NewS_ 12
#define _CALL_RegisterI_ 13
#define _CALL_ReturnsError_ 14
#define _CALL_Sum_ 15
#define _CALL_UnregisterI_ 16
#define _GO_testpkg_I_DESCRIPTOR_ "go.testpkg.I"
#define _GO_testpkg_I_Error_ (0x10a)
@ -96,7 +97,7 @@ static void proxyGoTestpkgI(id obj, int code, GoSeq* in, GoSeq* out) {
} else {
NSString* errorDesc = [error localizedDescription];
if (errorDesc == NULL || errorDesc.length == 0) {
errorDesc = @"unknown error";
errorDesc = @"gobind: unknown error";
}
go_seq_writeUTF8(out, errorDesc);
}
@ -112,6 +113,65 @@ static void proxyGoTestpkgI(id obj, int code, GoSeq* in, GoSeq* out) {
}
}
#define _GO_testpkg_Node_DESCRIPTOR_ "go.testpkg.Node"
#define _GO_testpkg_Node_FIELD_V_GET_ (0x00f)
#define _GO_testpkg_Node_FIELD_V_SET_ (0x01f)
#define _GO_testpkg_Node_FIELD_Err_GET_ (0x10f)
#define _GO_testpkg_Node_FIELD_Err_SET_ (0x11f)
@implementation GoTestpkgNode {
}
- (id)initWithRef:(id)ref {
self = [super init];
if (self) { _ref = ref; }
return self;
}
- (NSString*)V {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_V_GET_, &in_, &out_);
NSString* ret_ = go_seq_readUTF8(&out_);
go_seq_free(&in_);
go_seq_free(&out_);
return ret_;
}
- (void)setV:(NSString*)v {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_writeUTF8(&in_, v);
go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_V_SET_, &in_, &out_);
go_seq_free(&in_);
go_seq_free(&out_);
}
- (NSString*)Err {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_Err_GET_, &in_, &out_);
NSString* ret_ = go_seq_readUTF8(&out_);
go_seq_free(&in_);
go_seq_free(&out_);
return ret_;
}
- (void)setErr:(NSString*)v {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_writeUTF8(&in_, v);
go_seq_send(_GO_testpkg_Node_DESCRIPTOR_, _GO_testpkg_Node_FIELD_Err_SET_, &in_, &out_);
go_seq_free(&in_);
go_seq_free(&out_);
}
@end
#define _GO_testpkg_S_DESCRIPTOR_ "go.testpkg.S"
#define _GO_testpkg_S_FIELD_X_GET_ (0x00f)
#define _GO_testpkg_S_FIELD_X_SET_ (0x01f)
@ -321,6 +381,21 @@ id<GoTestpkgI> GoTestpkgNewI() {
return ret0_;
}
GoTestpkgNode* GoTestpkgNewNode(NSString* name) {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeUTF8(&in_, name);
go_seq_send(_DESCRIPTOR_, _CALL_NewNode_, &in_, &out_);
GoSeqRef* ret0__ref = go_seq_readRef(&out_);
GoTestpkgNode* ret0_ = ret0__ref.obj;
if (ret0_ == NULL) {
ret0_ = [[GoTestpkgNode alloc] initWithRef:ret0__ref];
}
go_seq_free(&in_);
go_seq_free(&out_);
return ret0_;
}
GoTestpkgS* GoTestpkgNewS(double x, double y) {
GoSeq in_ = {};
GoSeq out_ = {};

View File

@ -134,3 +134,12 @@ func (s *S) Sum() float64 {
func CallSSum(s *S) float64 {
return s.Sum()
}
type Node struct {
V string
Err error
}
func NewNode(name string) *Node {
return &Node{V: name}
}

View File

@ -78,6 +78,3 @@ func init() {
seq.Register(proxyTestStruct_Descriptor, proxyTestStruct_Value_Set_Code, proxyTestStruct_Value_Set)
seq.Register(proxyTestStruct_Descriptor, proxyTestStruct_Value_Get_Code, proxyTestStruct_Value_Get)
}
func init() {
}

9
bind/testdata/issue12328.go vendored Normal file
View File

@ -0,0 +1,9 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue12328
type T struct {
Err error
}

39
bind/testdata/issue12328.go.golden vendored Normal file
View File

@ -0,0 +1,39 @@
// Package go_issue12328 is an autogenerated binder stub for package issue12328.
// gobind -lang=go issue12328
//
// File is generated by gobind. Do not edit.
package go_issue12328
import (
"golang.org/x/mobile/bind/seq"
"issue12328"
)
const (
proxyT_Descriptor = "go.issue12328.T"
proxyT_Err_Get_Code = 0x00f
proxyT_Err_Set_Code = 0x01f
)
type proxyT seq.Ref
func proxyT_Err_Set(out, in *seq.Buffer) {
ref := in.ReadRef()
v := in.ReadError()
ref.Get().(*issue12328.T).Err = v
}
func proxyT_Err_Get(out, in *seq.Buffer) {
ref := in.ReadRef()
v := ref.Get().(*issue12328.T).Err
if v == nil {
out.WriteString("")
} else {
out.WriteString(v.Error())
}
}
func init() {
seq.Register(proxyT_Descriptor, proxyT_Err_Set_Code, proxyT_Err_Set)
seq.Register(proxyT_Descriptor, proxyT_Err_Get_Code, proxyT_Err_Get)
}

74
bind/testdata/issue12328.java.golden vendored Normal file
View File

@ -0,0 +1,74 @@
// Java Package issue12328 is a proxy for talking to a Go program.
// gobind -lang=java issue12328
//
// File is generated by gobind. Do not edit.
package go.issue12328;
import go.Seq;
public abstract class Issue12328 {
private Issue12328() {} // uninstantiable
public static final class T implements go.Seq.Object {
private static final String DESCRIPTOR = "go.issue12328.T";
private static final int FIELD_Err_GET = 0x00f;
private static final int FIELD_Err_SET = 0x01f;
private go.Seq.Ref ref;
private T(go.Seq.Ref ref) { this.ref = ref; }
public go.Seq.Ref ref() { return ref; }
public void call(int code, go.Seq in, go.Seq out) {
throw new RuntimeException("internal error: cycle: cannot call concrete proxy");
}
public String getErr() {
Seq in = new Seq();
Seq out = new Seq();
in.writeRef(ref);
Seq.send(DESCRIPTOR, FIELD_Err_GET, in, out);
return out.readString();
}
public void setErr(String v) {
Seq in = new Seq();
Seq out = new Seq();
in.writeRef(ref);
in.writeString(v);
Seq.send(DESCRIPTOR, FIELD_Err_SET, in, out);
}
@Override public boolean equals(Object o) {
if (o == null || !(o instanceof T)) {
return false;
}
T that = (T)o;
String thisErr = getErr();
String thatErr = that.getErr();
if (thisErr == null) {
if (thatErr != null) {
return false;
}
} else if (!thisErr.equals(thatErr)) {
return false;
}
return true;
}
@Override public int hashCode() {
return java.util.Arrays.hashCode(new Object[] {getErr()});
}
@Override public String toString() {
StringBuilder b = new StringBuilder();
b.append("T").append("{");
b.append("Err:").append(getErr()).append(",");
return b.append("}").toString();
}
}
private static final String DESCRIPTOR = "issue12328";
}

22
bind/testdata/issue12328.objc.h.golden vendored Normal file
View File

@ -0,0 +1,22 @@
// Objective-C API for talking to issue12328 Go package.
// gobind -lang=objc issue12328
//
// File is generated by gobind. Do not edit.
#ifndef __GoIssue12328_H__
#define __GoIssue12328_H__
#include <Foundation/Foundation.h>
@class GoIssue12328T;
@interface GoIssue12328T : NSObject {
}
@property(strong, readonly) id ref;
- (id)initWithRef:(id)ref;
- (NSString*)Err;
- (void)setErr:(NSString*)v;
@end
#endif

54
bind/testdata/issue12328.objc.m.golden vendored Normal file
View File

@ -0,0 +1,54 @@
// Objective-C API for talking to issue12328 Go package.
// gobind -lang=objc issue12328
//
// File is generated by gobind. Do not edit.
#include "GoIssue12328.h"
#include <Foundation/Foundation.h>
#include "seq.h"
static NSString* errDomain = @"go.issue12328";
@protocol goSeqRefInterface
-(GoSeqRef*) ref;
@end
#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)
@implementation GoIssue12328T {
}
- (id)initWithRef:(id)ref {
self = [super init];
if (self) { _ref = ref; }
return self;
}
- (NSString*)Err {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_send(_GO_issue12328_T_DESCRIPTOR_, _GO_issue12328_T_FIELD_Err_GET_, &in_, &out_);
NSString* ret_ = go_seq_readUTF8(&out_);
go_seq_free(&in_);
go_seq_free(&out_);
return ret_;
}
- (void)setErr:(NSString*)v {
GoSeq in_ = {};
GoSeq out_ = {};
go_seq_writeRef(&in_, self.ref);
go_seq_writeUTF8(&in_, v);
go_seq_send(_GO_issue12328_T_DESCRIPTOR_, _GO_issue12328_T_FIELD_Err_SET_, &in_, &out_);
go_seq_free(&in_);
go_seq_free(&out_);
}
@end