diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index e48750a4ccc05..989b6e0f19804 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -336,10 +336,17 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF, SILLocation loc, /// Get the type of each parameter, filtering out empty tuples. static SmallVector -getParameterTypes(AnyFunctionType::CanParamArrayRef params) { +getParameterTypes(AnyFunctionType::CanParamArrayRef params, + bool hasSelfParam=false) { SmallVector results; - for (auto param : params) { - assert(!param.isInOut() && !param.isVariadic()); + for (auto n : indices(params)) { + bool isSelf = (hasSelfParam ? n == params.size() - 1 : false); + + const auto ¶m = params[n]; + assert(isSelf || !param.isInOut() && + "Only the 'self' parameter can be inout in a bridging thunk"); + assert(!param.isVariadic()); + if (param.getPlainType()->isVoid()) continue; results.push_back(param.getPlainType()); @@ -1723,10 +1730,11 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { }; { + bool hasSelfParam = fd->hasImplicitSelfDecl(); auto foreignFormalParams = - getParameterTypes(foreignCI.LoweredType.getParams()); + getParameterTypes(foreignCI.LoweredType.getParams(), hasSelfParam); auto nativeFormalParams = - getParameterTypes(nativeCI.LoweredType.getParams()); + getParameterTypes(nativeCI.LoweredType.getParams(), hasSelfParam); for (unsigned nativeParamIndex : indices(params)) { // Bring the parameter to +1. @@ -1762,7 +1770,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { maybeAddForeignErrorArg(); - bool isSelf = nativeParamIndex == params.size() - 1; + bool isSelf = (hasSelfParam && nativeParamIndex == params.size() - 1); if (memberStatus.isInstance()) { // Leave space for `self` to be filled in later. @@ -1787,6 +1795,12 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { F.mapTypeIntoContext(foreignFormalParams[nativeParamIndex]) ->getCanonicalType(); + if (isSelf) { + assert(!nativeCI.LoweredType.getParams()[nativeParamIndex].isInOut() || + nativeFormalType == foreignFormalType && + "Cannot bridge 'self' parameter if passed inout"); + } + auto foreignParam = foreignFnTy->getParameters()[foreignArgIndex++]; SILType foreignLoweredTy = F.mapTypeIntoContext(foreignParam.getSILStorageType( diff --git a/test/SILGen/Inputs/foreign_to_native_inout_self_helper.h b/test/SILGen/Inputs/foreign_to_native_inout_self_helper.h new file mode 100644 index 0000000000000..fc6400f50beb5 --- /dev/null +++ b/test/SILGen/Inputs/foreign_to_native_inout_self_helper.h @@ -0,0 +1,3 @@ +typedef struct {} MyIterator __attribute__((swift_name("MyIterator"))); + +void MyIteratorNext(MyIterator *self) __attribute__((swift_name("MyIterator.next(self:)"))); diff --git a/test/SILGen/foreign_to_native_inout_self.swift b/test/SILGen/foreign_to_native_inout_self.swift new file mode 100644 index 0000000000000..5044d7f1b02c9 --- /dev/null +++ b/test/SILGen/foreign_to_native_inout_self.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-frontend -emit-silgen %s -import-objc-header %S/Inputs/foreign_to_native_inout_self_helper.h | %FileCheck %s + +protocol FakeIterator { + mutating func next() +} + +extension MyIterator : FakeIterator {} + +// CHECK-LABEL: sil shared [serializable] [thunk] [ossa] @$sSo10MyIteratora4nextyyFTO : $@convention(method) (@inout MyIterator) -> () { +// CHECK: bb0(%0 : $*MyIterator): +// CHECK: [[FN:%.*]] = function_ref @MyIteratorNext : $@convention(c) (@inout MyIterator) -> () +// CHECK: apply [[FN]](%0) : $@convention(c) (@inout MyIterator) -> () +// CHECK: [[RESULT:%.*]] = tuple () +// CHECK: return [[RESULT]] : $() +// CHECK: } \ No newline at end of file