Skip to content
/ bond Public
forked from microsoft/bond

Commit

Permalink
[c# grpc] Fix codegen for generic collection args
Browse files Browse the repository at this point in the history
If a service use a generic type like bond.Box<T> with a collection type
argument as a parameter/return type, the generated code was missing an
import of System.Collections.Generic. This has been fixed.

An example, demonstrating how to use bond.Box to wrap scalar service
arguments has been added. This also serves to test the fixed codegen.

A helper method Bond.Box.Create() has been added to enable creation of
Bond.Box<T> instances via type deduction.

Fixes microsoft#623
  • Loading branch information
chwarr committed Sep 28, 2017
1 parent f96af1f commit cafeacc
Show file tree
Hide file tree
Showing 29 changed files with 687 additions and 15 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ different versioning scheme, following the Haskell community's
* IDL core version: TBD
* IDL comm version: TBD
* C++ version: TBD (minor bump needed)
* C# NuGet version: TBD (bug fix bump needed)
* C# NuGet version: TBD (minor bump needed)
* C# Comm NuGet version: (minor bump needed)

### `gbc` and Bond compiler library ###
Expand Down Expand Up @@ -44,6 +44,7 @@ different versioning scheme, following the Haskell community's

### C# ###

* Added `Bond.Box.Create` helper method to create `Bond.Box<T>` instances.
* Reflection.IsBonded now recognizes custom IBonded implementations.
* Use Newtonsoft's JSON.NET BigInteger support -- when available -- to
handle the full range of uint64 values in the SimpleJson protocol (.NET
Expand All @@ -59,6 +60,9 @@ different versioning scheme, following the Haskell community's
state left in the CompactBinaryWriter.
* Apply IDL annotations to services and methods for gRPC.
[Issue #617](https://github.com/Microsoft/bond/issues/617)
* Fixed a bug that produced C# code that couldn't be compiled when using
Bond-over-gRPC with a generic type instantiated with a collection.
[Issue #623](https://github.com/Microsoft/bond/issues/623)

[msdn-gzipstream]: https://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream(v=vs.110).aspx
[msdn-stream-canseek]: https://msdn.microsoft.com/en-us/library/system.io.stream.canseek(v=vs.110).aspx
Expand Down
5 changes: 4 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,10 @@
nunit-console-x86 /framework:net-4.5 /labels "cs\test\core\bin\debug\net45-nonportable\${env:BOND_OUTPUT}\Bond.UnitTest.dll"
if (-not $?) { throw "tests failed" }
& examples\cs\grpc\pingpong\bin\Debug\pingpong.exe
& examples\cs\grpc\pingpong\bin\Debug\grpc-pingpong.exe
if (-not $?) { throw "tests failed" }
& examples\cs\grpc\scalar\bin\Debug\grpc-scalar.exe
if (-not $?) { throw "tests failed" }
# We need to investigate why these tests are failing in AppVeyor, but not locally.
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/Language/Bond/Codegen/Cs/Comm_cs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ comm_interface_cs cs _ _ declarations = ("_interfaces.cs", [lt|
#{CS.disableReSharperWarnings}
namespace #{csNamespace}
{
using System.Collections.Generic;

#{doubleLineSep 1 comm declarations}
} // #{csNamespace}
|])
Expand Down Expand Up @@ -74,6 +76,8 @@ comm_proxy_cs cs _ _ declarations = ("_proxies.cs", [lt|
#{CS.disableReSharperWarnings}
namespace #{csNamespace}
{
using System.Collections.Generic;

#{doubleLineSep 1 comm declarations}
} // #{csNamespace}
|])
Expand Down Expand Up @@ -145,6 +149,8 @@ comm_service_cs cs _ _ declarations = ("_services.cs", [lt|
#{CS.disableReSharperWarnings}
namespace #{csNamespace}
{
using System.Collections.Generic;

#{doubleLineSep 1 comm declarations}
} // #{csNamespace}
|])
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/Language/Bond/Codegen/Cs/Grpc_cs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ grpc_cs cs _ _ declarations = ("_grpc.cs", [lt|

namespace #{csNamespace}
{
using System.Collections.Generic;

#{doubleLineSep 1 grpc declarations}
} // #{csNamespace}
|])
Expand Down
144 changes: 140 additions & 4 deletions compiler/tests/generated/generic_service_comm.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ namespace tests
virtual void foo33(const ::bond::comm::payload<Payload>& input,
const std::function<void (const ::bond::comm::message<Payload>&)>& callback) = 0;

virtual void ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) = 0;

virtual void ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) = 0;

struct Schema;
class Proxy;

Expand All @@ -37,6 +43,8 @@ namespace tests
private: static const ::bond::Metadata s_foo31_metadata;
private: static const ::bond::Metadata s_foo32_metadata;
private: static const ::bond::Metadata s_foo33_metadata;
private: static const ::bond::Metadata s_ConsumesGeneric1_metadata;
private: static const ::bond::Metadata s_ConsumesGeneric2_metadata;

public: struct service
{
Expand All @@ -63,14 +71,32 @@ namespace tests
&Foo<Payload>::foo33,
&s_foo33_metadata
> foo33;

typedef ::bond::reflection::MethodTemplate<
Foo<Payload>,
::bond::comm::payload< ::tests::SomeBox<int32_t>>,
::bond::comm::message<void>,
&Foo<Payload>::ConsumesGeneric1,
&s_ConsumesGeneric1_metadata
> ConsumesGeneric1;

typedef ::bond::reflection::MethodTemplate<
Foo<Payload>,
::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>,
::bond::comm::message<void>,
&Foo<Payload>::ConsumesGeneric2,
&s_ConsumesGeneric2_metadata
> ConsumesGeneric2;
};

private: typedef boost::mpl::list<> methods0;
private: typedef typename boost::mpl::push_front<methods0, typename service::foo33>::type methods1;
private: typedef typename boost::mpl::push_front<methods1, typename service::foo32>::type methods2;
private: typedef typename boost::mpl::push_front<methods2, typename service::foo31>::type methods3;
private: typedef typename boost::mpl::push_front<methods0, typename service::ConsumesGeneric2>::type methods1;
private: typedef typename boost::mpl::push_front<methods1, typename service::ConsumesGeneric1>::type methods2;
private: typedef typename boost::mpl::push_front<methods2, typename service::foo33>::type methods3;
private: typedef typename boost::mpl::push_front<methods3, typename service::foo32>::type methods4;
private: typedef typename boost::mpl::push_front<methods4, typename service::foo31>::type methods5;

public: typedef typename methods3::type methods;
public: typedef typename methods5::type methods;

Schema()
{
Expand All @@ -79,6 +105,8 @@ namespace tests
(void)s_foo31_metadata;
(void)s_foo32_metadata;
(void)s_foo33_metadata;
(void)s_ConsumesGeneric1_metadata;
(void)s_ConsumesGeneric2_metadata;
}
};

Expand All @@ -98,6 +126,14 @@ namespace tests
template <typename Payload>
const ::bond::Metadata Foo<Payload>::Schema::s_foo33_metadata
= ::bond::reflection::MetadataInit("foo33");

template <typename Payload>
const ::bond::Metadata Foo<Payload>::Schema::s_ConsumesGeneric1_metadata
= ::bond::reflection::MetadataInit("ConsumesGeneric1");

template <typename Payload>
const ::bond::Metadata Foo<Payload>::Schema::s_ConsumesGeneric2_metadata
= ::bond::reflection::MetadataInit("ConsumesGeneric2");

template <typename Payload>
class Foo<Payload>::Proxy
Expand Down Expand Up @@ -142,6 +178,30 @@ namespace tests
_impl->foo33(input, callback);
}

void ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
_impl->ConsumesGeneric1(input, callback);
}

void ConsumesGeneric1(const ::tests::SomeBox<int32_t>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback)
{
_impl->ConsumesGeneric1(boost::cref(input), callback);
}

void ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
_impl->ConsumesGeneric2(input, callback);
}

void ConsumesGeneric2(const ::tests::SomeBox<std::vector<int32_t> >& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback)
{
_impl->ConsumesGeneric2(boost::cref(input), callback);
}

template <template <typename> class Promise>
class Using;

Expand Down Expand Up @@ -178,6 +238,18 @@ namespace tests
_proxy.Send(_name, Schema::service::foo33::metadata.name, input, callback);
}

void ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
_proxy.Send(_name, Schema::service::ConsumesGeneric1::metadata.name, input, callback);
}

void ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
_proxy.Send(_name, Schema::service::ConsumesGeneric2::metadata.name, input, callback);
}

private:
ServiceProxy _proxy;
const std::string _name;
Expand All @@ -199,6 +271,12 @@ namespace tests
virtual auto foo33(const ::bond::comm::payload<Payload>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<Payload>>>().get_future()) = 0;

virtual auto ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future()) = 0;

virtual auto ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future()) = 0;

void foo31(const ::bond::comm::payload<Payload>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
Expand All @@ -216,6 +294,18 @@ namespace tests
{
when(foo33(input), ::bond::comm::Continuation(callback));
}

void ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
when(ConsumesGeneric1(input), ::bond::comm::Continuation(callback));
}

void ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input,
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
{
when(ConsumesGeneric2(input), ::bond::comm::Continuation(callback));
}
};

template <typename Payload>
Expand Down Expand Up @@ -291,6 +381,52 @@ namespace tests

return promise->get_future();
}

using Foo<Payload>::Proxy::ConsumesGeneric1;

auto ConsumesGeneric1(const ::bond::comm::payload< ::tests::SomeBox<int32_t>>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future())
{
auto promise = boost::make_shared<Promise< ::bond::comm::message<void>>>();

_impl->ConsumesGeneric1(input,
[=](const ::bond::comm::message<void>& result) mutable
{
promise->set_value(result);
});

return promise->get_future();
}

auto ConsumesGeneric1(const ::tests::SomeBox<int32_t>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future())
{
return ConsumesGeneric1(::bond::comm::payload< ::tests::SomeBox<int32_t>>(boost::cref(input)));
}


using Foo<Payload>::Proxy::ConsumesGeneric2;

auto ConsumesGeneric2(const ::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future())
{
auto promise = boost::make_shared<Promise< ::bond::comm::message<void>>>();

_impl->ConsumesGeneric2(input,
[=](const ::bond::comm::message<void>& result) mutable
{
promise->set_value(result);
});

return promise->get_future();
}

auto ConsumesGeneric2(const ::tests::SomeBox<std::vector<int32_t> >& input)
-> decltype(std::declval< Promise< ::bond::comm::message<void>>>().get_future())
{
return ConsumesGeneric2(::bond::comm::payload< ::tests::SomeBox<std::vector<int32_t> >>(boost::cref(input)));
}

};


Expand Down
44 changes: 44 additions & 0 deletions compiler/tests/generated/generic_service_grpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

namespace tests
{
using System.Collections.Generic;

[System.CodeDom.Compiler.GeneratedCode("gbc", "0.10.0.0")]
public static class Foo<Payload> where Payload : class
{
Expand All @@ -42,13 +44,31 @@ public static class Foo<Payload> where Payload : class
global::Bond.Grpc.Marshaller<Payload>.Instance,
global::Bond.Grpc.Marshaller<Payload>.Instance);

static readonly global::Grpc.Core.Method<global::Bond.Grpc.IMessage<SomeBox<int>>, global::Bond.Grpc.IMessage<global::Bond.Void>> Method_ConsumesGeneric1 = new global::Grpc.Core.Method<global::Bond.Grpc.IMessage<SomeBox<int>>, global::Bond.Grpc.IMessage<global::Bond.Void>>(
global::Grpc.Core.MethodType.Unary,
ServiceName,
"ConsumesGeneric1",
global::Bond.Grpc.Marshaller<SomeBox<int>>.Instance,
global::Bond.Grpc.Marshaller<global::Bond.Void>.Instance);

static readonly global::Grpc.Core.Method<global::Bond.Grpc.IMessage<SomeBox<List<int>>>, global::Bond.Grpc.IMessage<global::Bond.Void>> Method_ConsumesGeneric2 = new global::Grpc.Core.Method<global::Bond.Grpc.IMessage<SomeBox<List<int>>>, global::Bond.Grpc.IMessage<global::Bond.Void>>(
global::Grpc.Core.MethodType.Unary,
ServiceName,
"ConsumesGeneric2",
global::Bond.Grpc.Marshaller<SomeBox<List<int>>>.Instance,
global::Bond.Grpc.Marshaller<global::Bond.Void>.Instance);

public abstract class FooBase
{
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<global::Bond.Void>> foo31(global::Bond.Grpc.IMessage<Payload> request, global::Grpc.Core.ServerCallContext context);

public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<Payload>> foo32(global::Bond.Grpc.IMessage<global::Bond.Void> request, global::Grpc.Core.ServerCallContext context);

public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<Payload>> foo33(global::Bond.Grpc.IMessage<Payload> request, global::Grpc.Core.ServerCallContext context);

public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric1(global::Bond.Grpc.IMessage<SomeBox<int>> request, global::Grpc.Core.ServerCallContext context);

public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric2(global::Bond.Grpc.IMessage<SomeBox<List<int>>> request, global::Grpc.Core.ServerCallContext context);
}

public class FooClient : global::Grpc.Core.ClientBase<FooClient>
Expand Down Expand Up @@ -98,6 +118,28 @@ protected FooClient(global::Grpc.Core.ClientBase.ClientBaseConfiguration configu
return CallInvoker.AsyncUnaryCall(Method_foo33, null, options, request);
}

public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric1Async(SomeBox<int> request, global::Grpc.Core.Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
var message = global::Bond.Grpc.Message.From(request);
return ConsumesGeneric1Async(message, new global::Grpc.Core.CallOptions(headers, deadline, cancellationToken));
}

public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric1Async(global::Bond.Grpc.IMessage<SomeBox<int>> request, global::Grpc.Core.CallOptions options)
{
return CallInvoker.AsyncUnaryCall(Method_ConsumesGeneric1, null, options, request);
}

public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric2Async(SomeBox<List<int>> request, global::Grpc.Core.Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
var message = global::Bond.Grpc.Message.From(request);
return ConsumesGeneric2Async(message, new global::Grpc.Core.CallOptions(headers, deadline, cancellationToken));
}

public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<global::Bond.Void>> ConsumesGeneric2Async(global::Bond.Grpc.IMessage<SomeBox<List<int>>> request, global::Grpc.Core.CallOptions options)
{
return CallInvoker.AsyncUnaryCall(Method_ConsumesGeneric2, null, options, request);
}

protected override FooClient NewInstance(global::Grpc.Core.ClientBase.ClientBaseConfiguration configuration)
{
return new FooClient(configuration);
Expand All @@ -110,6 +152,8 @@ protected override FooClient NewInstance(global::Grpc.Core.ClientBase.ClientBase
.AddMethod(Method_foo31, serviceImpl.foo31)
.AddMethod(Method_foo32, serviceImpl.foo32)
.AddMethod(Method_foo33, serviceImpl.foo33)
.AddMethod(Method_ConsumesGeneric1, serviceImpl.ConsumesGeneric1)
.AddMethod(Method_ConsumesGeneric2, serviceImpl.ConsumesGeneric2)
.Build();
}
}
Expand Down
Loading

0 comments on commit cafeacc

Please sign in to comment.