diff --git a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj index d4a9e68..2e1fffa 100644 --- a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj +++ b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj @@ -14,6 +14,7 @@ + diff --git a/Capnp.Net.Runtime.Tests/Issue19.cs b/Capnp.Net.Runtime.Tests/Issue19.cs new file mode 100644 index 0000000..e07b6e3 --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Issue19.cs @@ -0,0 +1,332 @@ +using Capnp; +using Capnp.Rpc; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CapnpGen +{ + [TypeId(0x8f85f6df684d47b5UL), Proxy(typeof(GenericAProxy<>)), Skeleton(typeof(GenericASkeleton<>))] + public interface IGenericA : IDisposable where TT : class + { + Task MethodA(TT param1, CancellationToken cancellationToken_ = default); + } + + public class GenericAProxy : Proxy, IGenericA where TT : class + { + public async Task MethodA(TT param1, CancellationToken cancellationToken_ = default) + { + var in_ = SerializerState.CreateForRpc.Params_methodA.WRITER>(); + var arg_ = new CapnpGen.GenericA.Params_methodA() + {Param1 = param1}; + arg_.serialize(in_); + var d_ = await Call(10341943558714247093UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; + var r_ = CapnpSerializable.Create.Result_methodA>(d_); + return; + } + } + + public class GenericASkeleton : Skeleton> where TT : class + { + public GenericASkeleton() + { + SetMethodTable(MethodA); + } + + public override ulong InterfaceId => 10341943558714247093UL; + async Task MethodA(DeserializerState d_, CancellationToken cancellationToken_) + { + var in_ = CapnpSerializable.Create.Params_methodA>(d_); + await Impl.MethodA(in_.Param1, cancellationToken_); + var s_ = SerializerState.CreateForRpc.Result_methodA.WRITER>(); + return s_; + } + } + + public static class GenericA + where TT : class + { + [TypeId(0xe67c3d73f913c24fUL)] + public class Params_methodA : ICapnpSerializable + { + public const UInt64 typeId = 0xe67c3d73f913c24fUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Param1 = CapnpSerializable.Create(reader.Param1); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Param1.SetObject(Param1); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public TT Param1 + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public DeserializerState Param1 => ctx.StructReadPointer(0); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 1); + } + + public DynamicSerializerState Param1 + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [TypeId(0xd6791784c41c75f3UL)] + public class Result_methodA : ICapnpSerializable + { + public const UInt64 typeId = 0xd6791784c41c75f3UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 0); + } + } + } + } + + [TypeId(0xe3cd928b8338eac9UL), Proxy(typeof(B2Proxy)), Skeleton(typeof(B2Skeleton))] + public interface IB2 : CapnpGen.IGenericA + { + Task MethodB(long param1, CancellationToken cancellationToken_ = default); + } + + public class B2Proxy : Proxy, IB2 + { + public async Task MethodB(long param1, CancellationToken cancellationToken_ = default) + { + var in_ = SerializerState.CreateForRpc(); + var arg_ = new CapnpGen.B2.Params_methodB() + {Param1 = param1}; + arg_.serialize(in_); + var d_ = await Call(16414937344734980809UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; + var r_ = CapnpSerializable.Create(d_); + return (r_.Res); + } + + public async Task MethodA(string param1, CancellationToken cancellationToken_ = default) + { + var in_ = SerializerState.CreateForRpc.Params_methodA.WRITER>(); + var arg_ = new CapnpGen.GenericA.Params_methodA() + {Param1 = param1}; + arg_.serialize(in_); + var d_ = await Call(10341943558714247093UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; + var r_ = CapnpSerializable.Create.Result_methodA>(d_); + return; + } + } + + public class B2Skeleton : Skeleton + { + public B2Skeleton() + { + SetMethodTable(MethodB); + } + + public override ulong InterfaceId => 16414937344734980809UL; + Task MethodB(DeserializerState d_, CancellationToken cancellationToken_) + { + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.MethodB(in_.Param1, cancellationToken_), res => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new CapnpGen.B2.Result_methodB{Res = res}; + r_.serialize(s_); + return s_; + } + + ); + } + } + + public static class B2 + { + [TypeId(0xdf7b0019c911a776UL)] + public class Params_methodB : ICapnpSerializable + { + public const UInt64 typeId = 0xdf7b0019c911a776UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Param1 = reader.Param1; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Param1 = Param1; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public long Param1 + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public long Param1 => ctx.ReadDataLong(0UL, 0L); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 0); + } + + public long Param1 + { + get => this.ReadDataLong(0UL, 0L); + set => this.WriteData(0UL, value, 0L); + } + } + } + + [TypeId(0xea5fbbd3b20b4347UL)] + public class Result_methodB : ICapnpSerializable + { + public const UInt64 typeId = 0xea5fbbd3b20b4347UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Res = reader.Res; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Res = Res; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Res + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string Res => ctx.ReadText(0, ""); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 1); + } + + public string Res + { + get => this.ReadText(0, ""); + set => this.WriteText(0, value, ""); + } + } + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index fee316a..7b8c31c 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -120,5 +120,28 @@ namespace Capnp.Net.Runtime.Tests } } } + + [TestMethod] + public void InheritFromGenericInterface() + { + using (var server = SetupServer()) + { + var counters = new Counters(); + server.Main = new B2Impl(); + + using (var client = SetupClient()) + { + client.WhenConnected.Wait(); + + using (var main = client.GetMain()) + { + Assert.IsTrue(main.MethodA("42").Wait(MediumNonDbgTimeout)); + var b = main.MethodB(123); + Assert.IsTrue(b.Wait(MediumNonDbgTimeout)); + Assert.AreEqual("42", b.Result); + } + } + } + } } } diff --git a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/TestCapImplementations.cs index b00d2be..94d241a 100644 --- a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/TestCapImplementations.cs @@ -753,4 +753,27 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } #endregion TestHandle + + #region B2 + + class B2Impl : CapnpGen.IB2 + { + string _s; + + public void Dispose() + { + } + + public Task MethodA(string param1, CancellationToken cancellationToken_ = default) + { + _s = param1; + return Task.CompletedTask; + } + + public Task MethodB(long param1, CancellationToken cancellationToken_ = default) + { + return Task.FromResult(_s); + } + } + #endregion B2 } diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index fad4233..984ff3f 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -18,7 +18,7 @@ MIT Git capnp "Cap'n Proto" RPC serialization cerealization - 1.1-local$([System.DateTime]::UtcNow.ToString(yyMMddHHmm)) + 1.2-local$([System.DateTime]::UtcNow.ToString(yyMMddHHmm)) Debug;Release diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 98b7fe0..0ae96f1 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -119,21 +119,20 @@ namespace Capnp.Rpc try { var attrs = (from iface in _.GetInterfaces() - from attr in iface.GetCustomAttributes(typeof(SkeletonAttribute), true) - select (SkeletonAttribute)attr).ToArray(); + let generics = iface.GetGenericArguments() + from attr in iface.GetCustomAttributes(typeof(SkeletonAttribute), false) + select (Attr: (SkeletonAttribute)attr, Generics: generics)).ToArray(); if (attrs.Length == 0) throw new InvalidCapabilityInterfaceException("No 'Skeleton' attribute defined, don't know how to create the skeleton"); - Type[] genericArguments = type.GetGenericArguments(); - if (attrs.Length == 1) { - return CreateMonoSkeletonFactory(attrs[0], genericArguments); + return CreateMonoSkeletonFactory(attrs[0].Attr, attrs[0].Generics); } else { - var monoFactories = attrs.Select(a => CreateMonoSkeletonFactory(a, genericArguments)).ToArray(); + var monoFactories = attrs.Select(a => CreateMonoSkeletonFactory(a.Attr, a.Generics)).ToArray(); return new PolySkeletonFactory(monoFactories); } } @@ -174,7 +173,7 @@ namespace Capnp.Rpc try { var attrs = type - .GetCustomAttributes(typeof(ProxyAttribute), true) + .GetCustomAttributes(typeof(ProxyAttribute), false) .Cast() .ToArray(); diff --git a/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj b/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj index 0f3fa11..cf329b9 100644 --- a/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj +++ b/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj @@ -10,7 +10,10 @@ + + + @@ -24,6 +27,7 @@ + @@ -37,6 +41,7 @@ + diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature index 239fd3d..8952e00 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature @@ -46,3 +46,12 @@ Scenario: Multiple errors Then the invocation must fail And the reason must be bad input And the error output must contain multiple messages + +Scenario Outline: Valid generator output + Given I have a binary code generator request + When I invoke capnpc-csharp + Then the invocation must succeed and the generated code must compile + +Examples: + | bin | + | Issue19.capnp.bin | diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs index c01b9e3..0fdc738 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs @@ -241,6 +241,34 @@ this.ScenarioInitialize(scenarioInfo); #line hidden this.ScenarioCleanup(); } + + public virtual void ValidGeneratorOutput(string bin, string[] exampleTags) + { + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Valid generator output", null, exampleTags); +#line 50 +this.ScenarioInitialize(scenarioInfo); + this.ScenarioStart(); +#line 51 + testRunner.Given(string.Format("I have a binary code generator request {0}", bin), ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line 52 + testRunner.When("I invoke capnpc-csharp", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 53 + testRunner.Then("the invocation must succeed and the generated code must compile", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden + this.ScenarioCleanup(); + } + + [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()] + [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Valid generator output: Issue19.capnp.bin")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "Issue19.capnp.bin")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:bin", "Issue19.capnp.bin")] + public virtual void ValidGeneratorOutput_Issue19_Capnp_Bin() + { +#line 50 +this.ValidGeneratorOutput("Issue19.capnp.bin", ((string[])(null))); +#line hidden + } } } #pragma warning restore diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue19.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue19.capnp.bin new file mode 100644 index 0000000..31aca23 Binary files /dev/null and b/CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue19.capnp.bin differ diff --git a/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs b/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs index c539e1c..ee75822 100644 --- a/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs +++ b/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs @@ -102,6 +102,13 @@ namespace CapnpC.CSharp.Generator.Tests Assert.IsNotNull(_result.Exception, "Expected an exception"); } + [Then(@"the invocation must succeed and the generated code must compile")] + public void ThenTheInvocationMustSucceedAndTheGeneratedCodeMustCompile() + { + Assert.IsTrue(_result.IsSuccess, "Tool invocation was not successful"); + Assert.IsTrue(Util.InlineAssemblyCompiler.TryCompileCapnp(_result.GeneratedFiles[0].GeneratedContent), "Compilation was not successful"); + } + [Given(@"capnp\.exe is installed on my system")] public void GivenCapnp_ExeIsInstalledOnMySystem() { diff --git a/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs b/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs new file mode 100644 index 0000000..7abc30f --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs @@ -0,0 +1,49 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; + +namespace CapnpC.CSharp.Generator.Tests.Util +{ + class InlineAssemblyCompiler + { + public static bool TryCompileCapnp(string code) + { + var options = new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + optimizationLevel: OptimizationLevel.Debug); + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code); + + string assemblyRoot = Path.GetDirectoryName(typeof(object).Assembly.Location); + + string capnpRuntimePath = Path.GetFullPath(Path.Combine( + Assembly.GetExecutingAssembly().Location, + @"..\..\..\..\..\Capnp.Net.Runtime\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.dll")); + + var capnpRuntimeMetadataRef = MetadataReference.CreateFromFile(capnpRuntimePath); + + var compilation = CSharpCompilation.Create( + "CompilationTestAssembly", + options: options, + references: new MetadataReference[] { + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "mscorlib.dll")), + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.dll")), + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Core.dll")), + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Runtime.dll")), + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Private.CoreLib.dll")), + capnpRuntimeMetadataRef }, + syntaxTrees: new SyntaxTree[] { syntaxTree }); + + using (var stream = new MemoryStream()) + { + var emitResult = compilation.Emit(stream); + + return emitResult.Success; + } + } + } +} diff --git a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs index 5476c2f..2a2f9dd 100644 --- a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs @@ -283,7 +283,7 @@ namespace CapnpC.CSharp.Generator.CodeGen var allMethods = from c in Types.FromDefinition(type).AllImplementedClasses - from m in c.Definition.Methods + from m in c.Methods select m; foreach (var method in allMethods) diff --git a/CapnpC.CSharp.Generator/Model/AbstractType.cs b/CapnpC.CSharp.Generator/Model/AbstractType.cs index 6b6d4c7..0107e08 100644 --- a/CapnpC.CSharp.Generator/Model/AbstractType.cs +++ b/CapnpC.CSharp.Generator/Model/AbstractType.cs @@ -5,7 +5,6 @@ namespace CapnpC.CSharp.Generator.Model abstract class AbstractType { public TypeTag Tag { get; set; } - protected List Fields { get; } = new List(); public uint? FixedBitWidth { diff --git a/CapnpC.CSharp.Generator/Model/Method.cs b/CapnpC.CSharp.Generator/Model/Method.cs index 1d1ba7b..f7f2109 100644 --- a/CapnpC.CSharp.Generator/Model/Method.cs +++ b/CapnpC.CSharp.Generator/Model/Method.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace CapnpC.CSharp.Generator.Model { @@ -12,5 +13,21 @@ namespace CapnpC.CSharp.Generator.Model public Type ParamsStruct { get; set; } public Type ResultStruct { get; set; } public List GenericParameters { get; } = new List(); + + public Method Clone() + { + var method = new Method() + { + DeclaringInterface = DeclaringInterface, + Id = Id, + Name = Name, + ParamsStruct = ParamsStruct, + ResultStruct = ResultStruct + }; + method.Params.AddRange(Params.Select((p => p.Clone()))); + method.Results.AddRange(Results.Select(r => r.Clone())); + method.GenericParameters.AddRange(GenericParameters); + return method; + } } } diff --git a/CapnpC.CSharp.Generator/Model/SchemaModel.cs b/CapnpC.CSharp.Generator/Model/SchemaModel.cs index 9d9e223..f0b9c88 100644 --- a/CapnpC.CSharp.Generator/Model/SchemaModel.cs +++ b/CapnpC.CSharp.Generator/Model/SchemaModel.cs @@ -648,8 +648,9 @@ namespace CapnpC.CSharp.Generator.Model { foreach (var superClassReader in ifaceReader.Interface_Superclasses) { - var superClass = ProcessTypeDef(superClassReader.Id, state, TypeTag.Interface); - def.Superclasses.Add(Types.FromDefinition(superClass)); + var superClass = Types.FromDefinition(ProcessTypeDef(superClassReader.Id, state, TypeTag.Interface)); + ProcessBrand(superClassReader.Brand, superClass, state); + def.Superclasses.Add(superClass); } return ProcessInterfaceOrStructTail(def, ifaceReader, state); diff --git a/CapnpC.CSharp.Generator/Model/Type.cs b/CapnpC.CSharp.Generator/Model/Type.cs index 087f507..a48665e 100644 --- a/CapnpC.CSharp.Generator/Model/Type.cs +++ b/CapnpC.CSharp.Generator/Model/Type.cs @@ -83,7 +83,7 @@ namespace CapnpC.CSharp.Generator.Model } else { - return Types.AnyPointer; + return type; } } @@ -117,7 +117,25 @@ namespace CapnpC.CSharp.Generator.Model return result; } - public new IReadOnlyList Fields => Definition.Fields.LazyListSelect(SubstituteGenerics); + Method SubstituteGenerics(Method method) + { + var result = method.Clone(); + result.ParamsStruct = SubstituteGenerics(result.ParamsStruct); + result.ResultStruct = SubstituteGenerics(result.ResultStruct); + foreach (var field in result.Params) + { + field.Type = SubstituteGenerics(field.Type); + } + foreach (var field in result.Results) + { + field.Type = SubstituteGenerics(field.Type); + } + return result; + } + + public IReadOnlyList Fields => Definition.Fields.LazyListSelect(SubstituteGenerics); + + public IReadOnlyList Methods => Definition.Methods.LazyListSelect(SubstituteGenerics); public Type DeclaringType { diff --git a/CapnpC.CSharp.Generator/Model/TypeDefinition.cs b/CapnpC.CSharp.Generator/Model/TypeDefinition.cs index 9a0557c..61e8e64 100644 --- a/CapnpC.CSharp.Generator/Model/TypeDefinition.cs +++ b/CapnpC.CSharp.Generator/Model/TypeDefinition.cs @@ -39,7 +39,7 @@ namespace CapnpC.CSharp.Generator.Model public string Name { get; set; } public SpecialName SpecialName { get; set; } public DiscriminationInfo UnionInfo { get; set; } - public new List Fields => base.Fields; + public List Fields { get; } = new List(); public List Enumerants { get; } = new List(); public ICollection NestedDefinitions { get; } = new List(); public IEnumerable NestedTypes { get => this.GetNestedTypes(); } diff --git a/MsBuildGenerationTest/Issue19.capnp b/MsBuildGenerationTest/Issue19.capnp new file mode 100644 index 0000000..28aebd2 --- /dev/null +++ b/MsBuildGenerationTest/Issue19.capnp @@ -0,0 +1,9 @@ +@0xe169e9301753ca94; + +interface GenericA(T) { + methodA @0 (param1 :T) -> (); +} + +interface B2 extends (GenericA(Text)) { + methodB @0 (param1 :Int64) -> (res :Text); +} diff --git a/MsBuildGenerationTest/MsBuildGenerationTest.csproj b/MsBuildGenerationTest/MsBuildGenerationTest.csproj index b1dd49e..930a851 100644 --- a/MsBuildGenerationTest/MsBuildGenerationTest.csproj +++ b/MsBuildGenerationTest/MsBuildGenerationTest.csproj @@ -8,6 +8,14 @@ $(Version)* + + + + + + + + @@ -55,4 +63,10 @@ + + + Issue19.capnp + + + diff --git a/appveyor.yml b/appveyor.yml index eb8fafe..7d8f6c5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.1.{build}' +version: '1.2.{build}' image: Visual Studio 2019 # branches: # only: diff --git a/capnpc-csharp/capnpc-csharp.csproj b/capnpc-csharp/capnpc-csharp.csproj index 6b51e8e..373c3a3 100644 --- a/capnpc-csharp/capnpc-csharp.csproj +++ b/capnpc-csharp/capnpc-csharp.csproj @@ -13,7 +13,7 @@ https://github.com/c80k/capnproto-dotnetcore Git capnp capnpc RPC serialization cerealization - 1.1.0 + 1.2.0 Debug;Release