|
27 | 27 | #include "swift/AST/ASTMangler.h"
|
28 | 28 | #include "swift/AST/DiagnosticsSIL.h"
|
29 | 29 | #include "swift/AST/FileUnit.h"
|
| 30 | +#include "swift/AST/ForeignAsyncConvention.h" |
30 | 31 | #include "swift/AST/GenericEnvironment.h"
|
31 | 32 | #include "swift/SIL/PrettyStackTrace.h"
|
32 | 33 | #include "swift/SIL/SILArgument.h"
|
@@ -141,7 +142,8 @@ SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant,
|
141 | 142 | SILFunction *
|
142 | 143 | SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
|
143 | 144 | CanSILFunctionType blockType,
|
144 |
| - CanType continuationTy) { |
| 145 | + CanType continuationTy, |
| 146 | + ForeignAsyncConvention convention) { |
145 | 147 | // Extract the result type from the continuation type.
|
146 | 148 | auto resumeType = cast<BoundGenericType>(continuationTy).getGenericArgs()[0];
|
147 | 149 |
|
@@ -184,10 +186,125 @@ SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction(
|
184 | 186 | if (F->empty()) {
|
185 | 187 | // TODO: Emit the implementation.
|
186 | 188 | SILGenFunction SGF(*this, *F, SwiftModule);
|
187 |
| - SmallVector<ManagedValue, 4> params; |
188 |
| - SGF.collectThunkParams(loc, params); |
| 189 | + { |
| 190 | + Scope scope(SGF, loc); |
| 191 | + SmallVector<ManagedValue, 4> params; |
| 192 | + SGF.collectThunkParams(loc, params); |
189 | 193 |
|
190 |
| - SGF.B.createUnreachable(loc); |
| 194 | + // Get the continuation out of the block object. |
| 195 | + auto blockStorage = params[0].getValue(); |
| 196 | + auto continuationAddr = SGF.B.createProjectBlockStorage(loc, blockStorage); |
| 197 | + auto continuationVal = SGF.B.createLoad(loc, continuationAddr, |
| 198 | + LoadOwnershipQualifier::Trivial); |
| 199 | + auto continuation = ManagedValue::forUnmanaged(continuationVal); |
| 200 | + |
| 201 | + // Check for an error if the convention includes one. |
| 202 | + auto errorIndex = convention.completionHandlerErrorParamIndex(); |
| 203 | + |
| 204 | + FuncDecl *resumeIntrinsic, *errorIntrinsic; |
| 205 | + |
| 206 | + SILBasicBlock *returnBB = nullptr; |
| 207 | + if (errorIndex) { |
| 208 | + resumeIntrinsic = getResumeUnsafeThrowingContinuation(); |
| 209 | + errorIntrinsic = getResumeUnsafeThrowingContinuationWithError(); |
| 210 | + |
| 211 | + auto errorArgument = params[*errorIndex + 1]; |
| 212 | + auto someErrorBB = SGF.createBasicBlock(FunctionSection::Postmatter); |
| 213 | + auto noneErrorBB = SGF.createBasicBlock(); |
| 214 | + returnBB = SGF.createBasicBlockAfter(noneErrorBB); |
| 215 | + |
| 216 | + auto &C = SGF.getASTContext(); |
| 217 | + std::pair<EnumElementDecl *, SILBasicBlock *> switchErrorBBs[] = { |
| 218 | + {C.getOptionalSomeDecl(), someErrorBB}, |
| 219 | + {C.getOptionalNoneDecl(), noneErrorBB} |
| 220 | + }; |
| 221 | + |
| 222 | + SGF.B.createSwitchEnum(loc, errorArgument.borrow(SGF, loc).getValue(), |
| 223 | + /*default*/ nullptr, |
| 224 | + switchErrorBBs); |
| 225 | + |
| 226 | + SGF.B.emitBlock(someErrorBB); |
| 227 | + |
| 228 | + auto matchedErrorTy = errorArgument.getType().getOptionalObjectType(); |
| 229 | + auto matchedError = SGF.B |
| 230 | + .createGuaranteedTransformingTerminatorArgument(matchedErrorTy); |
| 231 | + |
| 232 | + // Resume the continuation as throwing the given error, bridged to a |
| 233 | + // native Swift error. |
| 234 | + auto nativeError = SGF.emitBridgedToNativeError(loc, matchedError); |
| 235 | + Type replacementTypes[] = {resumeType}; |
| 236 | + auto subs = SubstitutionMap::get(errorIntrinsic->getGenericSignature(), |
| 237 | + replacementTypes, |
| 238 | + ArrayRef<ProtocolConformanceRef>{}); |
| 239 | + SGF.emitApplyOfLibraryIntrinsic(loc, errorIntrinsic, subs, |
| 240 | + {continuation, nativeError}, |
| 241 | + SGFContext()); |
| 242 | + |
| 243 | + SGF.B.createBranch(loc, returnBB); |
| 244 | + SGF.B.emitBlock(noneErrorBB); |
| 245 | + } else { |
| 246 | + resumeIntrinsic = getResumeUnsafeContinuation(); |
| 247 | + } |
| 248 | + |
| 249 | + auto loweredResumeTy = SGF.getLoweredType(AbstractionPattern::getOpaque(), |
| 250 | + resumeType); |
| 251 | + |
| 252 | + // Prepare the argument for the resume intrinsic, using the non-error |
| 253 | + // arguments to the callback. |
| 254 | + { |
| 255 | + Scope resumeScope(SGF, loc); |
| 256 | + unsigned errorIndexBoundary = errorIndex ? *errorIndex : ~0u; |
| 257 | + auto resumeArgBuf = SGF.emitTemporaryAllocation(loc, |
| 258 | + loweredResumeTy.getAddressType()); |
| 259 | + |
| 260 | + auto prepareArgument = [&](SILValue destBuf, ManagedValue arg) { |
| 261 | + // Convert the ObjC argument to the bridged Swift representation we |
| 262 | + // want. |
| 263 | + ManagedValue bridgedArg = SGF.emitBridgedToNativeValue(loc, |
| 264 | + arg, |
| 265 | + arg.getType().getASTType(), |
| 266 | + // FIXME: pass down formal type |
| 267 | + destBuf->getType().getASTType(), |
| 268 | + destBuf->getType().getObjectType()); |
| 269 | + bridgedArg.forwardInto(SGF, loc, destBuf); |
| 270 | + }; |
| 271 | + |
| 272 | + if (auto resumeTuple = dyn_cast<TupleType>(resumeType)) { |
| 273 | + assert(params.size() == resumeTuple->getNumElements() |
| 274 | + + 1 + (bool)errorIndex); |
| 275 | + for (auto i : indices(resumeTuple.getElementTypes())) { |
| 276 | + auto resumeEltBuf = SGF.B.createTupleElementAddr(loc, |
| 277 | + resumeArgBuf, i); |
| 278 | + auto arg = params[1 + i + (i >= errorIndexBoundary)]; |
| 279 | + prepareArgument(resumeEltBuf, arg); |
| 280 | + } |
| 281 | + } else { |
| 282 | + assert(params.size() == 2 + (bool)errorIndex); |
| 283 | + prepareArgument(resumeArgBuf, params[1 + (errorIndexBoundary == 0)]); |
| 284 | + } |
| 285 | + |
| 286 | + |
| 287 | + // Resume the continuation with the composed bridged result. |
| 288 | + ManagedValue resumeArg = SGF.emitManagedBufferWithCleanup(resumeArgBuf); |
| 289 | + Type replacementTypes[] = {resumeType}; |
| 290 | + auto subs = SubstitutionMap::get(resumeIntrinsic->getGenericSignature(), |
| 291 | + replacementTypes, |
| 292 | + ArrayRef<ProtocolConformanceRef>{}); |
| 293 | + SGF.emitApplyOfLibraryIntrinsic(loc, resumeIntrinsic, subs, |
| 294 | + {continuation, resumeArg}, |
| 295 | + SGFContext()); |
| 296 | + } |
| 297 | + |
| 298 | + // Now we've resumed the continuation one way or another. Return from the |
| 299 | + // completion callback. |
| 300 | + if (returnBB) { |
| 301 | + SGF.B.createBranch(loc, returnBB); |
| 302 | + SGF.B.emitBlock(returnBB); |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + SGF.B.createReturn(loc, |
| 307 | + SILUndef::get(SGF.SGM.Types.getEmptyTupleType(), SGF.F)); |
191 | 308 | }
|
192 | 309 |
|
193 | 310 | return F;
|
|
0 commit comments