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); } }
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); } } } }
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)); }