@@ -98,18 +98,22 @@ struct CdeclLowering {
9898 try lowerParameter (
9999 selfParameter. type,
100100 convention: selfParameter. convention,
101- parameterName: selfParameter. parameterName ?? " self "
101+ parameterName: selfParameter. parameterName ?? " self " ,
102+ genericParameters: signature. genericParameters,
103+ genericRequirements: signature. genericRequirements
102104 )
103105 case nil , . initializer( _) , . staticMethod( _) :
104106 nil
105107 }
106108
107109 // Lower all of the parameters.
108110 let loweredParameters = try signature. parameters. enumerated ( ) . map { ( index, param) in
109- try lowerParameter (
111+ return try lowerParameter (
110112 param. type,
111113 convention: param. convention,
112- parameterName: param. parameterName ?? " _ \( index) "
114+ parameterName: param. parameterName ?? " _ \( index) " ,
115+ genericParameters: signature. genericParameters,
116+ genericRequirements: signature. genericRequirements
113117 )
114118 }
115119
@@ -142,7 +146,9 @@ struct CdeclLowering {
142146 func lowerParameter(
143147 _ type: SwiftType ,
144148 convention: SwiftParameterConvention ,
145- parameterName: String
149+ parameterName: String ,
150+ genericParameters: [ SwiftGenericParameterDeclaration ] ,
151+ genericRequirements: [ SwiftGenericRequirement ]
146152 ) throws -> LoweredParameter {
147153 // If there is a 1:1 mapping between this Swift type and a C type, we just
148154 // return it.
@@ -257,7 +263,7 @@ struct CdeclLowering {
257263 guard let genericArgs = nominal. genericArguments, genericArgs. count == 1 else {
258264 throw LoweringError . unhandledType ( type)
259265 }
260- return try lowerOptionalParameter ( genericArgs [ 0 ] , convention: convention, parameterName: parameterName)
266+ return try lowerOptionalParameter ( genericArgs [ 0 ] , convention: convention, parameterName: parameterName, genericParameters : genericParameters , genericRequirements : genericRequirements )
261267
262268 case . string:
263269 // 'String' is passed in by C string. i.e. 'UnsafePointer<Int8>' ('const uint8_t *')
@@ -300,7 +306,7 @@ struct CdeclLowering {
300306
301307 case . tuple( let tuple) :
302308 if tuple. count == 1 {
303- return try lowerParameter ( tuple [ 0 ] , convention: convention, parameterName: parameterName)
309+ return try lowerParameter ( tuple [ 0 ] , convention: convention, parameterName: parameterName, genericParameters : genericParameters , genericRequirements : genericRequirements )
304310 }
305311 if convention == . inout {
306312 throw LoweringError . inoutNotSupported ( type)
@@ -310,7 +316,7 @@ struct CdeclLowering {
310316 for (idx, element) in tuple. enumerated ( ) {
311317 // FIXME: Use tuple element label.
312318 let cdeclName = " \( parameterName) _ \( idx) "
313- let lowered = try lowerParameter ( element, convention: convention, parameterName: cdeclName)
319+ let lowered = try lowerParameter ( element, convention: convention, parameterName: cdeclName, genericParameters : genericParameters , genericRequirements : genericRequirements )
314320
315321 parameters. append ( contentsOf: lowered. cdeclParameters)
316322 conversions. append ( lowered. conversion)
@@ -330,23 +336,14 @@ struct CdeclLowering {
330336 conversion: conversion
331337 )
332338
333- case . opaque( let proto) , . existential( let proto) :
334- // If the protocol has a known representative implementation, e.g. `String` for `StringProtocol`
335- // Translate it as the concrete type.
336- // NOTE: This is a temporary workaround until we add support for generics.
337- if
338- let knownProtocol = proto. asNominalTypeDeclaration? . knownTypeKind,
339- let concreteTy = knownTypes. representativeType ( of: knownProtocol)
340- {
341- return try lowerParameter ( concreteTy, convention: convention, parameterName: parameterName)
339+ case . opaque, . existential, . genericParameter:
340+ if let concreteTy = representativeConcreteType ( type, genericParameters: genericParameters, genericRequirements: genericRequirements) {
341+ return try lowerParameter ( concreteTy, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
342342 }
343343 throw LoweringError . unhandledType ( type)
344344
345345 case . optional( let wrapped) :
346- return try lowerOptionalParameter ( wrapped, convention: convention, parameterName: parameterName)
347-
348- case . genericParameter:
349- throw LoweringError . unhandledType ( type)
346+ return try lowerOptionalParameter ( wrapped, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
350347 }
351348 }
352349
@@ -357,7 +354,9 @@ struct CdeclLowering {
357354 func lowerOptionalParameter(
358355 _ wrappedType: SwiftType ,
359356 convention: SwiftParameterConvention ,
360- parameterName: String
357+ parameterName: String ,
358+ genericParameters: [ SwiftGenericParameterDeclaration ] ,
359+ genericRequirements: [ SwiftGenericRequirement ]
361360 ) throws -> LoweredParameter {
362361 // If there is a 1:1 mapping between this Swift type and a C type, lower it to 'UnsafePointer<T>?'
363362 if let _ = try ? CType ( cdeclType: wrappedType) {
@@ -401,26 +400,59 @@ struct CdeclLowering {
401400 conversion: . pointee( . typedPointer( . optionalChain( . placeholder) , swiftType: wrappedType) )
402401 )
403402
404- case . existential( let proto) , . opaque( let proto) :
405- if
406- let knownProtocol = proto. asNominalTypeDeclaration? . knownTypeKind,
407- let concreteTy = knownTypes. representativeType ( of: knownProtocol)
408- {
409- return try lowerOptionalParameter ( concreteTy, convention: convention, parameterName: parameterName)
403+ case . existential, . opaque, . genericParameter:
404+ if let concreteTy = representativeConcreteType ( wrappedType, genericParameters: genericParameters, genericRequirements: genericRequirements) {
405+ return try lowerOptionalParameter ( concreteTy, convention: convention, parameterName: parameterName, genericParameters: genericParameters, genericRequirements: genericRequirements)
410406 }
411407 throw LoweringError . unhandledType ( . optional( wrappedType) )
412408
413409 case . tuple( let tuple) :
414410 if tuple. count == 1 {
415- return try lowerOptionalParameter ( tuple [ 0 ] , convention: convention, parameterName: parameterName)
411+ return try lowerOptionalParameter ( tuple [ 0 ] , convention: convention, parameterName: parameterName, genericParameters : genericParameters , genericRequirements : genericRequirements )
416412 }
417413 throw LoweringError . unhandledType ( . optional( wrappedType) )
418414
419- case . function, . metatype, . optional, . genericParameter :
415+ case . function, . metatype, . optional:
420416 throw LoweringError . unhandledType ( . optional( wrappedType) )
421417 }
422418 }
423419
420+ /// Returns a concrete type if the specified type is a generic parameter that
421+ /// conforms to a protocol with representative concrete type.
422+ func representativeConcreteType(
423+ _ type: SwiftType ,
424+ genericParameters: [ SwiftGenericParameterDeclaration ] ,
425+ genericRequirements: [ SwiftGenericRequirement ]
426+ ) -> SwiftType ? {
427+ var maybeProto : SwiftType ? = nil
428+ switch type {
429+ case . existential( let proto) , . opaque( let proto) :
430+ maybeProto = proto
431+ case . genericParameter( let genericParam) :
432+ // If the type is a generic parameter declared in this function and
433+ // conforms to a protocol with representative concrete type, use it.
434+ if genericParameters. contains ( genericParam) {
435+ for requirement in genericRequirements {
436+ if case . inherits( let left, let right) = requirement, left == type {
437+ guard maybeProto == nil else {
438+ // multiple requirements on the generic parameter.
439+ return nil
440+ }
441+ maybeProto = right
442+ break
443+ }
444+ }
445+ }
446+ default :
447+ return nil
448+ }
449+
450+ if let knownProtocol = maybeProto? . asNominalTypeDeclaration? . knownTypeKind {
451+ return knownTypes. representativeType ( of: knownProtocol)
452+ }
453+ return nil
454+ }
455+
424456 /// Lower a Swift function type (i.e. closure) to cdecl function type.
425457 ///
426458 /// - Parameters:
@@ -757,7 +789,9 @@ public struct LoweredFunctionSignature: Equatable {
757789 selfParameter: nil ,
758790 parameters: allLoweredParameters,
759791 result: SwiftResult ( convention: . direct, type: result. cdeclResultType) ,
760- effectSpecifiers: [ ]
792+ effectSpecifiers: [ ] ,
793+ genericParameters: [ ] ,
794+ genericRequirements: [ ]
761795 )
762796 }
763797}
0 commit comments