Skip to content
This repository was archived by the owner on Dec 12, 2024. It is now read-only.

Added Associated Type support in Get properties #314

Merged
merged 3 commits into from
Feb 14, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions SwiftReflector/MarshalEngineCSafeSwiftToCSharp.cs
Original file line number Diff line number Diff line change
@@ -433,7 +433,7 @@ public List<ICodeElement> MarshalFromLambdaReceiverToCSFunc (CSType thisType, st


public List<ICodeElement> MarshalFromLambdaReceiverToCSProp (CSProperty prop, CSType thisType, string csProxyName, CSParameterList delegateParams,
FunctionDeclaration funcDecl, CSType methodType, bool isObjC)
FunctionDeclaration funcDecl, CSType methodType, bool isObjC, bool hasAssociatedTypes)
{
bool forProtocol = csProxyName != null;
bool needsReturn = funcDecl.IsGetter;
@@ -463,12 +463,13 @@ public List<ICodeElement> MarshalFromLambdaReceiverToCSProp (CSProperty prop, CS


CSIdentifier csharpCall = null;
if (forProtocol) {
csharpCall = new CSIdentifier ($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisType.ToString()}> (self).{prop.Name.Name}");
var thisTypeName = hasAssociatedTypes ? csProxyName : thisType.ToString ();
if (forProtocol && !hasAssociatedTypes) {
csharpCall = new CSIdentifier ($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisTypeName}> (self).{prop.Name.Name}");
} else {
var call = isObjC ?
$"ObjCRuntime.Runtime.GetNSObject<{thisType.ToString ()}> (self).{prop.Name.Name}" :
$"SwiftObjectRegistry.Registry.CSObjectForSwiftObject<{thisType.ToString ()}> (self).{prop.Name.Name}";
$"ObjCRuntime.Runtime.GetNSObject<{thisTypeName}> (self).{prop.Name.Name}" :
$"SwiftObjectRegistry.Registry.CSObjectForSwiftObject<{thisTypeName}> (self).{prop.Name.Name}";

csharpCall = new CSIdentifier (call);
}
52 changes: 36 additions & 16 deletions SwiftReflector/NewClassCompiler.cs
Original file line number Diff line number Diff line change
@@ -2265,7 +2265,7 @@ CSProperty ImplementProtocolSubscriptEtter (WrappingResult wrapper,
List<CSLine> vtableAssignments, CSUsingPackages use, bool isSetter, CSProperty wrapperProp, string swiftLibraryPath)
{
CSDelegateTypeDecl etterDelegateDecl = DefineDelegateAndAddToVtable (vtable, etterFunc, use,
OverrideBuilder.VTableEntryIdentifier (vtableEntryIndex), true);
OverrideBuilder.VTableEntryIdentifier (vtableEntryIndex), !protocolDecl.HasAssociatedTypes);
vtable.Delegates.Add (etterDelegateDecl);

var etterWrapperFunc = FindProtocolWrapperFunction (etterFunc, wrapper);
@@ -2524,7 +2524,7 @@ int ImplementPropertyVtableForVirtualProperties (WrappingResult wrapper,
}
var wrapperProp = ImplementPropertyEtter (wrapper, classDecl, subclassDecl, classContents, cl, picl, usedPinvokeNames, virtFuncs,
getterFunc, tlSetter, vtableEntryIndex, vtableName, vtable, vtableAssignments, use,
false, null, swiftLibraryPath);
false, null, swiftLibraryPath, null);

if (hasSetter) {
wrapperProp = ImplementPropertyEtter (wrapper, classDecl, subclassDecl, classContents, cl, picl, usedPinvokeNames, virtFuncs,
@@ -2544,7 +2544,7 @@ CSProperty ImplementProtocolPropertyEtter (WrappingResult wrapper,
List<CSLine> vtableAssignments, CSUsingPackages use, bool isSetter, bool isObjC, CSProperty wrapperProp, string swiftLibraryPath)
{
var etterDelegateDecl = DefineDelegateAndAddToVtable (vtable, etterFunc, use,
OverrideBuilder.VTableEntryIdentifier (vtableEntryIndex), true);
OverrideBuilder.VTableEntryIdentifier (vtableEntryIndex), !protocolDecl.HasAssociatedTypes);
vtable.Delegates.Add (etterDelegateDecl);

var etterWrapperFunc = FindProtocolWrapperFunction (etterFunc, wrapper);
@@ -2561,7 +2561,7 @@ CSProperty ImplementProtocolPropertyEtter (WrappingResult wrapper,
piEtterName = Uniqueify (piEtterName, usedPinvokeNames);
usedPinvokeNames.Add (piEtterName);

string piEtterRef = PIClassName (TypeMapper.GetDotNetNameForSwiftClassName (protocolContents.Name)) + "." + piEtterName;
string piEtterRef = picl.Name + "." + piEtterName;
var piGetter = TLFCompiler.CompileMethod (etterWrapperFunc, use,
PInvokeName (wrapper.ModuleLibPath, swiftLibraryPath),
etterWrapper.MangledName, piEtterName, true, true, false);
@@ -2570,6 +2570,9 @@ CSProperty ImplementProtocolPropertyEtter (WrappingResult wrapper,

if (wrapperProp == null) {
wrapperProp = TLFCompiler.CompileProperty (use, propName, etterFunc, setter, CSMethodKind.None);
if (protocolDecl.HasAssociatedTypes) {
SubstituteAssociatedTypeNamer (protocolDecl, wrapperProp);
}

var ifaceProp = new CSProperty (wrapperProp.PropType, CSMethodKind.None,
new CSIdentifier (propName),
@@ -2580,6 +2583,8 @@ CSProperty ImplementProtocolPropertyEtter (WrappingResult wrapper,

var usedIds = new List<string> { propName };
var marshal = new MarshalEngine (use, usedIds, TypeMapper, wrapper.Module.SwiftCompilerVersion);
if (protocolDecl.HasAssociatedTypes)
marshal.GenericReferenceNamer = MakeAssociatedTypeNamer (protocolDecl);

var ifTest = kInterfaceImpl != CSConstant.Null;
var ifBlock = new CSCodeBlock ();
@@ -2600,12 +2605,16 @@ CSProperty ImplementProtocolPropertyEtter (WrappingResult wrapper,
etterFunc, etterFunc.ReturnTypeSpec, wrapperProp.PropType, etterFunc.ParameterLists [0] [0].TypeSpec, new CSSimpleType (iface.Name.Name), false, wrapper, etterFunc.HasThrows));
}

var ifElse = new CSIfElse (ifTest, ifBlock, elseBlock);
target.Add (ifElse);
if (protocolDecl.HasAssociatedTypes) {
target.AddRange (elseBlock);
} else {
var ifElse = new CSIfElse (ifTest, ifBlock, elseBlock);
target.Add (ifElse);
}

var recvr = ImplementVirtualPropertyStaticReceiver (new CSSimpleType (iface.Name.Name),
proxyClass.Name.Name, etterDelegateDecl, use,
etterFunc, wrapperProp, null, vtable.Name, isObjC);
proxyClass.ToCSType ().ToString (), etterDelegateDecl, use,
etterFunc, wrapperProp, null, vtable.Name, isObjC, protocolDecl.HasAssociatedTypes);
proxyClass.Methods.Add (recvr);

vtableAssignments.Add (CSAssignment.Assign (String.Format ("{0}.{1}",
@@ -2617,7 +2626,8 @@ CSProperty ImplementPropertyEtter (WrappingResult wrapper,
ClassDeclaration classDecl, ClassDeclaration subclassDecl,
ClassContents classContents, CSClass cl, CSClass picl, List<string> usedPinvokeNames, List<FunctionDeclaration> virtFuncs,
FunctionDeclaration etterFunc, TLFunction tlSetter, int vtableEntryIndex, string vtableName, CSStruct vtable,
List<CSLine> vtableAssignments, CSUsingPackages use, bool isSetter, CSProperty wrapperProp, string swiftLibraryPath)
List<CSLine> vtableAssignments, CSUsingPackages use, bool isSetter, CSProperty wrapperProp, string swiftLibraryPath,
Func<int, int, string> genericRenamer = null)
{
var swiftClassName = XmlToTLFunctionMapper.ToSwiftClassName (subclassDecl);
var tlEtter = XmlToTLFunctionMapper.ToTLFunction (etterFunc, classContents);
@@ -2644,7 +2654,8 @@ CSProperty ImplementPropertyEtter (WrappingResult wrapper,

var piGetter = TLFCompiler.CompileMethod (etterWrapperFunc, use,
PInvokeName (wrapper.ModuleLibPath, swiftLibraryPath),
etterWrapper.MangledName, piEtterName, true, true, false); picl.Methods.Add (piGetter);
etterWrapper.MangledName, piEtterName, true, true, false);
picl.Methods.Add (piGetter);

var superEtterFunc = subclassDecl.AllMethodsNoCDTor ().Where (fn =>
fn.Access == Accessibility.Internal && fn.IsProperty &&
@@ -2685,7 +2696,8 @@ CSProperty ImplementPropertyEtter (WrappingResult wrapper,
}
}

ImplementOverloadFromKnownWrapper (cl, picl, usedPinvokeNames, swiftClassName, superEtterTlf, superEtterFunc, use, true, wrapper, swiftLibraryPath, superEtterFuncWrapper, "", true);
ImplementOverloadFromKnownWrapper (cl, picl, usedPinvokeNames, swiftClassName, superEtterTlf, superEtterFunc, use, true, wrapper, swiftLibraryPath, superEtterFuncWrapper, "", true,
genericRenamer: genericRenamer);
var propertyImplMethod = cl.Methods.Last ();
CSMethod protoListMethod = null;
if (returnIsProtocolList) {
@@ -2711,7 +2723,7 @@ CSProperty ImplementPropertyEtter (WrappingResult wrapper,
}

var recvr = ImplementVirtualPropertyStaticReceiver (cl.ToCSType (), null, etterDelegateDecl, use, etterFunc,
wrapperProp, protoListMethod, vtable.Name, classDecl.IsObjC);
wrapperProp, protoListMethod, vtable.Name, classDecl.IsObjC, false);
cl.Methods.Add (recvr);

vtableAssignments.Add (CSAssignment.Assign (String.Format ("{0}.{1}",
@@ -2841,7 +2853,7 @@ CSMethod ImplementVirtualSubscriptStaticReceiver (CSType thisType, string csProx

CSMethod ImplementVirtualPropertyStaticReceiver (CSType thisType, string csProxyName, CSDelegateTypeDecl delType,
CSUsingPackages use, FunctionDeclaration funcDecl, CSProperty prop, CSMethod protoListMethod,
CSIdentifier vtableName, bool isObjC)
CSIdentifier vtableName, bool isObjC, bool hasAssociatedTypes)
{
var returnType = funcDecl.IsGetter ? delType.Type : CSSimpleType.Void;
CSParameterList pl = delType.Parameters;
@@ -2860,7 +2872,7 @@ CSMethod ImplementVirtualPropertyStaticReceiver (CSType thisType, string csProxy

var bodyContents = marshaler.MarshalFromLambdaReceiverToCSProp (prop, thisType, csProxyName,
delType.Parameters,
funcDecl, prop.PropType, isObjC);
funcDecl, prop.PropType, isObjC, hasAssociatedTypes);
body.AddRange (bodyContents);
recvrName = "xamVtable_recv_" + (funcDecl.IsGetter ? "get_" : "set_") + prop.Name.Name;
}
@@ -2895,7 +2907,7 @@ CSLambda ImplementVirtualPropertyReceiver (CSType thisType, string csProxyName,
var marshaler = new MarshalEngineCSafeSwiftToCSharp (use, usedIDs, TypeMapper);

var bodyContents = marshaler.MarshalFromLambdaReceiverToCSProp (prop, thisType, csProxyName, delType.Parameters,
funcDecl, prop.PropType, isObjC);
funcDecl, prop.PropType, isObjC, false);
var body = new CSCodeBlock (bodyContents);
return new CSLambda (pl, body);
}
@@ -5122,7 +5134,8 @@ CSIfElse InterfaceMethodRedirect (CSMethod publicMethod, IEnumerable<ICodeElemen
CSMethod ImplementOverloadFromKnownWrapper (CSClass cl, CSClass picl, List<string> usedPinvokeNames, SwiftClassName classForPI,
TLFunction methodToWrap, FunctionDeclaration funcToWrap, CSUsingPackages use, bool isFinal,
WrappingResult wrapper, string swiftLibraryPath, TLFunction wrapperFunction,
string homonymSuffix, bool forcePrivate = false, string alternativeName = null)
string homonymSuffix, bool forcePrivate = false, string alternativeName = null,
Func<int, int, string> genericRenamer = null)
{
var wrapperFuncDecl = FindEquivalentFunctionDeclarationForWrapperFunction (wrapperFunction, TypeMapper, wrapper);
var pinvokeMethodName = PIMethodName (classForPI, wrapperFunction.Name) + homonymSuffix;
@@ -5190,6 +5203,7 @@ CSMethod ImplementOverloadFromKnownWrapper (CSClass cl, CSClass picl, List<strin
};

var marshaler = new MarshalEngine (use, localIdentifiers, TypeMapper, wrapper.Module.SwiftCompilerVersion);
marshaler.GenericReferenceNamer = genericRenamer;

publicMethod.Body.AddRange (marshaler.MarshalFunctionCall (wrapperFuncDecl, false, pinvokeMethodRef,
publicMethod.Parameters, funcToWrap, funcToWrap.ReturnTypeSpec, publicMethod.Type, instanceTypeSpec, cl.ToCSType (),
@@ -6330,6 +6344,12 @@ void SubstituteAssociatedTypeNamer (ProtocolDeclaration protocolDecl, CSMethod p
SubstituteAssociatedTypeNamer (namer, parm.CSType);
}

void SubstituteAssociatedTypeNamer (ProtocolDeclaration protocolDecl, CSProperty publicProperty)
{
var namer = MakeAssociatedTypeNamer (protocolDecl);
SubstituteAssociatedTypeNamer (namer, publicProperty.PropType);
}

void SubstituteAssociatedTypeNamer (Func<int, int, string> namer, CSType ty)
{
if (ty is CSGenericReferenceType genType) {
11 changes: 9 additions & 2 deletions SwiftReflector/OverrideBuilder.cs
Original file line number Diff line number Diff line change
@@ -255,7 +255,10 @@ ClassDeclaration BuildAssociatedTypeOverride (string name, ModuleDeclaration tar
dtor.ReturnTypeName = "()";
decl.Members.Add (dtor);

return decl.MakeUnrooted () as ClassDeclaration;
decl = decl.MakeUnrooted () as ClassDeclaration;
foreach (var member in decl.Members)
member.Parent = decl;
return decl;
}

void CopyConstructors ()
@@ -837,7 +840,11 @@ SLProperty DefineOverrideProperty (FunctionDeclaration getter, FunctionDeclarati
var ifelse = new SLIfElse (condition, ifblock, elseblock);

if (isProtocol) {
getBlock = ifblock;
if (getBlock.Count == 0)
getBlock = ifblock;
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: if one part of the if statement has curly braces, the other should have too (or neither).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know. Likely this test is going to go away in about 4 PRs so I'm not going to fix it now.

getBlock.AddRange (ifblock);
}
} else {
getBlock.And (ifelse);
}
14 changes: 14 additions & 0 deletions tests/tom-swifty-test/SwiftReflector/ProtocolConformanceTests.cs
Original file line number Diff line number Diff line change
@@ -209,6 +209,20 @@ public protocol Iterator0 {
associatedtype Elem
func next () -> Elem
}
";
var printer = CSFunctionCall.ConsoleWriteLine (CSConstant.Val ("OK"));
var callingCode = CSCodeBlock.Create (printer);
TestRunning.TestAndExecute (swiftCode, callingCode, "OK\n", platform: PlatformName.macOS);
}

[Test]
public void SmokeProtocolAssocGetProp ()
{
var swiftCode = @"
public protocol Iterator1 {
associatedtype Elem
var next:Elem { get }
}
";
var printer = CSFunctionCall.ConsoleWriteLine (CSConstant.Val ("OK"));
var callingCode = CSCodeBlock.Create (printer);