From 2ea7e2cc92e2c0880e1e15fb5d001a50e5a1dfe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sun, 16 Oct 2016 15:33:11 +0300 Subject: [PATCH] bind, bind/java: support generating exceptional constructors In Go type constructors can often return an error type too beside an instance of the type being created. This is useful in cases where the parameters might be wrong and instantiaion cannot succeed. This CL extends the Java generator so that these methods are also converted into class constructors that also can throw. Change-Id: I5e531eec126904a026767a8503968255b9fd833b Reviewed-on: https://go-review.googlesource.com/31184 Reviewed-by: Elias Naur --- bind/gen.go | 7 ++++--- bind/genjava.go | 15 +++++++++++++-- bind/java/SeqTest.java | 21 ++++++++++++++++++--- bind/testpkg/testpkg.go | 11 +++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) 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 +}