@@ -253,6 +253,12 @@ struct CdeclLowering {
253253 ]
254254 ) )
255255
256+ case . optional:
257+ guard let genericArgs = type. asNominalType? . genericArguments, genericArgs. count == 1 else {
258+ throw LoweringError . unhandledType ( type)
259+ }
260+ return try lowerOptionalParameter ( genericArgs [ 0 ] , convention: convention, parameterName: parameterName)
261+
256262 case . string:
257263 // 'String' is passed in by C string. i.e. 'UnsafePointer<Int8>' ('const uint8_t *')
258264 if knownType == . string {
@@ -336,8 +342,79 @@ struct CdeclLowering {
336342 }
337343 throw LoweringError . unhandledType ( type)
338344
339- case . optional:
340- throw LoweringError . unhandledType ( type)
345+ case . optional( let wrapped) :
346+ return try lowerOptionalParameter ( wrapped, convention: convention, parameterName: parameterName)
347+ }
348+ }
349+
350+ /// Lower a Swift Optional to cdecl function type.
351+ ///
352+ /// - Parameters:
353+ /// - fn: the Swift function type to lower.
354+ func lowerOptionalParameter(
355+ _ wrappedType: SwiftType ,
356+ convention: SwiftParameterConvention ,
357+ parameterName: String
358+ ) throws -> LoweredParameter {
359+ // If there is a 1:1 mapping between this Swift type and a C type, lower it to 'UnsafePointer<T>?'
360+ if let _ = try ? CType ( cdeclType: wrappedType) {
361+ return LoweredParameter (
362+ cdeclParameters: [
363+ SwiftParameter ( convention: . byValue, parameterName: parameterName, type: . optional( knownTypes. unsafePointer ( wrappedType) ) )
364+ ] ,
365+ conversion: . pointee( . optionalChain( . placeholder) )
366+ )
367+ }
368+
369+ switch wrappedType {
370+ case . nominal( let nominal) :
371+ if let knownType = nominal. nominalTypeDecl. knownTypeKind {
372+ switch knownType {
373+ case . data:
374+ break
375+ case . unsafeRawPointer, . unsafeMutableRawPointer:
376+ throw LoweringError . unhandledType ( . optional( wrappedType) )
377+ case . unsafeRawBufferPointer, . unsafeMutableRawBufferPointer:
378+ throw LoweringError . unhandledType ( . optional( wrappedType) )
379+ case . unsafePointer, . unsafeMutablePointer:
380+ throw LoweringError . unhandledType ( . optional( wrappedType) )
381+ case . unsafeBufferPointer, . unsafeMutableBufferPointer:
382+ throw LoweringError . unhandledType ( . optional( wrappedType) )
383+ case . void, . string:
384+ throw LoweringError . unhandledType ( . optional( wrappedType) )
385+ case . dataProtocol:
386+ throw LoweringError . unhandledType ( . optional( wrappedType) )
387+ default :
388+ // Unreachable? Should be handled by `CType(cdeclType:)` lowering above.
389+ throw LoweringError . unhandledType ( . optional( wrappedType) )
390+ }
391+ }
392+
393+ // Lower arbitrary nominal to `UnsafeRawPointer?`
394+ return LoweredParameter (
395+ cdeclParameters: [
396+ SwiftParameter ( convention: . byValue, parameterName: parameterName, type: . optional( knownTypes. unsafeRawPointer) )
397+ ] ,
398+ conversion: . pointee( . typedPointer( . optionalChain( . placeholder) , swiftType: wrappedType) )
399+ )
400+
401+ case . existential( let proto) , . opaque( let proto) :
402+ if
403+ let knownProtocol = proto. asNominalTypeDeclaration? . knownTypeKind,
404+ let concreteTy = knownTypes. representativeType ( of: knownProtocol)
405+ {
406+ return try lowerOptionalParameter ( concreteTy, convention: convention, parameterName: parameterName)
407+ }
408+ throw LoweringError . unhandledType ( . optional( wrappedType) )
409+
410+ case . tuple( let tuple) :
411+ if tuple. count == 1 {
412+ return try lowerOptionalParameter ( tuple [ 0 ] , convention: convention, parameterName: parameterName)
413+ }
414+ throw LoweringError . unhandledType ( . optional( wrappedType) )
415+
416+ case . function, . metatype, . optional:
417+ throw LoweringError . unhandledType ( . optional( wrappedType) )
341418 }
342419 }
343420
@@ -527,13 +604,13 @@ struct CdeclLowering {
527604 case . void:
528605 return LoweredResult ( cdeclResultType: . void, cdeclOutParameters: [ ] , conversion: . placeholder)
529606
530- case . string:
531- // Returning string is not supported at this point.
532- throw LoweringError . unhandledType ( type)
533-
534607 case . data:
535608 break
536609
610+ case . string, . optional:
611+ // Not supported at this point.
612+ throw LoweringError . unhandledType ( type)
613+
537614 default :
538615 // Unreachable? Should be handled by `CType(cdeclType:)` lowering above.
539616 throw LoweringError . unhandledType ( type)
0 commit comments