diff --git a/Sources/JExtractSwiftLib/Common/TypeAnnotations.swift b/Sources/JExtractSwiftLib/Common/TypeAnnotations.swift index b23281d3..0297d96a 100644 --- a/Sources/JExtractSwiftLib/Common/TypeAnnotations.swift +++ b/Sources/JExtractSwiftLib/Common/TypeAnnotations.swift @@ -18,10 +18,12 @@ import SwiftJavaJNICore /// Determine if the given type needs any extra annotations that should be included /// in Java sources when the corresponding Java type is rendered. func getTypeAnnotations(swiftType: SwiftType, config: Configuration) -> [JavaAnnotation] { - switch swiftType { - case .array(let wrapped) where wrapped.isUnsignedInteger: + if swiftType.isUnsignedInteger { return [JavaAnnotation.unsigned] - case _ where swiftType.isUnsignedInteger: + } + + switch swiftType.asNominalType?.asKnownType { + case .array(let element) where element.isUnsignedInteger: return [JavaAnnotation.unsigned] default: return [] diff --git a/Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift b/Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift index d2eeb58d..58dc8926 100644 --- a/Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift +++ b/Sources/JExtractSwiftLib/FFM/CDeclLowering/CRepresentation.swift @@ -24,20 +24,24 @@ extension CType { init(cdeclType: SwiftType) throws { switch cdeclType { case .nominal(let nominalType): - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { - if let primitiveCType = knownType.primitiveCType { + if let knownType = nominalType.asKnownType { + if let primitiveCType = knownType.kind.primitiveCType { self = primitiveCType return } switch knownType { - case .unsafePointer where nominalType.genericArguments?.count == 1: + case .optional(let wrapped) where wrapped.isPointer: + try self.init(cdeclType: wrapped) + return + + case .unsafePointer(let pointee): self = .pointer( - .qualified(const: true, volatile: false, type: try CType(cdeclType: nominalType.genericArguments![0])) + .qualified(const: true, volatile: false, type: try CType(cdeclType: pointee)) ) return - case .unsafeMutablePointer where nominalType.genericArguments?.count == 1: - self = .pointer(try CType(cdeclType: nominalType.genericArguments![0])) + case .unsafeMutablePointer(let pointee): + self = .pointer(try CType(cdeclType: pointee)) return default: break @@ -67,10 +71,7 @@ extension CType { case .tuple([]): self = .void - case .optional(let wrapped) where wrapped.isPointer: - try self.init(cdeclType: wrapped) - - case .genericParameter, .metatype, .optional, .tuple, .opaque, .existential, .composite, .array, .dictionary, .set: + case .genericParameter, .metatype, .tuple, .opaque, .existential, .composite: throw CDeclToCLoweringError.invalidCDeclType(cdeclType) } } @@ -127,8 +128,6 @@ extension SwiftKnownTypeDeclKind { .pointer( .qualified(const: true, volatile: false, type: .void) ) - case .array: - .pointer(.qualified(const: false, volatile: false, type: .void)) case .void: .void default: nil // Since we know the set of all primitives, we can safely assume all others are not primitive diff --git a/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift b/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift index 9e3c4228..52d12640 100644 --- a/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift +++ b/Sources/JExtractSwiftLib/FFM/CDeclLowering/FFMSwift2JavaGenerator+FunctionLowering.swift @@ -176,19 +176,16 @@ struct CdeclLowering { ) case .nominal(let nominal): - if let knownType = nominal.nominalTypeDecl.knownTypeKind { + if let knownType = nominal.asKnownType { if convention == .inout { // FIXME: Support non-trivial 'inout' for builtin types. throw LoweringError.inoutNotSupported(type) } switch knownType { - case .unsafePointer, .unsafeMutablePointer: - guard let genericArgs = type.asNominalType?.genericArguments, genericArgs.count == 1 else { - throw LoweringError.unhandledType(type) - } + case .unsafePointer(let pointee), .unsafeMutablePointer(let pointee): // Typed pointers are mapped down to their raw forms in cdecl entry // points. These can be passed through directly. - let isMutable = knownType == .unsafeMutablePointer + let isMutable = knownType.kind == .unsafeMutablePointer return LoweredParameter( cdeclParameters: [ SwiftParameter( @@ -197,15 +194,12 @@ struct CdeclLowering { type: isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer ) ], - conversion: .typedPointer(.placeholder, swiftType: genericArgs[0]) + conversion: .typedPointer(.placeholder, swiftType: pointee) ) - case .unsafeBufferPointer, .unsafeMutableBufferPointer: - guard let genericArgs = nominal.genericArguments, genericArgs.count == 1 else { - throw LoweringError.unhandledType(type) - } + case .unsafeBufferPointer(let element), .unsafeMutableBufferPointer(let element): // Typed pointers are lowered to (raw-pointer, count) pair. - let isMutable = knownType == .unsafeMutableBufferPointer + let isMutable = knownType.kind == .unsafeMutableBufferPointer return LoweredParameter( cdeclParameters: [ SwiftParameter( @@ -226,7 +220,7 @@ struct CdeclLowering { label: "start", argument: .typedPointer( .explodedComponent(.placeholder, component: "pointer"), - swiftType: genericArgs[0] + swiftType: element ) ), LabeledArgument( @@ -245,7 +239,7 @@ struct CdeclLowering { SwiftParameter( convention: .byValue, parameterName: "\(parameterName)_pointer", - type: .optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) + type: knownTypes.optionalSugar(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) ), SwiftParameter( convention: .byValue, @@ -268,12 +262,9 @@ struct CdeclLowering { ) ) - case .optional: - guard let genericArgs = nominal.genericArguments, genericArgs.count == 1 else { - throw LoweringError.unhandledType(type) - } + case .optional(let wrapped): return try lowerOptionalParameter( - genericArgs[0], + wrapped, convention: convention, parameterName: parameterName, genericParameters: genericParameters, @@ -282,23 +273,60 @@ struct CdeclLowering { case .string: // 'String' is passed in by C string. i.e. 'UnsafePointer' ('const uint8_t *') - if knownType == .string { - return LoweredParameter( - cdeclParameters: [ - SwiftParameter( - convention: .byValue, - parameterName: parameterName, - type: knownTypes.unsafePointer(knownTypes.int8) - ) - ], - conversion: .initialize( - type, - arguments: [ - LabeledArgument(label: "cString", argument: .placeholder) - ] + return LoweredParameter( + cdeclParameters: [ + SwiftParameter( + convention: .byValue, + parameterName: parameterName, + type: knownTypes.unsafePointer(knownTypes.int8) ) + ], + conversion: .initialize( + type, + arguments: [ + LabeledArgument(label: "cString", argument: .placeholder) + ] ) - } + ) + + case .array(let element) where element == knownTypes.uint8: + // Lower an array as 'address' raw pointer and 'count' integer + let cdeclParameters = [ + SwiftParameter( + convention: .byValue, + parameterName: "\(parameterName)_pointer", + type: knownTypes.unsafeRawPointer + ), + SwiftParameter( + convention: .byValue, + parameterName: "\(parameterName)_count", + type: knownTypes.int + ), + ] + + let bufferPointerInit = ConversionStep.initialize( + knownTypes.unsafeRawBufferPointer, + arguments: [ + LabeledArgument( + label: "start", + argument: .explodedComponent(.placeholder, component: "pointer") + ), + LabeledArgument( + label: "count", + argument: .explodedComponent(.placeholder, component: "count") + ), + ] + ) + + let arrayInit = ConversionStep.initialize( + type, + arguments: [LabeledArgument(argument: bufferPointerInit)] + ) + + return LoweredParameter( + cdeclParameters: cdeclParameters, + conversion: arrayInit + ) case .foundationData, .essentialsData: break @@ -382,65 +410,8 @@ struct CdeclLowering { } throw LoweringError.unhandledType(type) - case .optional(let wrapped): - return try lowerOptionalParameter( - wrapped, - convention: convention, - parameterName: parameterName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - case .composite: throw LoweringError.unhandledType(type) - - case .array(let wrapped) where wrapped == knownTypes.uint8: - // Lower an array as 'address' raw pointer and 'count' integer - let cdeclParameters = [ - SwiftParameter( - convention: .byValue, - parameterName: "\(parameterName)_pointer", - type: knownTypes.unsafeRawPointer - ), - SwiftParameter( - convention: .byValue, - parameterName: "\(parameterName)_count", - type: knownTypes.int - ), - ] - - let bufferPointerInit = ConversionStep.initialize( - knownTypes.unsafeRawBufferPointer, - arguments: [ - LabeledArgument( - label: "start", - argument: .explodedComponent(.placeholder, component: "pointer") - ), - LabeledArgument( - label: "count", - argument: .explodedComponent(.placeholder, component: "count") - ), - ] - ) - - let arrayInit = ConversionStep.initialize( - type, - arguments: [LabeledArgument(argument: bufferPointerInit)] - ) - - return LoweredParameter( - cdeclParameters: cdeclParameters, - conversion: arrayInit - ) - - case .array: - throw LoweringError.unhandledType(type) - - case .dictionary: - throw LoweringError.unhandledType(type) - - case .set: - throw LoweringError.unhandledType(type) } } @@ -462,7 +433,7 @@ struct CdeclLowering { SwiftParameter( convention: .byValue, parameterName: parameterName, - type: .optional(knownTypes.unsafePointer(wrappedType)) + type: knownTypes.optionalSugar(knownTypes.unsafePointer(wrappedType)) ) ], conversion: .pointee(.optionalChain(.placeholder)) @@ -476,20 +447,20 @@ struct CdeclLowering { case .foundationData, .essentialsData: break case .unsafeRawPointer, .unsafeMutableRawPointer: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .unsafePointer, .unsafeMutablePointer: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .unsafeBufferPointer, .unsafeMutableBufferPointer: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .void, .string: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .foundationDataProtocol, .essentialsDataProtocol: - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) default: // Unreachable? Should be handled by `CType(cdeclType:)` lowering above. - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) } } @@ -499,7 +470,7 @@ struct CdeclLowering { SwiftParameter( convention: .byValue, parameterName: parameterName, - type: .optional(knownTypes.unsafeRawPointer) + type: knownTypes.optionalSugar(knownTypes.unsafeRawPointer) ) ], conversion: .pointee(.typedPointer(.optionalChain(.placeholder), swiftType: wrappedType)) @@ -519,7 +490,7 @@ struct CdeclLowering { genericRequirements: genericRequirements ) } - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) case .tuple(let tuple): if tuple.count == 1 { @@ -531,10 +502,10 @@ struct CdeclLowering { genericRequirements: genericRequirements ) } - throw LoweringError.unhandledType(.optional(wrappedType)) + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) - case .function, .metatype, .optional, .composite, .array, .dictionary, .set: - throw LoweringError.unhandledType(.optional(wrappedType)) + case .function, .metatype, .composite: + throw LoweringError.unhandledType(knownTypes.optionalSugar(wrappedType)) } } @@ -610,7 +581,7 @@ struct CdeclLowering { SwiftParameter( convention: .byValue, parameterName: "\(parameterName)_pointer", - type: .optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) + type: knownTypes.optionalSugar(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) ), SwiftParameter( convention: .byValue, @@ -635,12 +606,13 @@ struct CdeclLowering { // Custom types are not supported yet. throw LoweringError.unhandledType(type) - case .genericParameter, .function, .metatype, .optional, .tuple, .existential, .opaque, .composite, .array, .dictionary, .set: + case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite: // TODO: Implement throw LoweringError.unhandledType(type) } } + /// Create "out" parameter names when we're returning an array-like result. fileprivate func makeBufferIndirectReturnParameters(_ outParameterName: String, isMutable: Bool) -> [SwiftParameter] { [ @@ -648,7 +620,7 @@ struct CdeclLowering { convention: .byValue, parameterName: "\(outParameterName)_pointer", type: knownTypes.unsafeMutablePointer( - .optional(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) + knownTypes.optionalSugar(isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer) ) ), SwiftParameter( @@ -686,11 +658,11 @@ struct CdeclLowering { case .nominal(let nominal): // Types from the Swift standard library that we know about. - if let knownType = nominal.nominalTypeDecl.knownTypeKind { + if let knownType = nominal.asKnownType { switch knownType { case .unsafePointer, .unsafeMutablePointer: // Typed pointers are lowered to corresponding raw forms. - let isMutable = knownType == .unsafeMutablePointer + let isMutable = knownType.kind == .unsafeMutablePointer let resultType: SwiftType = isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer return LoweredResult( cdeclResultType: resultType, @@ -700,7 +672,7 @@ struct CdeclLowering { case .unsafeBufferPointer, .unsafeMutableBufferPointer: // Typed pointers are lowered to (raw-pointer, count) pair. - let isMutable = knownType == .unsafeMutableBufferPointer + let isMutable = knownType.kind == .unsafeMutableBufferPointer return try lowerResult( .tuple([ SwiftTupleElement(label: nil, type: isMutable ? knownTypes.unsafeMutableRawPointer : knownTypes.unsafeRawPointer), @@ -711,7 +683,7 @@ struct CdeclLowering { case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer: // pointer buffers are lowered to (raw-pointer, count) pair. - let isMutable = knownType == .unsafeMutableRawBufferPointer + let isMutable = knownType.kind == .unsafeMutableRawBufferPointer return LoweredResult( cdeclResultType: .void, cdeclOutParameters: makeBufferIndirectReturnParameters(outParameterName, isMutable: isMutable), @@ -752,6 +724,45 @@ struct CdeclLowering { // Not supported at this point. throw LoweringError.unhandledType(type) + case .array(let element) where element == knownTypes.uint8: + let resultName = "_result" + + return LoweredResult( + cdeclResultType: .void, // we call into the _result_initialize instead + cdeclOutParameters: [ + SwiftParameter( + convention: .byValue, + parameterName: "\(outParameterName)_initialize", + type: knownTypes.functionInitializeByteBuffer + ) + ], + conversion: .aggregate( + [ + .method( + base: resultName, + methodName: "withUnsafeBufferPointer", + arguments: [ + .init( + argument: + .closureLowering( + parameters: [.placeholder], + result: .method( + base: "\(outParameterName)_initialize", + methodName: nil, // just `(...)` apply the closure + arguments: [ + .init(label: nil, argument: .member(.constant("_0"), member: "baseAddress!")), + .init(label: nil, argument: .member(.constant("_0"), member: "count")), + ] + ) + ) + ) + ] + ) + ], + name: resultName + ) + ) + default: // Unreachable? Should be handled by `CType(cdeclType:)` lowering above. throw LoweringError.unhandledType(type) @@ -811,46 +822,7 @@ struct CdeclLowering { conversion: .tupleExplode(conversions, name: outParameterName) ) - case .array(let wrapped) where wrapped == knownTypes.uint8: - let resultName = "_result" - - return LoweredResult( - cdeclResultType: .void, // we call into the _result_initialize instead - cdeclOutParameters: [ - SwiftParameter( - convention: .byValue, - parameterName: "\(outParameterName)_initialize", - type: knownTypes.functionInitializeByteBuffer - ) - ], - conversion: .aggregate( - [ - .method( - base: resultName, - methodName: "withUnsafeBufferPointer", - arguments: [ - .init( - argument: - .closureLowering( - parameters: [.placeholder], - result: .method( - base: "\(outParameterName)_initialize", - methodName: nil, // just `(...)` apply the closure - arguments: [ - .init(label: nil, argument: .member(.constant("_0"), member: "baseAddress!")), - .init(label: nil, argument: .member(.constant("_0"), member: "count")), - ] - ) - ) - ) - ] - ) - ], - name: resultName - ) - ) - - case .genericParameter, .function, .optional, .existential, .opaque, .composite, .array, .dictionary, .set: + case .genericParameter, .function, .existential, .opaque, .composite: throw LoweringError.unhandledType(type) } } diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift index d9fd611f..80543a20 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+JavaTranslation.swift @@ -390,7 +390,7 @@ extension FFMSwift2JavaGenerator { ) case .nominal(let swiftNominalType): - if let knownType = swiftNominalType.nominalTypeDecl.knownTypeKind { + if let knownType = swiftNominalType.asKnownType { if convention == .inout { // FIXME: Support non-trivial 'inout' for builtin types. throw JavaTranslationError.inoutNotSupported(swiftType) @@ -414,12 +414,9 @@ extension FFMSwift2JavaGenerator { ]) ) - case .optional: - guard let genericArgs = swiftNominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unhandledType(swiftType) - } + case .optional(let wrapped): return try translateOptionalParameter( - wrappedType: genericArgs[0], + wrappedType: wrapped, convention: convention, parameterName: parameterName, loweredParam: loweredParam, @@ -439,6 +436,23 @@ extension FFMSwift2JavaGenerator { conversion: .call(.placeholder, function: "SwiftRuntime.toCString", withArena: true) ) + case .array(let element) where element == knownTypes.uint8: + return TranslatedParameter( + javaParameters: [ + JavaParameter(name: parameterName, type: .array(.byte), annotations: parameterAnnotations) + ], + conversion: + .commaSeparated([ + .call( + .commaSeparated([.constant("ValueLayout.JAVA_BYTE"), .placeholder]), + base: .temporaryArena, + function: "allocateFrom", + withArena: false // this would pass the arena as last argument, but instead we make a call on the arena + ), + .property(.placeholder, propertyName: "length"), + ]) + ) + case .foundationData, .essentialsData: break @@ -515,45 +529,8 @@ extension FFMSwift2JavaGenerator { // Otherwise, not supported yet. throw JavaTranslationError.unhandledType(swiftType) - case .optional(let wrapped): - return try translateOptionalParameter( - wrappedType: wrapped, - convention: convention, - parameterName: parameterName, - loweredParam: loweredParam, - methodName: methodName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - case .composite: throw JavaTranslationError.unhandledType(swiftType) - - case .array(let wrapped) where wrapped == knownTypes.uint8: - return TranslatedParameter( - javaParameters: [ - JavaParameter(name: parameterName, type: .array(.byte), annotations: parameterAnnotations) - ], - conversion: - .commaSeparated([ - .call( - .commaSeparated([.constant("ValueLayout.JAVA_BYTE"), .placeholder]), - base: .temporaryArena, - function: "allocateFrom", - withArena: false // this would pass the arena as last argument, but instead we make a call on the arena - ), - .property(.placeholder, propertyName: "length"), - ]) - ) - - case .array: - throw JavaTranslationError.unhandledType(swiftType) - - case .dictionary: - throw JavaTranslationError.unhandledType(swiftType) - - case .set: - throw JavaTranslationError.unhandledType(swiftType) } } @@ -631,7 +608,7 @@ extension FFMSwift2JavaGenerator { case .short: ("Optional", "toOptionalSegmentShort") case .float: ("Optional", "toOptionalSegmentFloat") default: - throw JavaTranslationError.unhandledType(.optional(swiftType)) + throw JavaTranslationError.unhandledType(known: .optional(swiftType)) } return TranslatedParameter( javaParameters: [ @@ -650,7 +627,7 @@ extension FFMSwift2JavaGenerator { case .essentialsData, .essentialsDataProtocol: break default: - throw JavaTranslationError.unhandledType(.optional(swiftType)) + throw JavaTranslationError.unhandledType(known: .optional(swiftType)) } } @@ -677,7 +654,7 @@ extension FFMSwift2JavaGenerator { genericRequirements: genericRequirements ) } - throw JavaTranslationError.unhandledType(.optional(swiftType)) + throw JavaTranslationError.unhandledType(known: .optional(swiftType)) case .tuple(let tuple): if tuple.count == 1 { return try translateOptionalParameter( @@ -690,9 +667,9 @@ extension FFMSwift2JavaGenerator { genericRequirements: genericRequirements ) } - throw JavaTranslationError.unhandledType(.optional(swiftType)) + throw JavaTranslationError.unhandledType(known: .optional(swiftType)) default: - throw JavaTranslationError.unhandledType(.optional(swiftType)) + throw JavaTranslationError.unhandledType(known: .optional(swiftType)) } } @@ -738,7 +715,7 @@ extension FFMSwift2JavaGenerator { ) case .nominal(let swiftNominalType): - if let knownType = swiftNominalType.nominalTypeDecl.knownTypeKind { + if let knownType = swiftNominalType.asKnownType { switch knownType { case .unsafeRawBufferPointer, .unsafeMutableRawBufferPointer: return TranslatedResult( @@ -774,6 +751,56 @@ extension FFMSwift2JavaGenerator { outParameters: [], conversion: .call(.placeholder, function: "SwiftRuntime.fromCString", withArena: false) ) + + case .array(let element) where element == knownTypes.uint8: + return TranslatedResult( + javaResultType: + .array(.byte), + annotations: [.unsigned], + outParameters: [], // no out parameters, but we do an "out" callback + outCallback: OutCallback( + name: "$_result_initialize", + members: [ + "byte[] result = null" + ], + parameters: [ + JavaParameter(name: "pointer", type: .javaForeignMemorySegment), + JavaParameter(name: "count", type: .long), + ], + cFunc: CFunction( + resultType: .void, + name: "apply", + parameters: [ + CParameter(type: .pointer(.void)), + CParameter(type: .integral(.size_t)), + ], + isVariadic: false + ), + body: + "this.result = _0.reinterpret(_1).toArray(ValueLayout.JAVA_BYTE); // copy native Swift array to Java heap array" + ), + conversion: .initializeResultWithUpcall( + [ + .introduceVariable( + name: "_result_initialize", + initializeWith: .javaNew( + .commaSeparated( + [ + // We need to refer to the nested class that is created for this function. + // The class that contains all the related functional interfaces is called the same + // as the downcall function, so we use the thunk name to find this class/ + .placeholderForSwiftThunkName, .constant("$_result_initialize.Function$Impl()"), + ], + separator: "." + ) + ) + ), + .placeholderForDowncall, // perform the downcall here + ], + extractResult: .property(.constant("_result_initialize"), propertyName: "result") + ) + ) + default: throw JavaTranslationError.unhandledType(swiftType) } @@ -808,57 +835,7 @@ extension FFMSwift2JavaGenerator { resultAnnotations: resultAnnotations ) - case .array(let wrapped) where wrapped == knownTypes.uint8: - return TranslatedResult( - javaResultType: - .array(.byte), - annotations: [.unsigned], - outParameters: [], // no out parameters, but we do an "out" callback - outCallback: OutCallback( - name: "$_result_initialize", - members: [ - "byte[] result = null" - ], - parameters: [ - JavaParameter(name: "pointer", type: .javaForeignMemorySegment), - JavaParameter(name: "count", type: .long), - ], - cFunc: CFunction( - resultType: .void, - name: "apply", - parameters: [ - CParameter(type: .pointer(.void)), - CParameter(type: .integral(.size_t)), - ], - isVariadic: false - ), - body: - "this.result = _0.reinterpret(_1).toArray(ValueLayout.JAVA_BYTE); // copy native Swift array to Java heap array" - ), - conversion: .initializeResultWithUpcall( - [ - .introduceVariable( - name: "_result_initialize", - initializeWith: .javaNew( - .commaSeparated( - [ - // We need to refer to the nested class that is created for this function. - // The class that contains all the related functional interfaces is called the same - // as the downcall function, so we use the thunk name to find this class/ - .placeholderForSwiftThunkName, .constant("$_result_initialize.Function$Impl()"), - ], - separator: "." - ) - ) - ), - // .constant("var = new \(.placeholderForDowncallThunkName).."), - .placeholderForDowncall, // perform the downcall here - ], - extractResult: .property(.constant("_result_initialize"), propertyName: "result") - ) - ) - - case .genericParameter, .optional, .function, .existential, .opaque, .composite, .array, .dictionary, .set: + case .genericParameter, .function, .existential, .opaque, .composite: throw JavaTranslationError.unhandledType(swiftType) } @@ -1126,4 +1103,5 @@ extension CType { enum JavaTranslationError: Error { case inoutNotSupported(SwiftType, file: String = #file, line: Int = #line) case unhandledType(SwiftType, file: String = #file, line: Int = #line) + case unhandledType(known: SwiftKnownType, file: String = #file, line: Int = #line) } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+InterfaceWrapperGeneration.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+InterfaceWrapperGeneration.swift index 9cde170d..2f19b39a 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+InterfaceWrapperGeneration.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+InterfaceWrapperGeneration.swift @@ -195,24 +195,18 @@ extension JNISwift2JavaGenerator { switch type { case .nominal(let nominalType): - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + if let knownType = nominalType.asKnownType { switch knownType { - case .optional: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(type) - } + case .optional(let wrapped): return try translateOptionalParameter( name: parameterName, - wrappedType: genericArgs[0] + wrappedType: wrapped ) - case .array: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(type) - } + case .array(let element): return try translateArrayParameter( name: parameterName, - elementType: genericArgs[0] + elementType: element ) default: @@ -230,21 +224,6 @@ extension JNISwift2JavaGenerator { case .tuple([]): // void return .placeholder - case .optional(let wrappedType): - return try translateOptionalParameter( - name: parameterName, - wrappedType: wrappedType - ) - - case .array(let elementType): - return try translateArrayParameter(name: parameterName, elementType: elementType) - - case .dictionary: - throw JavaTranslationError.unsupportedSwiftType(type) - - case .set: - throw JavaTranslationError.unsupportedSwiftType(type) - case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite: throw JavaTranslationError.unsupportedSwiftType(type) } @@ -253,6 +232,15 @@ extension JNISwift2JavaGenerator { private func translateArrayParameter(name: String, elementType: SwiftType) throws -> UpcallConversionStep { switch elementType { case .nominal(let nominalType): + if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + switch knownType { + case .optional, .array, .dictionary, .set: + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) + default: + break + } + } + // We assume this is a JExtracted type return .map( .placeholder, @@ -263,8 +251,8 @@ extension JNISwift2JavaGenerator { ) ) - case .array, .dictionary, .set, .composite, .existential, .function, .genericParameter, .metatype, .opaque, .optional, .tuple: - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + case .composite, .existential, .function, .genericParameter, .metatype, .opaque, .tuple: + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) } } @@ -288,22 +276,16 @@ extension JNISwift2JavaGenerator { switch type { case .nominal(let nominalType): - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + if let knownType = nominalType.asKnownType { switch knownType { - case .optional: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(type) - } + case .optional(let wrapped): return try self.translateOptionalResult( - wrappedType: genericArgs[0], + wrappedType: wrapped, methodName: methodName ) - case .array: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(type) - } - return try self.translateArrayResult(elementType: genericArgs[0]) + case .array(let element): + return try self.translateArrayResult(elementType: element) default: throw JavaTranslationError.unsupportedSwiftType(type) @@ -325,18 +307,6 @@ extension JNISwift2JavaGenerator { case .tuple([]): // void return .placeholder - case .optional(let wrappedType): - return try self.translateOptionalResult(wrappedType: wrappedType, methodName: methodName) - - case .array(let elementType): - return try self.translateArrayResult(elementType: elementType) - - case .dictionary: - throw JavaTranslationError.unsupportedSwiftType(type) - - case .set: - throw JavaTranslationError.unsupportedSwiftType(type) - case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite: throw JavaTranslationError.unsupportedSwiftType(type) } @@ -345,6 +315,15 @@ extension JNISwift2JavaGenerator { private func translateArrayResult(elementType: SwiftType) throws -> UpcallConversionStep { switch elementType { case .nominal(let nominalType): + if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + switch knownType { + case .optional, .array, .dictionary, .set: + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) + default: + break + } + } + // We assume this is a JExtracted type return .map( .placeholder, @@ -355,8 +334,8 @@ extension JNISwift2JavaGenerator { ) ) - case .array, .dictionary, .set, .composite, .existential, .function, .genericParameter, .metatype, .opaque, .optional, .tuple: - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + case .composite, .existential, .function, .genericParameter, .metatype, .opaque, .tuple: + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) } } @@ -477,21 +456,20 @@ extension SwiftType { var isDirectlyTranslatedToWrapJava: Bool { switch self { case .nominal(let swiftNominalType): - guard let knownType = swiftNominalType.nominalTypeDecl.knownTypeKind else { + guard let knownType = swiftNominalType.asKnownType else { return false } switch knownType { case .bool, .int, .uint, .int8, .uint8, .int16, .uint16, .int32, .uint32, .int64, .uint64, .float, .double, .string, .void: return true + case .array(let element): + return element.isDirectlyTranslatedToWrapJava default: return false } - case .array(let elementType): - return elementType.isDirectlyTranslatedToWrapJava - - case .genericParameter, .function, .metatype, .optional, .tuple, .existential, .opaque, .composite, .dictionary, .set: + case .genericParameter, .function, .metatype, .tuple, .existential, .opaque, .composite: return false } } diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift index 2563c1a5..38e891f2 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift @@ -458,23 +458,17 @@ extension JNISwift2JavaGenerator { case .nominal(let nominalType): let nominalTypeName = nominalType.nominalTypeDecl.qualifiedName - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + if let knownType = nominalType.asKnownType { switch knownType { - case .optional: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(swiftType) - } + case .optional(let wrapped): return try translateOptionalParameter( - wrappedType: genericArgs[0], + wrappedType: wrapped, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements ) - case .array: - guard let elementType = nominalType.genericArguments?.first else { - throw JavaTranslationError.unsupportedSwiftType(swiftType) - } + case .array(let elementType): return try translateArrayParameter( elementType: elementType, parameterName: parameterName, @@ -482,24 +476,18 @@ extension JNISwift2JavaGenerator { genericRequirements: genericRequirements ) - case .dictionary: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 2 else { - throw JavaTranslationError.dictionaryRequiresKeyAndValueTypes(swiftType) - } + case .dictionary(let keyType, let valueType): return try translateDictionaryParameter( - keyType: genericArgs[0], - valueType: genericArgs[1], + keyType: keyType, + valueType: valueType, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements ) - case .set: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.setRequiresElementType(swiftType) - } + case .set(let elementType): return try translateSetParameter( - elementType: genericArgs[0], + elementType: elementType, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements @@ -518,7 +506,7 @@ extension JNISwift2JavaGenerator { ) default: - guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else { + guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType.kind, config: self.config) else { throw JavaTranslationError.unsupportedSwiftType(swiftType) } @@ -578,14 +566,6 @@ extension JNISwift2JavaGenerator { conversion: .placeholder ) - case .optional(let wrapped): - return try translateOptionalParameter( - wrappedType: wrapped, - parameterName: parameterName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - case .opaque(let proto), .existential(let proto): guard let parameterPosition else { fatalError("Cannot extract opaque or existential type that is not a parameter: \(proto)") @@ -615,31 +595,6 @@ extension JNISwift2JavaGenerator { throw JavaTranslationError.unsupportedSwiftType(swiftType) - case .array(let elementType): - return try translateArrayParameter( - elementType: elementType, - parameterName: parameterName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - - case .dictionary(let keyType, let valueType): - return try translateDictionaryParameter( - keyType: keyType, - valueType: valueType, - parameterName: parameterName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - - case .set(let elementType): - return try translateSetParameter( - elementType: elementType, - parameterName: parameterName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - case .metatype: return TranslatedParameter( parameter: JavaParameter(name: parameterName, type: .long), @@ -1056,36 +1011,6 @@ extension JNISwift2JavaGenerator { case .tuple([]): return TranslatedResult(javaType: .void, outParameters: [], conversion: .placeholder) - case .optional(let wrapped): - return try translateOptionalResult( - wrappedType: wrapped, - resultName: resultName, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - - case .array(let elementType): - return try translateArrayResult( - elementType: elementType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - - case .dictionary(let keyType, let valueType): - return try translateDictionaryResult( - keyType: keyType, - valueType: valueType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - - case .set(let elementType): - return try translateSetResult( - elementType: elementType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - case .tuple(let elements) where !elements.isEmpty: return try translateTupleResult( elements: elements, @@ -1212,43 +1137,6 @@ extension JNISwift2JavaGenerator { } return .class(package: nil, name: generic.name) - case .optional(let wrapped): - let wrappedType = try translateGenericTypeParameter( - wrapped, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - return .class(package: "java.util", name: "Optional", typeParameters: [wrappedType]) - - case .array(let elementType): - let elementJavaType = try translateGenericTypeParameter( - elementType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - return .array(elementJavaType) - - case .dictionary(let keyType, let valueType): - let keyJavaType = try translateGenericTypeParameter( - keyType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - let valueJavaType = try translateGenericTypeParameter( - valueType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - return .swiftDictionaryMap(keyJavaType, valueJavaType) - - case .set(let elementType): - let elementJavaType = try translateGenericTypeParameter( - elementType, - genericParameters: genericParameters, - genericRequirements: genericRequirements - ) - return .swiftSet(elementJavaType) - case .metatype, .tuple, .function, .existential, .opaque, .composite: throw JavaTranslationError.unsupportedSwiftType(swiftType) } @@ -2130,6 +2018,15 @@ extension JNISwift2JavaGenerator { .unsupportedSwiftType(type, fileID: _fileID, line: _line) } + case unsupportedSwiftType(known: SwiftKnownType, fileID: String, line: Int) + static func unsupportedSwiftType( + known type: SwiftKnownType, + _fileID: String = #fileID, + _line: Int = #line + ) -> JavaTranslationError { + .unsupportedSwiftType(known: type, fileID: _fileID, line: _line) + } + /// The user has not supplied a mapping from `SwiftType` to /// a java class. case wrappedJavaClassTranslationNotProvided(SwiftType) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift index e83ab08a..48875f8f 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+NativeTranslation.swift @@ -101,39 +101,27 @@ extension JNISwift2JavaGenerator { case .nominal(let nominalType): let nominalTypeName = nominalType.nominalTypeDecl.name - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + if let knownType = nominalType.asKnownType { switch knownType { - case .optional: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(type) - } + case .optional(let wrapped): return try translateOptionalParameter( - wrappedType: genericArgs[0], + wrappedType: wrapped, parameterName: parameterName ) - case .array: - guard let elementType = nominalType.genericArguments?.first else { - throw JavaTranslationError.unsupportedSwiftType(type) - } - return try translateArrayParameter(elementType: elementType, parameterName: parameterName) + case .array(let element): + return try translateArrayParameter(elementType: element, parameterName: parameterName) - case .dictionary: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 2 else { - throw JavaTranslationError.dictionaryRequiresKeyAndValueTypes(type) - } + case .dictionary(let key, let value): return try translateDictionaryParameter( - keyType: genericArgs[0], - valueType: genericArgs[1], + keyType: key, + valueType: value, parameterName: parameterName ) - case .set: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.setRequiresElementType(type) - } + case .set(let element): return try translateSetParameter( - elementType: genericArgs[0], + elementType: element, parameterName: parameterName ) @@ -169,17 +157,17 @@ extension JNISwift2JavaGenerator { ) default: - guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config), + guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType.kind, config: self.config), javaType.implementsJavaValue else { throw JavaTranslationError.unsupportedSwiftType(type) } let indirectStepType = JNIJavaTypeTranslator.indirectConversionStepSwiftType( - for: knownType, + for: knownType.kind, from: knownTypes ) - let indirectCheck = JNIJavaTypeTranslator.checkStep(for: knownType, from: knownTypes) + let indirectCheck = JNIJavaTypeTranslator.checkStep(for: knownType.kind, from: knownTypes) return NativeParameter( parameters: [ @@ -295,12 +283,6 @@ extension JNISwift2JavaGenerator { conversionCheck: nil ) - case .optional(let wrapped): - return try translateOptionalParameter( - wrappedType: wrapped, - parameterName: parameterName - ) - case .opaque(let proto), .existential(let proto): return try translateProtocolParameter( protocolType: proto, @@ -321,25 +303,6 @@ extension JNISwift2JavaGenerator { throw JavaTranslationError.unsupportedSwiftType(type) - case .array(let elementType): - return try translateArrayParameter( - elementType: elementType, - parameterName: parameterName - ) - - case .dictionary(let keyType, let valueType): - return try translateDictionaryParameter( - keyType: keyType, - valueType: valueType, - parameterName: parameterName - ) - - case .set(let elementType): - return try translateSetParameter( - elementType: elementType, - parameterName: parameterName - ) - case .metatype: return NativeParameter( parameters: [ @@ -672,7 +635,7 @@ extension JNISwift2JavaGenerator { outParameters: [] ) - case .function, .metatype, .optional, .tuple, .existential, .opaque, .genericParameter, .composite, .array, .dictionary, .set: + case .function, .metatype, .tuple, .existential, .opaque, .genericParameter, .composite: throw JavaTranslationError.unsupportedSwiftType(type) } } @@ -704,7 +667,7 @@ extension JNISwift2JavaGenerator { // Custom types are not supported yet. throw JavaTranslationError.unsupportedSwiftType(type) - case .function, .metatype, .optional, .tuple, .existential, .opaque, .genericParameter, .composite, .array, .dictionary, .set: + case .function, .metatype, .tuple, .existential, .opaque, .genericParameter, .composite: throw JavaTranslationError.unsupportedSwiftType(type) } } @@ -715,36 +678,24 @@ extension JNISwift2JavaGenerator { ) throws -> NativeResult { switch swiftResult.type { case .nominal(let nominalType): - if let knownType = nominalType.nominalTypeDecl.knownTypeKind { + if let knownType = nominalType.asKnownType { switch knownType { - case .optional: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.unsupportedSwiftType(swiftResult.type) - } - return try translateOptionalResult(wrappedType: genericArgs[0], resultName: resultName) + case .optional(let wrapped): + return try translateOptionalResult(wrappedType: wrapped, resultName: resultName) - case .array: - guard let elementType = nominalType.genericArguments?.first else { - throw JavaTranslationError.unsupportedSwiftType(swiftResult.type) - } + case .array(let elementType): return try translateArrayResult(elementType: elementType, resultName: resultName) - case .dictionary: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 2 else { - throw JavaTranslationError.dictionaryRequiresKeyAndValueTypes(swiftResult.type) - } + case .dictionary(let keyType, let valueType): return try translateDictionaryResult( - keyType: genericArgs[0], - valueType: genericArgs[1], + keyType: keyType, + valueType: valueType, resultName: resultName ) - case .set: - guard let genericArgs = nominalType.genericArguments, genericArgs.count == 1 else { - throw JavaTranslationError.setRequiresElementType(swiftResult.type) - } + case .set(let elementType): return try translateSetResult( - elementType: genericArgs[0], + elementType: elementType, resultName: resultName ) @@ -760,14 +711,14 @@ extension JNISwift2JavaGenerator { ) default: - guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config), + guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType.kind, config: self.config), javaType.implementsJavaValue else { throw JavaTranslationError.unsupportedSwiftType(swiftResult.type) } if let indirectReturnType = JNIJavaTypeTranslator.indirectConversionStepSwiftType( - for: knownType, + for: knownType.kind, from: knownTypes ) { return NativeResult( @@ -814,25 +765,6 @@ extension JNISwift2JavaGenerator { outParameters: [] ) - case .optional(let wrapped): - return try translateOptionalResult(wrappedType: wrapped, resultName: resultName) - - case .array(let elementType): - return try translateArrayResult(elementType: elementType, resultName: resultName) - - case .dictionary(let keyType, let valueType): - return try translateDictionaryResult( - keyType: keyType, - valueType: valueType, - resultName: resultName - ) - - case .set(let elementType): - return try translateSetResult( - elementType: elementType, - resultName: resultName - ) - case .tuple(let elements) where !elements.isEmpty: return try translateTupleResult(elements: elements, resultName: resultName) @@ -911,7 +843,7 @@ extension JNISwift2JavaGenerator { guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config), javaType.implementsJavaValue else { - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) } return NativeResult( @@ -922,7 +854,7 @@ extension JNISwift2JavaGenerator { } guard !nominalType.isSwiftJavaWrapper else { - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) } // Assume JExtract imported class @@ -948,7 +880,7 @@ extension JNISwift2JavaGenerator { ) default: - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + throw JavaTranslationError.unsupportedSwiftType(known: .array(elementType)) } } @@ -969,21 +901,21 @@ extension JNISwift2JavaGenerator { parameters: [ JavaParameter(name: parameterName, type: .array(javaType)) ], - conversion: .initFromJNI(.placeholder, swiftType: .array(elementType)), + conversion: .initFromJNI(.placeholder, swiftType: knownTypes.arraySugar(elementType)), indirectConversion: nil, conversionCheck: nil ) } guard !nominalType.isSwiftJavaWrapper else { - throw JavaTranslationError.unsupportedSwiftType(.array(elementType)) + throw JavaTranslationError.unsupportedSwiftType(knownTypes.arraySugar(elementType)) } // Assume JExtract wrapped class return NativeParameter( parameters: [JavaParameter(name: parameterName, type: .array(.long))], conversion: .method( - .initFromJNI(.placeholder, swiftType: .array(self.knownTypes.int64)), + .initFromJNI(.placeholder, swiftType: knownTypes.arraySugar(self.knownTypes.int64)), function: "map", arguments: [ ( @@ -1020,7 +952,7 @@ extension JNISwift2JavaGenerator { parameters: [ JavaParameter(name: parameterName, type: .long) ], - conversion: .initFromJNI(.placeholder, swiftType: .dictionary(key: keyType, value: valueType)), + conversion: .initFromJNI(.placeholder, swiftType: knownTypes.dictionarySugar(keyType, valueType)), indirectConversion: nil, conversionCheck: nil ) @@ -1050,7 +982,7 @@ extension JNISwift2JavaGenerator { parameters: [ JavaParameter(name: parameterName, type: .long) ], - conversion: .initFromJNI(.placeholder, swiftType: .set(element: elementType)), + conversion: .initFromJNI(.placeholder, swiftType: knownTypes.set(elementType)), indirectConversion: nil, conversionCheck: nil ) diff --git a/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift index 18cf5991..ff4de215 100644 --- a/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift +++ b/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift @@ -151,9 +151,12 @@ extension Swift2JavaTranslator { func check(_ type: SwiftType) -> Bool { switch type { case .nominal(let nominal): + if let genericArguments = nominal.genericArguments { + if genericArguments.contains(where: check) { + return true + } + } return predicate(nominal.nominalTypeDecl) - case .optional(let ty): - return check(ty) case .tuple(let tuple): return tuple.contains(where: { check($0.type) }) case .function(let fn): @@ -166,12 +169,6 @@ extension Swift2JavaTranslator { return types.contains(where: check) case .genericParameter: return false - case .array(let ty): - return check(ty) - case .dictionary(let key, let value): - return check(key) || check(value) - case .set(let element): - return check(element) } } diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift index 5c285a7d..805f0b49 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift @@ -96,7 +96,13 @@ extension SwiftFunctionSignature { lookupContext: lookupContext ) - let type = node.optionalMark != nil ? .optional(enclosingType) : enclosingType + let type: SwiftType = + if node.optionalMark != nil { + SwiftKnownTypes(symbolTable: lookupContext.symbolTable) + .optionalSugar(enclosingType) + } else { + enclosingType + } self.init( selfParameter: .initializer(enclosingType), diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypeDecls.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypeDecls.swift index 2b41e12b..c0c1eaad 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypeDecls.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypeDecls.swift @@ -14,6 +14,142 @@ import SwiftSyntax +enum SwiftKnownType: Equatable { + case bool + case int + case uint + case int8 + case uint8 + case int16 + case uint16 + case int32 + case uint32 + case int64 + case uint64 + case float + case double + case unsafeRawPointer + case unsafeRawBufferPointer + case unsafeMutableRawPointer + case unsafeMutableRawBufferPointer + case unsafePointer(_ pointee: SwiftType) + case unsafeMutablePointer(_ pointee: SwiftType) + case unsafeBufferPointer(_ element: SwiftType) + case unsafeMutableBufferPointer(_ element: SwiftType) + case optional(_ wrapped: SwiftType) + case void + case string + case array(_ element: SwiftType) + case dictionary(_ key: SwiftType, _ value: SwiftType) + case set(_ element: SwiftType) + + // Foundation + case foundationDataProtocol + case essentialsDataProtocol + case foundationData + case essentialsData + case foundationDate + case essentialsDate + case foundationUUID + case essentialsUUID + + init?(kind: SwiftKnownTypeDeclKind, genericArguments: [SwiftType]?) { + switch kind { + case .bool: self = .bool + case .int: self = .int + case .uint: self = .uint + case .int8: self = .int8 + case .uint8: self = .uint8 + case .int16: self = .int16 + case .uint16: self = .uint16 + case .int32: self = .int32 + case .uint32: self = .uint32 + case .int64: self = .int64 + case .uint64: self = .uint64 + case .float: self = .float + case .double: self = .double + case .unsafeRawPointer: self = .unsafeRawPointer + case .unsafeRawBufferPointer: self = .unsafeRawBufferPointer + case .unsafeMutableRawPointer: self = .unsafeMutableRawPointer + case .unsafeMutableRawBufferPointer: self = .unsafeMutableRawBufferPointer + case .unsafePointer: + guard let arg = genericArguments?.first else { return nil } + self = .unsafePointer(arg) + case .unsafeMutablePointer: + guard let arg = genericArguments?.first else { return nil } + self = .unsafeMutablePointer(arg) + case .unsafeBufferPointer: + guard let arg = genericArguments?.first else { return nil } + self = .unsafeBufferPointer(arg) + case .unsafeMutableBufferPointer: + guard let arg = genericArguments?.first else { return nil } + self = .unsafeMutableBufferPointer(arg) + case .optional: + guard let arg = genericArguments?.first else { return nil } + self = .optional(arg) + case .void: self = .void + case .string: self = .string + case .array: + guard let arg = genericArguments?.first else { return nil } + self = .array(arg) + case .dictionary: + guard let key = genericArguments?.first, let value = genericArguments?.dropFirst().first else { return nil } + self = .dictionary(key, value) + case .set: + guard let arg = genericArguments?.first else { return nil } + self = .set(arg) + case .foundationDataProtocol: self = .foundationDataProtocol + case .essentialsDataProtocol: self = .essentialsDataProtocol + case .foundationData: self = .foundationData + case .essentialsData: self = .essentialsData + case .foundationDate: self = .foundationDate + case .essentialsDate: self = .essentialsDate + case .foundationUUID: self = .foundationUUID + case .essentialsUUID: self = .essentialsUUID + } + } + + var kind: SwiftKnownTypeDeclKind { + switch self { + case .bool: .bool + case .int: .int + case .uint: .uint + case .int8: .int8 + case .uint8: .uint8 + case .int16: .int16 + case .uint16: .uint16 + case .int32: .int32 + case .uint32: .uint32 + case .int64: .int64 + case .uint64: .uint64 + case .float: .float + case .double: .double + case .unsafeRawPointer: .unsafeRawPointer + case .unsafeRawBufferPointer: .unsafeRawBufferPointer + case .unsafeMutableRawPointer: .unsafeMutableRawPointer + case .unsafeMutableRawBufferPointer: .unsafeMutableRawBufferPointer + case .unsafePointer: .unsafePointer + case .unsafeMutablePointer: .unsafeMutablePointer + case .unsafeBufferPointer: .unsafeBufferPointer + case .unsafeMutableBufferPointer: .unsafeMutableBufferPointer + case .optional: .optional + case .void: .void + case .string: .string + case .array: .array + case .dictionary: .dictionary + case .set: .set + case .foundationDataProtocol: .foundationDataProtocol + case .essentialsDataProtocol: .essentialsDataProtocol + case .foundationData: .foundationData + case .essentialsData: .essentialsData + case .foundationDate: .foundationDate + case .essentialsDate: .essentialsDate + case .foundationUUID: .foundationUUID + case .essentialsUUID: .essentialsUUID + } + } +} + enum SwiftKnownTypeDeclKind: String, Hashable { // Swift case bool = "Swift.Bool" diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypes.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypes.swift index edf75f0f..a1a21fd6 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypes.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftKnownTypes.swift @@ -104,6 +104,45 @@ struct SwiftKnownTypes { ) } + func optionalSugar(_ wrappedType: SwiftType) -> SwiftType { + .nominal( + SwiftNominalType( + sugarName: .optional, + nominalTypeDecl: symbolTable[.optional], + genericArguments: [wrappedType] + ) + ) + } + + func arraySugar(_ elementType: SwiftType) -> SwiftType { + .nominal( + SwiftNominalType( + sugarName: .array, + nominalTypeDecl: symbolTable[.array], + genericArguments: [elementType] + ) + ) + } + + func dictionarySugar(_ keyType: SwiftType, _ valueType: SwiftType) -> SwiftType { + .nominal( + SwiftNominalType( + sugarName: .dictionary, + nominalTypeDecl: symbolTable[.dictionary], + genericArguments: [keyType, valueType] + ) + ) + } + + func set(_ elementType: SwiftType) -> SwiftType { + .nominal( + SwiftNominalType( + nominalTypeDecl: symbolTable[.set], + genericArguments: [elementType] + ) + ) + } + /// Returns the known representative concrete type if there is one for the /// given protocol kind. E.g. `String` for `StringProtocol` func representativeType(of knownProtocol: SwiftKnownTypeDeclKind) -> SwiftType? { diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift index 78ae5289..d4414971 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift @@ -169,6 +169,16 @@ package class SwiftNominalTypeDeclaration: SwiftTypeDeclaration { } } +extension SwiftNominalTypeDeclaration: CustomStringConvertible { + package var description: String { + if isGeneric { + "\(qualifiedName)<\(genericParameters.map(\.name).joined(separator: ", "))>" + } else { + qualifiedName + } + } +} + package class SwiftGenericParameterDeclaration: SwiftTypeDeclaration { let syntax: GenericParameterSyntax diff --git a/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift index f3328c8d..13e7aada 100644 --- a/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift +++ b/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift @@ -38,9 +38,6 @@ enum SwiftType: Equatable { /// `.Type` indirect case metatype(SwiftType) - /// `?` - indirect case optional(SwiftType) - /// `(