diff --git a/bind/gen.go b/bind/gen.go index ac8bca5..519d1e3 100644 --- a/bind/gen.go +++ b/bind/gen.go @@ -175,13 +175,14 @@ func (g *Generator) Init() { } } -// constructorType returns the type T for a function on the form +// constructorType returns the type T for a function of the forms: // -// func NewT(...) *T +// func NewT...(...) *T +// func NewT...(...) (*T, error) func (g *Generator) constructorType(f *types.Func) *types.TypeName { sig := f.Type().(*types.Signature) res := sig.Results() - if res.Len() != 1 { + if res.Len() != 1 && !(res.Len() == 2 && isErrorType(res.At(1).Type())) { return nil } rt := res.At(0).Type() diff --git a/bind/genjava.go b/bind/genjava.go index f2a82fa..1989210 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -941,6 +941,7 @@ func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { return } sig := f.Type().(*types.Signature) + res := sig.Results() g.Printf("JNIEXPORT jobject JNICALL\n") g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz", g.jniPkgName(), sName, java.JNIMangle("__"+f.Name())) @@ -956,8 +957,12 @@ func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { name := g.paramName(params, i) g.genJavaToC(name, params.At(i).Type(), modeTransient) } - // Constructors always have one result parameter, a *T. - g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name()) + // Constructors always return a mandatory *T and an optional error + if res.Len() == 1 { + g.Printf("int32_t refnum = proxy%s__%s(", g.pkgPrefix, f.Name()) + } else { + g.Printf("struct proxy%s__%s_return res = proxy%s__%s(", g.pkgPrefix, f.Name(), g.pkgPrefix, f.Name()) + } for i := 0; i < params.Len(); i++ { if i > 0 { g.Printf(", ") @@ -968,6 +973,12 @@ func (g *JavaGen) genJNIConstructor(f *types.Func, sName string) { for i := 0; i < params.Len(); i++ { g.genRelease(g.paramName(params, i), params.At(i).Type(), modeTransient) } + // Extract multi returns and handle errors + if res.Len() == 2 { + g.Printf("int32_t refnum = res.r0;\n") + g.genCToJava("_err", "res.r1", res.At(1).Type(), modeRetained) + g.Printf("go_seq_maybe_throw_exception(env, _err);\n") + } // Pass no proxy class so that the Seq.Ref is returned instead. g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n") g.Outdent() diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java index 101ccba..1089fda 100644 --- a/bind/java/SeqTest.java +++ b/bind/java/SeqTest.java @@ -530,12 +530,27 @@ public class SeqTest extends InstrumentationTestCase { public void testConstructor() { Interface i = new Concrete(); i.f(); + S2 s = new S2(1, 2); assertEquals("new S2().sum", 3.0, s.sum()); assertEquals("new S2().tryTwoStrings", "gostring", s.tryTwoStrings("go", "string")); - new S3(); - S4 s4 = new S4(123); - assertEquals("Constructor argument", 123, s4.getI()); + + new S3(); + + S4 s4 = new S4(123); + assertEquals("Constructor argument", 123, s4.getI()); + + s4 = new S4(123.456); + assertEquals("Overloaded constructor argument", 123, s4.getI()); + + s4 = new S4(false); + assertEquals("Exceptional constructor", 0, s4.getI()); + + try { + s4 = new S4(true); + fail("Constructor error wasn't caught"); + } catch (Exception e) { + } } public void testEmptyError() { diff --git a/bind/testpkg/testpkg.go b/bind/testpkg/testpkg.go index 9e743ef..5411f45 100644 --- a/bind/testpkg/testpkg.go +++ b/bind/testpkg/testpkg.go @@ -558,3 +558,14 @@ type S4 struct { func NewS4WithInt(i int) *S4 { return &S4{i} } + +func NewS4WithFloat(f float64) *S4 { + return &S4{int(f)} +} + +func NewS4WithBoolAndError(b bool) (*S4, error) { + if b { + return nil, errors.New("some error") + } + return new(S4), nil +}