Example #1
0
        static bool TypeMatches(FunctionDeclaration decl, NamedTypeSpec ts, SwiftGenericArgReferenceType genArg)
        {
            if (!decl.IsTypeSpecGeneric(ts))
            {
                return(false);
            }
            var depthAndIndex = decl.GetGenericDepthAndIndex(ts.Name);

            return(genArg.Depth == depthAndIndex.Item1 && genArg.Index == depthAndIndex.Item2);
        }
 static bool TypeMatches(FunctionDeclaration decl, NamedTypeSpec ts, SwiftGenericArgReferenceType genArg, TypeMapper typeMap)
 {
     if (genArg.HasAssociatedTypePath)
     {
         if (!decl.IsProtocolWithAssociatedTypesFullPath(ts, typeMap))
         {
             return(false);
         }
         var parts = ts.Name.Split('.');
         // parts will have the generic part at 0, genArg will not
         if (parts.Length != genArg.AssociatedTypePath.Count + 1)
         {
             return(false);
         }
         var depthAndIndex = decl.GetGenericDepthAndIndex(parts [0]);
         if (genArg.Depth != depthAndIndex.Item1 || genArg.Index != depthAndIndex.Item2)
         {
             return(false);
         }
         for (int i = 0; i < genArg.AssociatedTypePath.Count; i++)
         {
             if (genArg.AssociatedTypePath [i] != parts [i + 1])
             {
                 return(false);
             }
         }
         return(true);
     }
     else
     {
         if (!decl.IsTypeSpecGeneric(ts))
         {
             return(false);
         }
         var depthAndIndex = decl.GetGenericDepthAndIndex(ts.Name);
         return(genArg.Depth == depthAndIndex.Item1 && genArg.Index == depthAndIndex.Item2);
     }
 }
        public List <ICodeElement> MarshalFromLambdaReceiverToCSProp(CSProperty prop, CSType thisType, string csProxyName, CSParameterList delegateParams,
                                                                     FunctionDeclaration funcDecl, CSType methodType, bool isObjC)
        {
            bool forProtocol     = csProxyName != null;
            bool needsReturn     = funcDecl.IsGetter;
            bool returnIsGeneric = funcDecl.IsTypeSpecGeneric(funcDecl.ReturnTypeSpec);

            var entity = !returnIsGeneric?typeMapper.GetEntityForTypeSpec(funcDecl.ReturnTypeSpec) : null;

            var entityType = !returnIsGeneric?typeMapper.GetEntityTypeForTypeSpec(funcDecl.ReturnTypeSpec) : EntityType.None;

            bool returnIsStructOrEnum = needsReturn && entity != null && entity.IsStructOrEnum;
            bool returnIsClass        = needsReturn && entity != null && entity.EntityType == EntityType.Class;
            bool returnIsProtocol     = needsReturn && entity != null && entity.EntityType == EntityType.Protocol;
            bool returnIsProtocolList = needsReturn && entityType == EntityType.ProtocolList;
            bool returnIsTuple        = needsReturn && entityType == EntityType.Tuple;
            bool returnIsClosure      = needsReturn && entityType == EntityType.Closure;

            string returnCsProxyName = returnIsProtocol ?
                                       NewClassCompiler.CSProxyNameForProtocol(entity.Type.ToFullyQualifiedName(true), typeMapper) : null;

            if (returnIsProtocol && returnCsProxyName == null)
            {
                throw ErrorHelper.CreateError(ReflectorError.kCompilerReferenceBase + 22, $"Unable to find C# interface for protocol {entity.Type.ToFullyQualifiedName ()}");
            }


            var body = new List <ICodeElement> ();

            if (isObjC)
            {
                use.AddIfNotPresent("ObjCRuntime");
            }
            else
            {
                use.AddIfNotPresent(typeof(SwiftObjectRegistry));
            }


            CSIdentifier csharpCall = null;

            if (forProtocol)
            {
                csharpCall = new CSIdentifier($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisType.ToString()}> (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}";

                csharpCall = new CSIdentifier(call);
            }

            if (funcDecl.IsGetter)
            {
                if (returnIsClass)
                {
                    if (isObjC)
                    {
                        body.Add(CSReturn.ReturnLine(csharpCall.Dot(new CSIdentifier("Handle"))));
                    }
                    else
                    {
                        body.Add(CSReturn.ReturnLine(csharpCall.Dot(NewClassCompiler.kSwiftObjectGetter)));
                    }
                }
                else if (returnIsStructOrEnum || returnIsTuple || returnIsGeneric)
                {
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                    var    retvalId   = new CSIdentifier(retvalName);
                    body.Add(CSFieldDeclaration.VarLine(methodType, retvalId, csharpCall));
                    if (returnIsGeneric)
                    {
                        body.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                 methodType.Typeof(), retvalId, delegateParams [0].Name));
                    }
                    else
                    {
                        body.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                 retvalId, delegateParams [0].Name));
                    }
                }
                else if (returnIsProtocol)
                {
                    string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                    identifiersUsed.Add(retvalName);
                    var retvalId = new CSIdentifier(retvalName);
                    body.Add(CSFieldDeclaration.VarLine(methodType, retvalId, csharpCall));
                    var protocolMaker = new CSFunctionCall("SwiftExistentialContainer1", true,
                                                           new CSFunctionCall("SwiftObjectRegistry.Registry.ExistentialContainerForProtocols", false, retvalId, methodType.Typeof()));
                    body.Add(CSReturn.ReturnLine(protocolMaker));
                }
                else if (returnIsProtocolList)
                {
                    var protoTypeOf    = new List <CSBaseExpression> ();
                    var swiftProtoList = funcDecl.ReturnTypeSpec as ProtocolListTypeSpec;
                    foreach (var swiftProto in swiftProtoList.Protocols.Keys)
                    {
                        protoTypeOf.Add(typeMapper.MapType(funcDecl, swiftProto, false).ToCSType(use).Typeof());
                    }
                    var callExprs = new List <CSBaseExpression> ();
                    callExprs.Add(csharpCall);
                    callExprs.AddRange(protoTypeOf);
                    var retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                    identifiersUsed.Add(retvalName);
                    var retvalId = new CSIdentifier(retvalName);
                    body.Add(CSVariableDeclaration.VarLine(methodType, retvalId, new CSFunctionCall("StructMarshal.ThrowIfNotImplementsAll", false, callExprs.ToArray())));
                    var containerExprs = new List <CSBaseExpression> ();
                    containerExprs.Add(retvalId);
                    containerExprs.AddRange(protoTypeOf);

                    var returnContainerName = MarshalEngine.Uniqueify("returnContainer", identifiersUsed);
                    identifiersUsed.Add(returnContainerName);
                    var returnContainerId = new CSIdentifier(returnContainerName);
                    body.Add(CSVariableDeclaration.VarLine(CSSimpleType.Var, returnContainerId, new CSFunctionCall("SwiftObjectRegistry.Registry.ExistentialContainerForProtocols", false, containerExprs.ToArray())));
                    body.Add(CSFunctionCall.FunctionCallLine($"{returnContainerName}.CopyTo", false, new CSUnaryExpression(CSUnaryOperator.Ref, delegateParams [0].Name)));
                }
                else
                {
                    if (returnIsClosure)
                    {
                        body.Add(CSReturn.ReturnLine(MarshalEngine.BuildBlindClosureCall(csharpCall, methodType as CSSimpleType, use)));
                    }
                    else
                    {
                        body.Add(CSReturn.ReturnLine(csharpCall));
                    }
                }
            }
            else
            {
                CSBaseExpression valueExpr      = null;
                bool             valueIsGeneric = funcDecl.IsTypeSpecGeneric(funcDecl.ParameterLists [1] [0].TypeSpec);
                entity = !valueIsGeneric?typeMapper.GetEntityForTypeSpec(funcDecl.ParameterLists [1] [0].TypeSpec) : null;

                entityType = !valueIsGeneric?typeMapper.GetEntityTypeForTypeSpec(funcDecl.ParameterLists [1] [0].TypeSpec) : EntityType.None;

                var isUnusualNewValue = IsUnusualParameter(entity, delegateParams [1]);

                if (entityType == EntityType.Class || (entity != null && entity.IsObjCProtocol))
                {
                    var csParmType = delegateParams [1].CSType as CSSimpleType;
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 42, "Inconceivable! The class type for a method was a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));
                    var fullClassName = entity.Type.ToFullyQualifiedName(true);
                    var retrievecall  = NewClassCompiler.SafeMarshalClassFromIntPtr(delegateParams [1].Name, csParmType, use, fullClassName, typeMapper, entity.IsObjCProtocol);
                    valueExpr = retrievecall;
                }
                else if (entityType == EntityType.Protocol)
                {
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));
                    var retrievecall = new CSFunctionCall($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisType.ToString ()}> (self).{prop.Name.Name}", false);
                    valueExpr = retrievecall;
                }
                else if (entityType == EntityType.Tuple || (entity != null && entity.IsStructOrEnum && !isUnusualNewValue))
                {
                    var ntb     = typeMapper.MapType(funcDecl, funcDecl.ParameterLists [1] [0].TypeSpec, false);
                    var valType = ntb.ToCSType(use);
                    if (entityType == EntityType.TrivialEnum)
                    {
                        valueExpr = new CSCastExpression(valType, new CSCastExpression(CSSimpleType.Long, delegateParams [1].Name));
                    }
                    else
                    {
                        var marshalCall = new CSFunctionCall("StructMarshal.Marshaler.ToNet", false, delegateParams [1].Name, valType.Typeof());
                        valueExpr = new CSCastExpression(valType, marshalCall);
                    }
                }
                else if (valueIsGeneric)
                {
                    // T someVal = (T)StructMarshal.Marshaler.ToNet(parm, typeof(T));
                    // someVal gets passed in
                    var depthIndex = funcDecl.GetGenericDepthAndIndex(funcDecl.ParameterLists [1] [0].TypeSpec);
                    var genRef     = new CSGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify(delegateParams [1].Name + "Temp", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(genRef, valMarshalId,
                                                                new CSCastExpression(genRef, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false,
                                                                                                                delegateParams [1].Name,
                                                                                                                genRef.Typeof())));
                    body.Add(valDecl);
                    valueExpr = valMarshalId;
                }
                else
                {
                    if (entityType == EntityType.Closure)
                    {
                        valueExpr = MarshalEngine.BuildWrappedClosureCall(delegateParams [1].Name, methodType as CSSimpleType);
                    }
                    else
                    {
                        valueExpr = delegateParams [1].Name;
                    }
                }
                body.Add(CSAssignment.Assign(csharpCall, valueExpr));
            }
            return(body);
        }
        public List <ICodeElement> MarshalFromLambdaReceiverToCSFunc(CSType thisType, string csProxyName, CSParameterList delegateParams,
                                                                     FunctionDeclaration funcDecl, CSType methodType, CSParameterList methodParams, string methodName, bool isObjC)
        {
            bool thisIsInterface = csProxyName != null;
            bool isIndexer       = funcDecl.IsSubscript;
            bool needsReturn     = methodType != null && methodType != CSSimpleType.Void;
            bool isSetter        = funcDecl.IsSubscriptSetter;
            bool returnIsGeneric = funcDecl.IsTypeSpecGeneric(funcDecl.ReturnTypeSpec);

            var entity = !returnIsGeneric?typeMapper.GetEntityForTypeSpec(funcDecl.ReturnTypeSpec) : null;

            var returnEntity = entity;
            var entityType   = !returnIsGeneric?typeMapper.GetEntityTypeForTypeSpec(funcDecl.ReturnTypeSpec) : EntityType.None;

            bool returnIsStruct   = needsReturn && entity != null && entity.IsStructOrEnum;
            bool returnIsClass    = needsReturn && entity != null && entity.EntityType == EntityType.Class;
            bool returnIsProtocol = needsReturn && ((entity != null && entity.EntityType == EntityType.Protocol) || entityType == EntityType.ProtocolList);
            bool returnIsTuple    = needsReturn && entityType == EntityType.Tuple;
            bool returnIsClosure  = needsReturn && entityType == EntityType.Closure;

            var callParams                    = new List <CSBaseExpression> ();
            var preMarshalCode                = new List <CSLine> ();
            var postMarshalCode               = new List <CSLine> ();
            CSBaseExpression valueExpr        = null;
            bool             marshalingThrows = false;


            if (isSetter)
            {
                var valueID = delegateParams [1].Name;
                valueExpr = valueID;
                var  swiftNewValue     = funcDecl.ParameterLists [1] [0];
                bool newValueIsGeneric = funcDecl.IsTypeSpecGeneric(funcDecl.PropertyType);
                entity = !newValueIsGeneric?typeMapper.GetEntityForTypeSpec(swiftNewValue.TypeSpec) : null;

                entityType = !newValueIsGeneric?typeMapper.GetEntityTypeForTypeSpec(swiftNewValue.TypeSpec) : EntityType.None;

                var isUnusualNewValue = IsUnusualParameter(entity, delegateParams [1]);

                if (entityType == EntityType.Class || entity.IsObjCProtocol)
                {
                    var csParmType = new CSSimpleType(entity.SharpNamespace + "." + entity.SharpTypeName);
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 26, "Inconceivable! The class type for a subscript was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));

                    var fullClassName = entity.Type.ToFullyQualifiedName(true);
                    valueExpr = NewClassCompiler.SafeMarshalClassFromIntPtr(valueID, csParmType, use, fullClassName, typeMapper, entity.IsObjCProtocol);
                }
                else if (entityType == EntityType.Protocol)
                {
                    var csParmType = new CSSimpleType(entity.SharpNamespace + "." + entity.SharpTypeName);
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 27, "Inconceivable! The protocol type for a subscript was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));
                    valueExpr = new CSFunctionCall($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{csParmType.ToString ()}>", false, valueID);
                }
                else if ((entityType == EntityType.Struct || entityType == EntityType.Enum) && !isUnusualNewValue)
                {
                    var csParmType = new CSSimpleType(entity.SharpNamespace + "." + entity.SharpTypeName);
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 28, $"Inconceivable! The {entityType} type for a subscript was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify("val", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    CSLine valDecl = CSVariableDeclaration.VarLine(csParmType, valMarshalId,
                                                                   new CSCastExpression(csParmType, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false, valueID,
                                                                                                                       csParmType.Typeof())));
                    preMarshalCode.Add(valDecl);
                    valueExpr = valMarshalId;
                }
                else if (entityType == EntityType.Tuple)
                {
                    var csParmType = new CSSimpleType(entity.SharpNamespace + "." + entity.SharpTypeName);
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 29, "Inconceivable! The tuple type for a subscript was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify("val", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(csParmType, valMarshalId,
                                                                new CSCastExpression(csParmType, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false, valueID,
                                                                                                                    csParmType.Typeof())));
                    preMarshalCode.Add(valDecl);
                    valueExpr = valMarshalId;
                }
                else if (newValueIsGeneric)
                {
                    var depthIndex = funcDecl.GetGenericDepthAndIndex(swiftNewValue.TypeSpec);
                    var genRef     = new CSGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                    if (genRef == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 30, "Inconceivable! The generic type for a parameter in a method was NOT a CSGenericReferenceType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify("valTemp", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(genRef, valMarshalId,
                                                                new CSCastExpression(genRef, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false,
                                                                                                                valueID, genRef.Typeof())));
                    preMarshalCode.Add(valDecl);
                    valueExpr = valMarshalId;
                }
            }

            int j = 0;
            int k = isSetter ? 1 : 0;

            for (int i = (funcDecl.HasThrows || returnIsStruct || returnIsProtocol || isSetter || returnIsGeneric) ? 2 : 1; i < delegateParams.Count; i++, j++, k++)
            {
                var  swiftParm     = funcDecl.ParameterLists [1] [k];
                bool parmIsGeneric = funcDecl.IsTypeSpecGeneric(swiftParm);
                entity = !parmIsGeneric?typeMapper.GetEntityForTypeSpec(swiftParm.TypeSpec) : null;

                entityType = !parmIsGeneric?typeMapper.GetEntityTypeForTypeSpec(swiftParm.TypeSpec) : EntityType.None;

                var isUnusualParameter = IsUnusualParameter(entity, delegateParams [i]);
                var csParm             = methodParams [j];

                if (entityType == EntityType.Class || (entity != null && entity.IsObjCProtocol))
                {
                    var csParmType = csParm.CSType as CSSimpleType;
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 31, "Inconceivable! The class type for a method was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));

                    var fullClassName = entity.Type.ToFullyQualifiedName(true);
                    var retrievecall  = NewClassCompiler.SafeMarshalClassFromIntPtr(delegateParams [0].Name, csParmType, use, fullClassName, typeMapper, entity.IsObjCProtocol);
                    if (csParm.ParameterKind == CSParameterKind.Out || csParm.ParameterKind == CSParameterKind.Ref)
                    {
                        string id = MarshalEngine.Uniqueify(delegateParams [i].Name.Name, identifiersUsed);
                        identifiersUsed.Add(id);
                        preMarshalCode.Add(CSFieldDeclaration.FieldLine(csParmType, id, retrievecall));
                        callParams.Add(new CSIdentifier(String.Format("{0} {1}",
                                                                      csParm.ParameterKind == CSParameterKind.Out ? "out" : "ref", id)));
                        postMarshalCode.Add(CSAssignment.Assign(delegateParams [i].Name,
                                                                NewClassCompiler.SafeBackingFieldAccessor(new CSIdentifier(id), use, entity.Type.ToFullyQualifiedName(true), typeMapper)));
                    }
                    else
                    {
                        callParams.Add(retrievecall);
                    }
                }
                else if (entityType == EntityType.Protocol)
                {
                    var thePtr     = new CSIdentifier(MarshalEngine.Uniqueify("p", identifiersUsed));
                    var csParmType = csParm.CSType as CSSimpleType;
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 32, "Inconceivable! The protocol type for a method was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(SwiftObjectRegistry));
                    string csParmProxyType = NewClassCompiler.CSProxyNameForProtocol(entity.Type.ToFullyQualifiedName(true), typeMapper);
                    if (csParmProxyType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 33, $"Unable to find C# interface type for protocol {entity.Type.ToFullyQualifiedName ()}");
                    }

                    var retrievecall = new CSFunctionCall($"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{csParmType.Name}>", false, delegateParams [i].Name);
                    if (csParm.ParameterKind == CSParameterKind.Out || csParm.ParameterKind == CSParameterKind.Ref)
                    {
                        CSIdentifier id = new CSIdentifier(MarshalEngine.Uniqueify(delegateParams [i].Name.Name, identifiersUsed));
                        identifiersUsed.Add(id.Name);
                        preMarshalCode.Add(CSFieldDeclaration.FieldLine(csParmType, id.Name, retrievecall));
                        callParams.Add(new CSIdentifier(String.Format("{0} {1}",
                                                                      csParm.ParameterKind == CSParameterKind.Out ? "out" : "ref", id)));
                        postMarshalCode.Add(CSAssignment.Assign(delegateParams [i].Name,
                                                                new CSFunctionCall("SwiftExistentialContainer1", true,
                                                                                   new CSFunctionCall("SwiftObjectRegistry.Registry.ExistentialContainerForProtocol", false, id, csParmType.Typeof()))));
                    }
                    else
                    {
                        callParams.Add(retrievecall);
                    }
                }
                else if ((entityType == EntityType.Struct || entityType == EntityType.Enum) && !isUnusualParameter)
                {
                    var csParmType = csParm.CSType as CSSimpleType;
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 34, $"Inconceivable! The {entityType} type for a method was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify(delegateParams [i].Name + "Temp", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(csParmType, valMarshalId,
                                                                new CSCastExpression(csParmType, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false, delegateParams [i].Name,
                                                                                                                    csParmType.Typeof())));
                    preMarshalCode.Add(valDecl);
                    callParams.Add(valMarshalId);
                }
                else if (entityType == EntityType.Tuple)
                {
                    var csParmType = csParm.CSType as CSSimpleType;
                    if (csParmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 35, "Inconceivable! The tuple type for a parameter in a method was NOT a CSSimpleType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify(delegateParams [i].Name + "Temp", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(csParmType, valMarshalId,
                                                                new CSCastExpression(csParmType, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false, delegateParams [i].Name,
                                                                                                                    csParmType.Typeof())));
                    preMarshalCode.Add(valDecl);
                    callParams.Add(valMarshalId);
                }
                else if (entityType == EntityType.Closure)
                {
                    // parm is a SwiftClosureRepresentation
                    // (FuncType)StructMarshal.Marshaler.MakeDelegateFromBlindClosure (arg, argTypes, returnType);
                    var argTypesId = new CSIdentifier(MarshalEngine.Uniqueify("argTypes" + delegateParams [i], identifiersUsed));
                    identifiersUsed.Add(argTypesId.Name);
                    var parmType = csParm.CSType as CSSimpleType;
                    if (parmType == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 44, "Inconceivable! The type for a closure should be a CSSimpleType");
                    }
                    var hasReturn      = parmType.GenericTypeName == "Func";
                    var returnType     = hasReturn ? (CSBaseExpression)parmType.GenericTypes [parmType.GenericTypes.Length - 1].Typeof() : CSConstant.Null;
                    var argTypesLength = hasReturn ? parmType.GenericTypes.Length - 1 : parmType.GenericTypes.Length;
                    var argTypes       = new CSBaseExpression [argTypesLength];
                    for (int idx = 0; idx < argTypesLength; idx++)
                    {
                        argTypes [idx] = parmType.GenericTypes [idx].Typeof();
                    }
                    var typeArr = new CSArray1DInitialized(CSSimpleType.Type, argTypes);

                    var closureExpr = new CSFunctionCall("StructMarshal.Marshaler.MakeDelegateFromBlindClosure", false, delegateParams [i].Name,
                                                         typeArr, returnType);
                    var castTo = new CSCastExpression(csParm.CSType, closureExpr);
                    callParams.Add(castTo);
                }
                else if (entityType == EntityType.ProtocolList)
                {
                    preMarshalCode.Add(CSFunctionCall.FunctionCallLine("throw new NotImplementedException", false, CSConstant.Val($"Argument {csParm.Name} is a protocol list type and can't be marshaled from a virtual method.")));
                    callParams.Add(CSConstant.Null);
                    marshalingThrows = true;
                }
                else if (parmIsGeneric)
                {
                    // parm is an IntPtr to some T
                    // to get T, we ask funcDecl for the depthIndex of T
                    // T someVal = (T)StructMarshal.Marshaler.ToNet(parm, typeof(T));
                    // someVal gets passed in
                    var genRef = csParm.CSType as CSGenericReferenceType;
                    if (genRef == null)
                    {
                        throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 36, "Inconceivable! The generic type for a parameter in a method was NOT a CSGenericReferenceType!");
                    }
                    use.AddIfNotPresent(typeof(StructMarshal));
                    string valMarshalName = MarshalEngine.Uniqueify(delegateParams [i].Name + "Temp", identifiersUsed);
                    var    valMarshalId   = new CSIdentifier(valMarshalName);

                    var valDecl = CSVariableDeclaration.VarLine(genRef, valMarshalId,
                                                                new CSCastExpression(genRef, new CSFunctionCall("StructMarshal.Marshaler.ToNet", false,
                                                                                                                delegateParams [i].Name,
                                                                                                                genRef.Typeof())));
                    preMarshalCode.Add(valDecl);
                    callParams.Add(valMarshalId);
                }
                else
                {
                    if (csParm.ParameterKind == CSParameterKind.Out || csParm.ParameterKind == CSParameterKind.Ref)
                    {
                        callParams.Add(new CSIdentifier(String.Format("{0} {1}",
                                                                      csParm.ParameterKind == CSParameterKind.Out ? "out" : "ref", delegateParams [i].Name.Name)));
                    }
                    else
                    {
                        callParams.Add(delegateParams [i].Name);
                    }
                }
            }

            var body = new CSCodeBlock();

            if (isObjC)
            {
                use.AddIfNotPresent("ObjCRuntime");
            }
            else
            {
                use.AddIfNotPresent(typeof(SwiftObjectRegistry));
            }


            CSBaseExpression invoker = null;

            if (isIndexer)
            {
                if (thisIsInterface)
                {
                    invoker = new CSIndexExpression(
                        $"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisType.ToString ()}> (self)",
                        false, callParams.ToArray());
                }
                else
                {
                    var registryCall = isObjC ?
                                       $"Runtime.GetNSObject<{thisType.ToString ()}> (self)" :
                                       $"SwiftObjectRegistry.Registry.CSObjectForSwiftObject <{thisType.ToString ()}> (self)";
                    invoker = new CSIndexExpression(registryCall, false, callParams.ToArray());
                }
            }
            else
            {
                if (thisIsInterface)
                {
                    invoker = new CSFunctionCall(
                        $"SwiftObjectRegistry.Registry.InterfaceForExistentialContainer<{thisType.ToString ()}> (self).{methodName}",
                        false, callParams.ToArray());
                }
                else
                {
                    var registryCall = isObjC ?
                                       $"Runtime.GetNSObject<{thisType.ToString ()}>(self).{methodName}" :
                                       $"SwiftObjectRegistry.Registry.CSObjectForSwiftObject <{thisType.ToString ()}> (self).{methodName}";
                    invoker = new CSFunctionCall(registryCall, false, callParams.ToArray());
                }
            }

            var    tryBlock   = funcDecl.HasThrows ? new CSCodeBlock() : null;
            var    catchBlock = funcDecl.HasThrows ? new CSCodeBlock() : null;
            var    altBody    = tryBlock ?? body;
            string catchName  = MarshalEngine.Uniqueify("e", identifiersUsed);
            var    catchID    = new CSIdentifier(catchName);


            altBody.AddRange(preMarshalCode);
            if (marshalingThrows)
            {
                return(altBody);
            }

            if (funcDecl.HasThrows || needsReturn)               // function that returns or getter
            {
                if (funcDecl.HasThrows)
                {
                    use.AddIfNotPresent(typeof(SwiftError));
                    use.AddIfNotPresent(typeof(Tuple));
                    use.AddIfNotPresent(typeof(StructMarshal));
                    CSType returnTuple = null;
                    if (needsReturn)
                    {
                        returnTuple = new CSSimpleType("Tuple", false,
                                                       methodType,
                                                       new CSSimpleType(typeof(SwiftError)),
                                                       CSSimpleType.Bool);
                    }
                    else
                    {
                        returnTuple = new CSSimpleType("Tuple", false,
                                                       new CSSimpleType(typeof(SwiftError)),
                                                       CSSimpleType.Bool);
                    }


                    if (needsReturn)
                    {
                        string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                        var    retvalId   = new CSIdentifier(retvalName);
                        altBody.Add(CSFieldDeclaration.VarLine(methodType, retvalId, invoker));
                        postMarshalCode.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                            methodType.Typeof(),
                                                                            retvalId,
                                                                            delegateParams [0].Name));
                        altBody.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.SetErrorNotThrown", false,
                                                                    delegateParams [0].Name, returnTuple.Typeof()));
                    }
                    else
                    {
                        if (isSetter)
                        {
                            altBody.Add(CSAssignment.Assign(invoker, CSAssignmentOperator.Assign, valueExpr));
                        }
                        else
                        {
                            altBody.Add(new CSLine(invoker));
                        }
                        altBody.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.SetErrorNotThrown", false,
                                                                    delegateParams [0].Name, returnTuple.Typeof()));
                    }
                    string swiftError           = MarshalEngine.Uniqueify("err", identifiersUsed);
                    var    swiftErrorIdentifier = new CSIdentifier(swiftError);
                    catchBlock.Add(CSFieldDeclaration.VarLine(new CSSimpleType(typeof(SwiftError)), swiftErrorIdentifier,
                                                              new CSFunctionCall("SwiftError.FromException", false, catchID)));
                    catchBlock.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.SetErrorThrown", false,
                                                                   delegateParams [0].Name,
                                                                   swiftErrorIdentifier,
                                                                   returnTuple.Typeof()));
                }
                else
                {
                    if (returnIsClass)
                    {
                        string       retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                        CSIdentifier retvalId   = new CSIdentifier(retvalName);
                        altBody.Add(CSFieldDeclaration.VarLine(methodType, retvalId, invoker));
                        postMarshalCode.Add(CSReturn.ReturnLine(
                                                NewClassCompiler.SafeBackingFieldAccessor(retvalId, use, returnEntity.Type.ToFullyQualifiedName(), typeMapper)));
                    }
                    else if (returnIsProtocol)
                    {
                        string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                        identifiersUsed.Add(retvalName);
                        var retvalId = new CSIdentifier(retvalName);
                        altBody.Add(CSFieldDeclaration.VarLine(methodType, retvalId, invoker));
                        var returnContainer = MarshalEngine.Uniqueify("returnContainer", identifiersUsed);
                        identifiersUsed.Add(returnContainer);
                        var returnContainerId = new CSIdentifier(returnContainer);
                        var protoGetter       = new CSFunctionCall($"SwiftObjectRegistry.Registry.ExistentialContainerForProtocols", false, retvalId, methodType.Typeof());
                        var protoDecl         = CSVariableDeclaration.VarLine(CSSimpleType.Var, returnContainerId, protoGetter);
                        var marshalBack       = CSFunctionCall.FunctionCallLine($"{returnContainer}.CopyTo", delegateParams [0].Name);
                        postMarshalCode.Add(protoDecl);
                        postMarshalCode.Add(marshalBack);
                    }
                    else if (returnIsStruct)
                    {
                        // non-blitable means that the parameter is an IntPtr and we can call the
                        // marshaler to copy into it
                        use.AddIfNotPresent(typeof(StructMarshal));
                        var marshalCall = CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                          invoker, delegateParams [0].Name);
                        altBody.Add(marshalCall);
                    }
                    else if (returnIsTuple)
                    {
                        // non-blitable means that the parameter is an IntPtr and we can call the
                        // marshaler to copy into it
                        use.AddIfNotPresent(typeof(StructMarshal));
                        var marshalCall = CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                          invoker, delegateParams [0].Name);
                        altBody.Add(marshalCall);
                    }
                    else if (returnIsGeneric)
                    {
                        // T retval = invoker();
                        // if (retval is ISwiftObject) {
                        //     Marshal.WriteIntPtr(delegateParams [0].Name, ((ISwiftObject)retval).SwiftObject);
                        // }
                        // else {
                        //    StructMarshal.Marshaler.ToSwift(typeof(T), retval, delegateParams[0].Name);
                        // }
                        string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                        var    retvalId   = new CSIdentifier(retvalName);
                        altBody.Add(CSFieldDeclaration.VarLine(methodType, retvalId, invoker));
                        var ifClause = new CSCodeBlock();
                        ifClause.Add(CSFunctionCall.FunctionCallLine("Marshal.WriteIntPtr", false,
                                                                     delegateParams [0].Name,
                                                                     new CSParenthesisExpression(new CSCastExpression("ISwiftObject", retvalId)).Dot(NewClassCompiler.kSwiftObjectGetter)));
                        var elseClause = new CSCodeBlock();
                        elseClause.Add(CSFunctionCall.FunctionCallLine("StructMarshal.Marshaler.ToSwift", false,
                                                                       methodType.Typeof(),
                                                                       retvalId,
                                                                       delegateParams [0].Name));
                        CSBaseExpression ifExpr = new CSSimpleType("ISwiftObject").Typeof().Dot(new CSFunctionCall("IsAssignableFrom", false,
                                                                                                                   methodType.Typeof()));

                        var retTest = new CSIfElse(ifExpr, ifClause, elseClause);
                        altBody.Add(retTest);
                    }
                    else
                    {
                        if (returnIsClosure)
                        {
                            invoker = MarshalEngine.BuildBlindClosureCall(invoker, methodType as CSSimpleType, use);
                        }
                        if (postMarshalCode.Count > 0)
                        {
                            string       retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                            CSIdentifier retvalId   = new CSIdentifier(retvalName);
                            altBody.Add(CSFieldDeclaration.VarLine(methodType, retvalId, invoker));
                            postMarshalCode.Add(CSReturn.ReturnLine(retvalId));
                        }
                        else
                        {
                            altBody.Add(CSReturn.ReturnLine(invoker));
                        }
                    }
                }
            }
            else                 // no return or setter
            {
                if (isSetter)
                {
                    altBody.Add(CSAssignment.Assign(invoker, CSAssignmentOperator.Assign, valueExpr));
                }
                else
                {
                    altBody.Add(new CSLine(invoker));
                }
            }
            altBody.AddRange(postMarshalCode);

            if (funcDecl.HasThrows)
            {
                body.Add(new CSTryCatch(tryBlock, new CSCatch(typeof(Exception), catchName, catchBlock)));
            }
            return(body);
        }
        public IEnumerable <ICodeElement> MarshalFunctionCall(FunctionDeclaration func, string vtableName, string vtableElementName)
        {
            preMarshalCode.Clear();
            postMarshalCode.Clear();
            ICodeElement returnLine         = null;
            var          instanceEntity     = typeMapper.GetEntityForTypeSpec(func.ParameterLists [0] [0].TypeSpec);
            bool         instanceIsProtocol = instanceEntity.EntityType == EntityType.Protocol;
            //			bool returnIsGeneric = func.ReturnTypeSpec != null && func.IsGenericType(func.ReturnTypeSpec);
            SLIdentifier returnIdent = null;

            if (func.ParameterLists.Count != 2)
            {
                throw new ArgumentException(String.Format("Method {0} is has {1} parameter lists - it should really have two (normal for an instance method).",
                                                          func.ToFullyQualifiedName(true), func.ParameterLists.Count));
            }

            var closureArgs = new List <SLBaseExpr> ();


            // marshal the regular arguments
            for (int i = 0; i < func.ParameterLists [1].Count; i++)
            {
                var parm        = func.ParameterLists [1] [i];
                var privateName = !String.IsNullOrEmpty(parm.PrivateName) ? parm.PrivateName : TypeSpecToSLType.ConjureIdentifier(null, i).Name;
                if (func.IsTypeSpecGeneric(parm))
                {
                    Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(parm.TypeSpec);
                    closureArgs.Add(MarshalGenericTypeSpec(func, privateName, parm.TypeSpec as NamedTypeSpec, depthIndex.Item1, depthIndex.Item2));
                }
                else
                {
                    closureArgs.Add(MarshalTypeSpec(func, privateName, parm.TypeSpec));
                }
            }
            string callName       = String.Format("{0}.{1}", vtableName, vtableElementName);
            var    callInvocation = new SLPostBang(new SLIdentifier(callName), false);

            if (instanceIsProtocol)
            {
                string protoName = MarshalEngine.Uniqueify("selfProto", identifiersUsed);
                identifiersUsed.Add(protoName);
                var selfProtoDecl = new SLDeclaration(false,
                                                      new SLBinding(protoName, new SLIdentifier("self"), new SLSimpleType(func.ParameterLists [0] [0].TypeName.NameWithoutModule())),
                                                      Visibility.None);
                preMarshalCode.Add(new SLLine(selfProtoDecl));
                closureArgs.Insert(0, new SLAddressOf(new SLIdentifier(protoName), false));
            }
            else
            {
                // add self as a parameter
                imports.AddIfNotPresent("XamGlue");
                closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), new SLIdentifier("self"), true)));
            }

            string       throwReturnName = null;
            SLIdentifier throwReturn     = null;
            SLType       throwReturnType = null;

            throwReturnType = new SLTupleType(
                new SLNameTypePair(SLParameterKind.None, "_", func.ReturnTypeSpec == null || func.ReturnTypeSpec.IsEmptyTuple ?
                                   SLSimpleType.Void : typeMapper.TypeSpecMapper.MapType(func, imports, func.ReturnTypeSpec, true)),
                new SLNameTypePair(SLParameterKind.None, "_", new SLSimpleType("Swift.Error")),
                new SLNameTypePair(SLParameterKind.None, "_", new SLSimpleType("Bool")));

            if (func.HasThrows)
            {
                throwReturnName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                identifiersUsed.Add(throwReturnName);
                throwReturn = new SLIdentifier(throwReturnName);
                imports.AddIfNotPresent("XamGlue");
                // FIXME for generics
                var throwReturnDecl = new SLDeclaration(true, new SLBinding(throwReturn,
                                                                            new SLFunctionCall(String.Format("UnsafeMutablePointer<{0}>.allocate", throwReturnType.ToString()),
                                                                                               false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true))), Visibility.None);
                closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), throwReturn, true)));
                preMarshalCode.Add(new SLLine(throwReturnDecl));
            }


            if (func.HasThrows)
            {
                returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)));
                string errName = MarshalEngine.Uniqueify("err", identifiersUsed);
                identifiersUsed.Add(errName);
                var errIdent = new SLIdentifier(errName);
                var errDecl  = new SLDeclaration(true, new SLBinding(errIdent, new SLFunctionCall("getExceptionThrown", false,
                                                                                                  new SLArgument(new SLIdentifier("retval"), throwReturn, true))), Visibility.None);
                postMarshalCode.Add(new SLLine(errDecl));
                var         ifblock   = new SLCodeBlock(null);
                SLCodeBlock elseblock = null;

                ifblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deinitialize", new SLArgument(new SLIdentifier("count"), SLConstant.Val(1), true)));
                ifblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deallocate"));
                ifblock.Add(new SLLine(new SLThrow(new SLPostBang(errIdent, false))));


                if (func.ReturnTypeSpec != null && !func.ReturnTypeSpec.IsEmptyTuple)
                {
                    elseblock = new SLCodeBlock(null);
                    string retvalvalName = MarshalEngine.Uniqueify("retvalval", identifiersUsed);
                    identifiersUsed.Add(retvalvalName);
                    SLIdentifier retvalval     = new SLIdentifier(retvalvalName);
                    string       tuplecracker  = "getExceptionNotThrown";
                    var          retvalvaldecl =
                        new SLDeclaration(true, new SLBinding(retvalval,
                                                              new SLFunctionCall(tuplecracker, false,
                                                                                 new SLArgument(new SLIdentifier("retval"), throwReturn, true))), Visibility.None);
                    elseblock.Add(new SLLine(retvalvaldecl));
                    elseblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deallocate"));
                    ISLExpr returnExpr = new SLPostBang(retvalval, false);
                    elseblock.Add(SLReturn.ReturnLine(returnExpr));
                }
                postMarshalCode.Add(new SLIfElse(new SLBinaryExpr(BinaryOp.NotEqual, errIdent, SLConstant.Nil),
                                                 ifblock, elseblock));
            }
            else
            {
                if (func.ReturnTypeSpec == null || func.ReturnTypeSpec.IsEmptyTuple)
                {
                    // On no return value
                    // _vtable.entry!(args)
                    //
                    returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)));
                }
                else
                {
                    if (TypeSpec.IsBuiltInValueType(func.ReturnTypeSpec))
                    {
                        // on simple return types (Int, UInt, Bool, etc)
                        // return _vtable.entry!(args)
                        //
                        var closureCall = new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs));
                        if (postMarshalCode.Count == 0)
                        {
                            returnLine = SLReturn.ReturnLine(closureCall);
                        }
                        else
                        {
                            returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed));
                            identifiersUsed.Add(returnIdent.Name);
                            var retvalDecl = new SLDeclaration(true, returnIdent, null, closureCall, Visibility.None);
                            returnLine = new SLLine(retvalDecl);
                            postMarshalCode.Add(SLReturn.ReturnLine(returnIdent));
                        }
                    }
                    else
                    {
                        if (func.IsTypeSpecGeneric(func.ReturnTypeSpec))
                        {
                            imports.AddIfNotPresent("XamGlue");
                            // dealing with a generic here.
                            // UnsafeMutablePointer<T> retval = UnsafeMutablePointer<T>.alloc(1)
                            // someCall(toIntPtr(retval), ...)
                            // T actualRetval = retval.move()
                            // retval.dealloc(1)
                            // return actualRetval
                            returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed));
                            identifiersUsed.Add(returnIdent.Name);
                            Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(func.ReturnTypeSpec);
                            var retvalDecl = new SLDeclaration(true, returnIdent, null,
                                                               new SLFunctionCall(String.Format("UnsafeMutablePointer<{0}>.allocate", SLGenericReferenceType.DefaultNamer(depthIndex.Item1, depthIndex.Item2)),
                                                                                  false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true)),
                                                               Visibility.None);
                            preMarshalCode.Add(new SLLine(retvalDecl));
                            closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), returnIdent, true)));
                            SLIdentifier actualReturnIdent = new SLIdentifier(MarshalEngine.Uniqueify("actualRetval", identifiersUsed));
                            identifiersUsed.Add(actualReturnIdent.Name);

                            returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)));

                            var actualRetvalDecl = new SLDeclaration(true, actualReturnIdent, null,
                                                                     new SLFunctionCall(String.Format("{0}.move", returnIdent.Name), false),
                                                                     Visibility.None);
                            postMarshalCode.Add(new SLLine(actualRetvalDecl));
                            postMarshalCode.Add(SLFunctionCall.FunctionCallLine(String.Format("{0}.deallocate", returnIdent.Name)));
                            postMarshalCode.Add(SLReturn.ReturnLine(actualReturnIdent));
                        }
                        else if (NamedSpecIsClass(func.ReturnTypeSpec as NamedTypeSpec))
                        {
                            // class (not struct or enum) return type is a pointer
                            // if we have no post marshal code:
                            // return fromIntPtr(_vtable.entry!(args))
                            // if we have post marshal code:
                            // let retval:returnType = fromIntPtr(_vtable.entry!(args))
                            // ... post marshal code
                            // return retval;
                            imports.AddIfNotPresent("XamGlue");
                            SLBaseExpr callExpr = new SLFunctionCall("fromIntPtr", false,
                                                                     new SLArgument(new SLIdentifier("ptr"), new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)), true));
                            if (postMarshalCode.Count > 0)
                            {
                                string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                                var    retDecl    = new SLDeclaration(true, retvalName,
                                                                      typeMapper.TypeSpecMapper.MapType(func, imports, func.ReturnTypeSpec, true), callExpr);
                                returnLine = new SLLine(retDecl);
                                postMarshalCode.Add(SLReturn.ReturnLine(new SLIdentifier(retvalName)));
                            }
                            else
                            {
                                returnLine = SLReturn.ReturnLine(callExpr);
                            }
                        }
                        else
                        {
                            var entity = typeMapper.GetEntityForTypeSpec(func.ReturnTypeSpec);
                            if (func.ReturnTypeSpec is NamedTypeSpec && entity == null)
                            {
                                throw new NotImplementedException($"Function {func.ToFullyQualifiedName (true)} has an unknown return type {func.ReturnTypeSpec.ToString ()}");
                            }
                            if (entity?.EntityType == EntityType.TrivialEnum)
                            {
                                imports.AddIfNotPresent(entity.Type.Module.Name);
                                var        slSelf   = new SLIdentifier($"{entity.Type.Name}.self");
                                SLBaseExpr callExpr = new SLFunctionCall("unsafeBitCast", false,
                                                                         new SLArgument(new SLIdentifier("_"), new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)), false),
                                                                         new SLArgument(new SLIdentifier("to"), slSelf, true));
                                if (postMarshalCode.Count == 0)
                                {
                                    returnLine = SLReturn.ReturnLine(callExpr);
                                }
                                else
                                {
                                    returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed));
                                    identifiersUsed.Add(returnIdent.Name);
                                    var retvalDecl = new SLDeclaration(true, returnIdent, null, callExpr, Visibility.None);
                                    returnLine = new SLLine(retvalDecl);
                                    postMarshalCode.Add(SLReturn.ReturnLine(returnIdent));
                                }
                            }
                            else
                            {
                                switch (func.ReturnTypeSpec.Kind)
                                {
                                case TypeSpecKind.Closure:

                                    // let retval:CT = allocSwiftClosureToFunc_ARGS ()
                                    // _vtable.entry!(retval, args)
                                    // let actualReturn = netFuncToSwiftClosure (retval.move())
                                    // retval.deallocate()
                                    // return actualReturn

                                    var ct      = func.ReturnTypeSpec as ClosureTypeSpec;
                                    var slct    = new SLBoundGenericType("UnsafeMutablePointer", ToMarshaledClosureType(func, ct));
                                    var ptrName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                                    identifiersUsed.Add(ptrName);

                                    var ptrAllocCallSite = ct.HasReturn() ? $"allocSwiftClosureToFunc_{ct.ArgumentCount()}" : $"allocSwiftClosureToAction_{ct.ArgumentCount ()}";
                                    var ptrAllocCall     = new SLFunctionCall(ptrAllocCallSite, false);
                                    var ptrDecl          = new SLDeclaration(true, new SLIdentifier(ptrName), slct, ptrAllocCall, Visibility.None);
                                    preMarshalCode.Add(new SLLine(ptrDecl));
                                    closureArgs.Insert(0, new SLIdentifier(ptrName));

                                    returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)));

                                    var actualReturnName = MarshalEngine.Uniqueify("actualReturn", identifiersUsed);
                                    identifiersUsed.Add(actualReturnName);
                                    var convertCallSite = ct.HasReturn() ? "netFuncToSwiftClosure" : "netActionToSwiftClosure";
                                    var isEmptyClosure  = !ct.HasReturn() && !ct.HasArguments();
                                    var pointerMove     = new SLFunctionCall($"{ptrName}.move", false);
                                    var convertCall     = isEmptyClosure ? pointerMove : new SLFunctionCall(convertCallSite, false, new SLArgument(new SLIdentifier("a1"), pointerMove, true));
                                    var actualDecl      = new SLDeclaration(true, actualReturnName, value: convertCall, vis: Visibility.None);
                                    postMarshalCode.Add(new SLLine(actualDecl));
                                    postMarshalCode.Add(new SLReturn(new SLIdentifier(actualReturnName)));
                                    break;

                                case TypeSpecKind.ProtocolList:
                                case TypeSpecKind.Tuple:
                                case TypeSpecKind.Named:
                                    var namedReturn = func.ReturnTypeSpec as NamedTypeSpec;
                                    // enums and structs can't get returned directly
                                    // instead they will be inserted at the head of the argument list
                                    // let retval = UnsafeMutablePointer<StructOrEnumType>.allocate(capacity: 1)
                                    // _vtable.entry!(retval, args)
                                    // T actualRetval = retval.move()
                                    // retval.deallocate()
                                    // return actualRetval
                                    string allocCallSite = String.Format("UnsafeMutablePointer<{0}>.allocate", func.ReturnTypeName);
                                    if (namedReturn != null)
                                    {
                                        imports.AddIfNotPresent(namedReturn.Module);
                                    }
                                    string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed);
                                    identifiersUsed.Add(retvalName);
                                    var retDecl = new SLDeclaration(true, retvalName,
                                                                    null, new SLFunctionCall(allocCallSite, false, new SLArgument(new SLIdentifier("capacity"),
                                                                                                                                  SLConstant.Val(1), true)), Visibility.None);
                                    preMarshalCode.Add(new SLLine(retDecl));
                                    closureArgs.Insert(0, new SLIdentifier(retvalName));
                                    returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)));

                                    SLIdentifier actualReturnIdent = new SLIdentifier(MarshalEngine.Uniqueify("actualRetval", identifiersUsed));
                                    identifiersUsed.Add(actualReturnIdent.Name);
                                    var actualRetvalDecl = new SLDeclaration(true, actualReturnIdent, null,
                                                                             new SLFunctionCall(String.Format("{0}.move", retvalName), false),
                                                                             Visibility.None);
                                    postMarshalCode.Add(new SLLine(actualRetvalDecl));
                                    postMarshalCode.Add(SLFunctionCall.FunctionCallLine(
                                                            String.Format("{0}.deallocate", retvalName)));
                                    postMarshalCode.Add(SLReturn.ReturnLine(actualReturnIdent));

                                    break;
                                }
                            }
                        }
                    }
                }
            }

            foreach (ICodeElement line in preMarshalCode)
            {
                yield return(line);
            }
            yield return(returnLine);

            foreach (ICodeElement line in postMarshalCode)
            {
                yield return(line);
            }
        }
Example #6
0
        void GatherGenerics(TypeMapper typeMapper, FunctionDeclaration func, SLImportModules modules, TypeSpec type,
                            SLGenericTypeDeclarationCollection genericDecl, Dictionary <string, List <BaseConstraint> > redundantConstraints)
        {
            if (!func.IsTypeSpecGeneric(type))
            {
                return;
            }

            if (type.ContainsGenericParameters)
            {
                var entity = typeMapper.GetEntityForTypeSpec(type);
                if (entity != null)
                {
                    for (int i = 0; i < entity.Type.Generics.Count; i++)
                    {
                        var genDecl             = entity.Type.Generics [i];
                        var originalGenTypeSpec = type.GenericParameters [i];
                        if (originalGenTypeSpec is NamedTypeSpec named)
                        {
                            var depthIndex = func.GetGenericDepthAndIndex(originalGenTypeSpec);
                            if (depthIndex.Item1 < 0 || depthIndex.Item2 < 0)
                            {
                                continue;
                            }
                            var genRef     = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                            var genRefName = genRef.Name;
                            List <BaseConstraint> constList = null;
                            if (!redundantConstraints.TryGetValue(genRefName, out constList))
                            {
                                constList = new List <BaseConstraint> ();
                                redundantConstraints.Add(genRefName, constList);
                            }
                            constList.AddRange(genDecl.Constraints);
                        }
                        else if (originalGenTypeSpec is ClosureTypeSpec closure)
                        {
                            GatherGenerics(typeMapper, func, modules, closure.Arguments, genericDecl, redundantConstraints);
                            GatherGenerics(typeMapper, func, modules, closure.ReturnType, genericDecl, redundantConstraints);
                        }
                        else if (originalGenTypeSpec is TupleTypeSpec tuple)
                        {
                            foreach (var tupleSpec in tuple.Elements)
                            {
                                GatherGenerics(typeMapper, func, modules, tupleSpec, genericDecl, redundantConstraints);
                            }
                        }
                    }
                }
                foreach (var subType in type.GenericParameters)
                {
                    GatherGenerics(typeMapper, func, modules, subType, genericDecl, redundantConstraints);
                }
            }
            else
            {
                if (type is NamedTypeSpec named)
                {
                    var depthIndex = func.GetGenericDepthAndIndex(type);
                    var gd         = func.GetGeneric(depthIndex.Item1, depthIndex.Item2);
                    var genRef     = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                    var sldecl     = new SLGenericTypeDeclaration(new SLIdentifier(genRef.Name));
#if SWIFT4
                    if (depthIndex.Item1 >= func.GetMaxDepth())
                    {
                        sldecl.Constraints.AddRange(gd.Constraints.Select(baseConstraint =>
                                                                          MethodWrapping.ToSLGenericConstraint(func, baseConstraint, genRef.ToString())
                                                                          ));
                    }
#else
                    sldecl.Constraints.AddRange(gd.Constraints.Select(bc => {
                        InheritanceConstraint inh = bc as InheritanceConstraint;
                        if (inh == null)
                        {
                            throw new CompilerException("Equality constraints not supported (yet)");
                        }
                        return(new SLGenericConstraint(true, new SLSimpleType(genRef.Name), parent.TypeSpecMapper.MapType(func, modules, inh.InheritsTypeSpec)));
                    }));
#endif
                    genericDecl.Add(sldecl);
                }
                else if (type is ClosureTypeSpec closure)
                {
                    GatherGenerics(typeMapper, func, modules, closure.Arguments, genericDecl, redundantConstraints);
                    GatherGenerics(typeMapper, func, modules, closure.ReturnType, genericDecl, redundantConstraints);
                }
                else if (type is TupleTypeSpec tuple)
                {
                    foreach (var tupleSpec in tuple.Elements)
                    {
                        GatherGenerics(typeMapper, func, modules, tupleSpec, genericDecl, redundantConstraints);
                    }
                }
            }
        }
Example #7
0
        public SLParameter ToParameter(TypeMapper typeMapper, FunctionDeclaration func, SLImportModules modules, ParameterItem p, int index,
                                       bool dontChangeInOut, SLGenericTypeDeclarationCollection genericDecl = null, bool remapSelf = false, string remappedSelfName = "")
        {
            var pIsGeneric     = func.IsTypeSpecGeneric(p) && p.TypeSpec is NamedTypeSpec;
            var parmTypeEntity = !pIsGeneric?typeMapper.GetEntityForTypeSpec(p.TypeSpec) : null;

            if (parmTypeEntity == null && !pIsGeneric && p.IsInOut)
            {
                throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 45, $"In function {func.ToFullyQualifiedName ()}, unknown type parameter type {p.PublicName}:{p.TypeName}.");
            }
            var    parmKind = p.IsInOut && (pIsGeneric || !parmTypeEntity.IsStructOrEnum) ? SLParameterKind.InOut : SLParameterKind.None;
            SLType parmType = null;

            var pTypeSpec = remapSelf ? p.TypeSpec.ReplaceName("Self", remappedSelfName) : p.TypeSpec;

            if (genericDecl != null)
            {
                GatherGenerics(typeMapper, func, modules, pTypeSpec, genericDecl);
            }
            if (pIsGeneric)
            {
                if (pTypeSpec.ContainsGenericParameters)
                {
                    var ns       = pTypeSpec as NamedTypeSpec;
                    var boundGen = new SLBoundGenericType(ns.Name,
                                                          pTypeSpec.GenericParameters.Select(genParm => {
                        return(MapType(func, modules, genParm, true));
                    }));
                    if (parent.MustForcePassByReference(func, ns))
                    {
                        boundGen = new SLBoundGenericType("UnsafeMutablePointer", boundGen);
                    }
                    parmType = boundGen;
                }
                else
                {
                    var namedType = pTypeSpec as NamedTypeSpec;
                    if (namedType == null)
                    {
                        throw new NotImplementedException("Can only have a named type spec here.");
                    }
                    var depthIndex = func.GetGenericDepthAndIndex(namedType.Name);
                    var gd         = func.GetGeneric(depthIndex.Item1, depthIndex.Item2);
                    var genRef     = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                    parmType = genRef;
                }
            }
            else
            {
                parmType = MapType(func, modules, pTypeSpec, false);
                if (pIsGeneric)
                {
                    Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(pTypeSpec);
                    parmType = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2);
                }
                else if (parent.MustForcePassByReference(func, pTypeSpec) && !dontChangeInOut)
                {
                    parmType = new SLBoundGenericType(p.IsInOut ? "UnsafeMutablePointer" : "UnsafePointer", parmType);
                }
            }
            if (isForOverride && p.IsVariadic)
            {
                // if we get here, then parmType is an SLSimpleType of SwiftArray<someType>
                // we're going to turn it into "someType ..."
                var oldParmType = parmType as SLBoundGenericType;
                parmType = new SLVariadicType(oldParmType.BoundTypes [0]);
            }
            var publicName  = !p.NameIsRequired ? null : ConjureIdentifier(p.PublicName, index);
            var privateName = !String.IsNullOrEmpty(p.PrivateName) ? p.PrivateName : null;

            return(new SLParameter(publicName, ConjureIdentifier(privateName, index), parmType, parmKind));
        }