Skip to content

Commit 7b6fb6e

Browse files
committed
Implement abstract templates to call virtuals
This allows for, just as with regular classes, the calling of virtual methods of abstract templates returned by functions. Fixes #1270. Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent 4e30a41 commit 7b6fb6e

File tree

11 files changed

+98
-42
lines changed

11 files changed

+98
-42
lines changed

src/Generator/Generators/CSharp/CSharpGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public override bool SetupPasses()
4343

4444
protected override string TypePrinterDelegate(Type type)
4545
{
46-
return type.Visit(typePrinter).Type;
46+
return type.Visit(typePrinter);
4747
}
4848
}
4949
}

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ public override bool VisitClassDecl(Class @class)
288288
Context.Return.Write($"({returnType.Visit(typePrinter)}) (object) ");
289289

290290
if (returnType.IsAddress())
291-
Context.Return.Write(HandleReturnedPointer(@class, qualifiedClass.Type));
291+
Context.Return.Write(HandleReturnedPointer(@class, qualifiedClass));
292292
else
293293
Context.Return.Write($"{qualifiedClass}.{Helpers.CreateInstanceIdentifier}({Context.ReturnVarName})");
294294

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,12 @@ public override bool VisitClassDecl(Class @class)
374374
return true;
375375
}
376376

377-
if (!@class.IsDependent)
377+
if (!@class.IsDependent && !@class.IsAbstractImpl)
378378
foreach (var nestedTemplate in @class.Classes.Where(
379379
c => !c.IsIncomplete && c.IsDependent))
380380
GenerateClassTemplateSpecializationInternal(nestedTemplate);
381381

382-
if (@class.IsTemplate)
382+
if (@class.IsTemplate && !@class.IsAbstractImpl)
383383
{
384384
if (!(@class.Namespace is Class))
385385
GenerateClassTemplateSpecializationInternal(@class);
@@ -1206,7 +1206,8 @@ private static Property GetActualProperty(Property property, Class c)
12061206
if (!(c is ClassTemplateSpecialization))
12071207
return property;
12081208
return c.Properties.SingleOrDefault(p => p.GetMethod != null &&
1209-
p.GetMethod.InstantiatedFrom == property.GetMethod);
1209+
p.GetMethod.InstantiatedFrom ==
1210+
(property.GetMethod.OriginalFunction ?? property.GetMethod));
12101211
}
12111212

12121213
private void GenerateFunctionInProperty(Class @class, Method constituent,
@@ -1487,6 +1488,9 @@ private void GenerateVariable(Class @class, Variable variable)
14871488

14881489
public List<VTableComponent> GetUniqueVTableMethodEntries(Class @class)
14891490
{
1491+
if (@class.IsDependent)
1492+
@class = @class.Specializations[0];
1493+
14901494
var uniqueEntries = new OrderedSet<VTableComponent>();
14911495
var vTableMethodEntries = VTables.GatherVTableMethodEntries(@class);
14921496
foreach (var entry in vTableMethodEntries.Where(e => !e.IsIgnored() && !e.Method.IsOperator))
@@ -1603,6 +1607,9 @@ private void AllocateNewVTables(Class @class, IList<VTableComponent> wrappedEntr
16031607

16041608
private void SaveOriginalVTablePointers(Class @class)
16051609
{
1610+
if (@class.IsDependent)
1611+
@class = @class.Specializations[0];
1612+
16061613
if (Context.ParserOptions.IsMicrosoftAbi)
16071614
WriteLine("__OriginalVTables = new void*[] {{ {0} }};",
16081615
string.Join(", ",
@@ -2086,13 +2093,14 @@ private void GenerateDisposeMethods(Class @class)
20862093
var classInternal = TypePrinter.PrintNative(@class);
20872094
if (@class.IsDynamic && GetUniqueVTableMethodEntries(@class).Count != 0)
20882095
{
2096+
ClassLayout layout = (@class.IsDependent ? @class.Specializations[0] : @class).Layout;
20892097
if (Context.ParserOptions.IsMicrosoftAbi)
2090-
for (var i = 0; i < @class.Layout.VTablePointers.Count; i++)
2098+
for (var i = 0; i < layout.VTablePointers.Count; i++)
20912099
WriteLine($@"(({classInternal}*) {Helpers.InstanceIdentifier})->{
2092-
@class.Layout.VTablePointers[i].Name} = new global::System.IntPtr(__OriginalVTables[{i}]);");
2100+
layout.VTablePointers[i].Name} = new global::System.IntPtr(__OriginalVTables[{i}]);");
20932101
else
20942102
WriteLine($@"(({classInternal}*) {Helpers.InstanceIdentifier})->{
2095-
@class.Layout.VTablePointers[0].Name} = new global::System.IntPtr(__OriginalVTables[0]);");
2103+
layout.VTablePointers[0].Name} = new global::System.IntPtr(__OriginalVTables[0]);");
20962104
}
20972105
}
20982106

@@ -2157,13 +2165,13 @@ private void GenerateNativeConstructor(Class @class)
21572165
if (!@class.IsAbstractImpl)
21582166
{
21592167
PushBlock(BlockKind.Method);
2160-
var printedClass = @class.Visit(TypePrinter);
2168+
TypePrinterResult printedClass = @class.Visit(TypePrinter);
21612169
WriteLine("internal static {0}{1} {2}(global::System.IntPtr native, bool skipVTables = false)",
21622170
@class.NeedsBase && !@class.BaseClass.IsInterface ? "new " : string.Empty,
21632171
printedClass, Helpers.CreateInstanceIdentifier);
21642172
WriteOpenBraceAndIndent();
21652173
var suffix = @class.IsAbstract ? "Internal" : string.Empty;
2166-
var ctorCall = $"{printedClass}{suffix}";
2174+
var ctorCall = $"{printedClass.Type}{suffix}{printedClass.NameSuffix}";
21672175
WriteLine("return new {0}(native.ToPointer(), skipVTables);", ctorCall);
21682176
UnindentAndWriteCloseBrace();
21692177
PopBlock(NewLineKind.BeforeNextBlock);
@@ -2196,7 +2204,7 @@ private void GenerateNativeConstructor(Class @class)
21962204
WriteLine("{0} = new global::System.IntPtr(native);", Helpers.InstanceIdentifier);
21972205
var dtor = @class.Destructors.FirstOrDefault();
21982206
var hasVTables = @class.IsDynamic && GetUniqueVTableMethodEntries(@class).Count > 0;
2199-
var setupVTables = !@class.IsAbstractImpl && hasVTables && dtor != null && dtor.IsVirtual;
2207+
var setupVTables = !@class.IsAbstractImpl && hasVTables && dtor?.IsVirtual == true;
22002208
if (setupVTables)
22012209
{
22022210
WriteLine("if (skipVTables)");
@@ -2224,7 +2232,7 @@ private void GenerateNativeConstructor(Class @class)
22242232
PopBlock(NewLineKind.BeforeNextBlock);
22252233
}
22262234

2227-
public void GenerateNativeConstructorByValue(Class @class, string returnType)
2235+
public void GenerateNativeConstructorByValue(Class @class, TypePrinterResult returnType)
22282236
{
22292237
var @internal = TypePrinter.PrintNative(@class.IsAbstractImpl ? @class.BaseClass : @class);
22302238

@@ -2235,7 +2243,7 @@ public void GenerateNativeConstructorByValue(Class @class, string returnType)
22352243
returnType, Helpers.CreateInstanceIdentifier, @internal);
22362244
WriteOpenBraceAndIndent();
22372245
var suffix = @class.IsAbstract ? "Internal" : "";
2238-
WriteLine($"return new {returnType}{suffix}(native, skipVTables);");
2246+
WriteLine($"return new {returnType.Type}{suffix}{returnType.NameSuffix}(native, skipVTables);");
22392247
UnindentAndWriteCloseBrace();
22402248
PopBlock(NewLineKind.BeforeNextBlock);
22412249
}
@@ -2451,7 +2459,7 @@ private void GenerateMethodBody(Class @class, Method method,
24512459
if (specialization != null)
24522460
{
24532461
var specializedMethod = @class.Methods.FirstOrDefault(
2454-
m => m.InstantiatedFrom == method);
2462+
m => m.InstantiatedFrom == (method.OriginalFunction ?? method));
24552463
if (specializedMethod == null)
24562464
{
24572465
WriteLine($@"throw new MissingMethodException(""Method {
@@ -2479,10 +2487,6 @@ private void GenerateMethodBody(Class @class, Method method,
24792487
{
24802488
GenerateOperator(method, returnType);
24812489
}
2482-
else if (method.SynthKind == FunctionSynthKind.AbstractImplCall)
2483-
{
2484-
GenerateVirtualFunctionCall(method);
2485-
}
24862490
else if (method.IsVirtual)
24872491
{
24882492
GenerateVirtualFunctionCall(method);
@@ -2752,12 +2756,6 @@ public void GenerateInternalFunctionCall(Function function,
27522756
public void GenerateFunctionCall(string functionName, Function function,
27532757
QualifiedType returnType = default(QualifiedType))
27542758
{
2755-
if (function.IsPure)
2756-
{
2757-
WriteLine("throw new System.NotImplementedException();");
2758-
return;
2759-
}
2760-
27612759
// ignored functions may get here from interfaces for secondary bases
27622760
if (function.Ignore)
27632761
{

src/Generator/Generators/CSharp/CSharpSourcesExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ public static void GenerateNativeConstructorsByValue(
2929
if (@class.IsTemplate)
3030
specializations = specializations.KeepSingleAllPointersSpecialization();
3131
foreach (var specialization in specializations)
32-
gen.GenerateNativeConstructorByValue(specialization, printedClass.Type);
32+
gen.GenerateNativeConstructorByValue(specialization, printedClass);
3333
}
3434
else
3535
{
36-
gen.GenerateNativeConstructorByValue(@class, printedClass.Type);
36+
gen.GenerateNativeConstructorByValue(@class, printedClass);
3737
}
3838
}
3939

src/Generator/Generators/CSharp/CSharpTypePrinter.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,11 @@ public override TypePrinterResult VisitTemplateSpecializationType(
293293
List<TemplateArgument> args = template.Arguments;
294294
var @class = (Class) template.Template.TemplatedDecl;
295295
TemplateArgument lastArg = args.Last();
296-
return $@"{VisitDeclaration(decl)}<{string.Join(", ",
296+
TypePrinterResult typePrinterResult = VisitDeclaration(decl);
297+
typePrinterResult.NameSuffix.Append($@"<{string.Join(", ",
297298
args.Concat(Enumerable.Range(0, @class.TemplateParameters.Count - args.Count).Select(
298-
i => lastArg)).Select(this.VisitTemplateArgument))}>";
299+
i => lastArg)).Select(this.VisitTemplateArgument))}>");
300+
return typePrinterResult;
299301
}
300302

301303
if (ContextKind == TypePrinterContextKind.Native)
@@ -529,20 +531,21 @@ public override TypePrinterResult VisitClassDecl(Class @class)
529531
return $@"{VisitDeclaration(@class.OriginalClass ?? @class)}.{
530532
Helpers.InternalStruct}{Helpers.GetSuffixForInternal(@class)}";
531533

532-
var printed = VisitDeclaration(@class).Type;
533-
if (!@class.IsTemplate)
534-
return printed;
535-
return $@"{printed}<{string.Join(", ",
536-
@class.TemplateParameters.Select(p => p.Name))}>";
534+
TypePrinterResult printed = VisitDeclaration(@class);
535+
if (@class.IsTemplate)
536+
printed.NameSuffix.Append($@"<{string.Join(", ",
537+
@class.TemplateParameters.Select(p => p.Name))}>");
538+
return printed;
537539
}
538540

539541
public override TypePrinterResult VisitClassTemplateSpecializationDecl(
540542
ClassTemplateSpecialization specialization)
541543
{
542-
if (ContextKind == TypePrinterContextKind.Native)
543-
return $"{VisitClassDecl(specialization)}";
544-
var args = string.Join(", ", specialization.Arguments.Select(VisitTemplateArgument));
545-
return $"{VisitClassDecl(specialization)}<{args}>";
544+
TypePrinterResult typePrinterResult = VisitClassDecl(specialization);
545+
if (ContextKind != TypePrinterContextKind.Native)
546+
typePrinterResult.NameSuffix.Append($@"<{string.Join(", ",
547+
specialization.Arguments.Select(VisitTemplateArgument))}>");
548+
return typePrinterResult;
546549
}
547550

548551
public TypePrinterResult VisitTemplateArgument(TemplateArgument a)
@@ -556,7 +559,8 @@ public TypePrinterResult VisitTemplateArgument(TemplateArgument a)
556559
return $@"CppSharp.Runtime.Pointer<{(pointee == PrimitiveType.Void ? IntPtrType :
557560
VisitPrimitiveType(pointee, new TypeQualifiers()).Type)}>";
558561
}
559-
return type.IsPrimitiveType(PrimitiveType.Void) ? "object" : type.Visit(this).Type;
562+
return type.IsPrimitiveType(PrimitiveType.Void) ?
563+
new TypePrinterResult("object") : type.Visit(this);
560564
}
561565

562566
public override TypePrinterResult VisitParameterDecl(Parameter parameter)

src/Generator/Passes/GenerateAbstractImplementationsPass.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public override bool VisitClassDecl(Class @class)
5757
if (@class.CompleteDeclaration != null)
5858
return VisitClassDecl(@class.CompleteDeclaration as Class);
5959

60-
if (@class.IsAbstract && !@class.IsTemplate)
60+
if (@class.IsAbstract && (!@class.IsTemplate || Options.GenerateClassTemplates))
6161
{
6262
foreach (var ctor in from ctor in @class.Constructors
6363
where ctor.Access == AccessSpecifier.Public
@@ -69,7 +69,7 @@ public override bool VisitClassDecl(Class @class)
6969
return @class.IsAbstract;
7070
}
7171

72-
private static Class AddInternalImplementation(Class @class)
72+
private static T AddInternalImplementation<T>(T @class) where T : Class, new()
7373
{
7474
var internalImpl = GetInternalImpl(@class);
7575

@@ -94,14 +94,26 @@ private static Class AddInternalImplementation(Class @class)
9494
return internalImpl;
9595
}
9696

97-
private static Class GetInternalImpl(Declaration @class)
97+
private static T GetInternalImpl<T>(T @class) where T : Class, new()
9898
{
99-
var internalImpl = new Class
99+
var internalImpl = new T
100100
{
101101
Name = @class.Name + "Internal",
102102
Access = AccessSpecifier.Private,
103103
Namespace = @class.Namespace
104104
};
105+
if (@class.IsDependent)
106+
{
107+
internalImpl.IsDependent = true;
108+
internalImpl.TemplateParameters.AddRange(@class.TemplateParameters);
109+
foreach (var specialization in @class.Specializations)
110+
{
111+
var specializationImpl = AddInternalImplementation(specialization);
112+
specializationImpl.Arguments.AddRange(specialization.Arguments);
113+
specializationImpl.TemplatedDecl = specialization.TemplatedDecl;
114+
internalImpl.Specializations.Add(specializationImpl);
115+
}
116+
}
105117

106118
var @base = new BaseClassSpecifier { Type = new TagType(@class) };
107119
internalImpl.Bases.Add(@base);

tests/CSharp/CSharp.Tests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,17 @@ public void TestFieldWithSpecializationType()
992992
}
993993
}
994994

995+
[Test]
996+
public void TestAbstractTemplate()
997+
{
998+
using (Foo foo = new Foo())
999+
using (AbstractTemplate<int> abstractTemplate = foo.AbstractTemplate)
1000+
{
1001+
Assert.That(abstractTemplate.Property, Is.EqualTo(55));
1002+
Assert.That(abstractTemplate.CallFunction(), Is.EqualTo(65));
1003+
}
1004+
}
1005+
9951006
[Test]
9961007
public void TestSpecializationForSecondaryBase()
9971008
{

tests/CSharp/CSharp.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ const int& Foo::returnConstRef()
8888
return rename;
8989
}
9090

91+
AbstractTemplate<int>* Foo::getAbstractTemplate()
92+
{
93+
return new ImplementAbstractTemplate();
94+
}
95+
9196
const int Foo::rename;
9297

9398
int Foo::makeFunctionCall()

tests/CSharp/CSharp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class DLL_API Foo
3232
int width();
3333
void set_width(int value);
3434
const int& returnConstRef();
35+
AbstractTemplate<int>* getAbstractTemplate();
3536

3637
static const int rename = 5;
3738
static int makeFunctionCall();

tests/CSharp/CSharpTemplates.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ void RegularDynamic::virtualFunction()
145145
{
146146
}
147147

148+
int ImplementAbstractTemplate::property()
149+
{
150+
return 55;
151+
}
152+
153+
int ImplementAbstractTemplate::callFunction()
154+
{
155+
return 65;
156+
}
157+
148158
void forceUseSpecializations(IndependentFields<int> _1, IndependentFields<bool> _2,
149159
IndependentFields<T1> _3, IndependentFields<std::string> _4,
150160
DependentValueFields<int> _5,

0 commit comments

Comments
 (0)