/// Emit a store of a native error to the foreign-error slot. static void emitStoreToForeignErrorSlot(SILGenFunction &gen, SILLocation loc, SILValue foreignErrorSlot, const BridgedErrorSource &errorSrc) { ASTContext &ctx = gen.getASTContext(); // The foreign error slot has type SomePointer<SomeErrorProtocol?>, // or possibly an optional thereof. // If the pointer itself is optional, we need to branch based on // whether it's really there. // FIXME: this code is written expecting pointer types to actually // be optional, as opposed to simply having a null inhabitant. OptionalTypeKind errorPtrOptKind; if (SILType errorPtrObjectTy = foreignErrorSlot->getType() .getAnyOptionalObjectType(gen.SGM.M, errorPtrOptKind)) { SILBasicBlock *contBB = gen.createBasicBlock(); SILBasicBlock *noSlotBB = gen.createBasicBlock(); SILBasicBlock *hasSlotBB = gen.createBasicBlock(); gen.B.createSwitchEnum(loc, foreignErrorSlot, nullptr, { { ctx.getOptionalSomeDecl(errorPtrOptKind), hasSlotBB }, { ctx.getOptionalNoneDecl(errorPtrOptKind), noSlotBB } }); // If we have the slot, emit a store to it. gen.B.emitBlock(hasSlotBB); SILValue slot = hasSlotBB->createBBArg(errorPtrObjectTy); emitStoreToForeignErrorSlot(gen, loc, slot, errorSrc); gen.B.createBranch(loc, contBB); // Otherwise, just release the error. gen.B.emitBlock(noSlotBB); errorSrc.emitRelease(gen, loc); gen.B.createBranch(loc, contBB); // Continue. gen.B.emitBlock(contBB); return; } // Okay, break down the components of SomePointer<SomeErrorProtocol?>. // TODO: this should really be an unlowered AST type? CanType bridgedErrorPtrType = foreignErrorSlot->getType().getSwiftRValueType(); PointerTypeKind ptrKind; CanType bridgedErrorProtocol = CanType(bridgedErrorPtrType->getAnyPointerElementType(ptrKind)); FullExpr scope(gen.Cleanups, CleanupLocation::get(loc)); WritebackScope writebacks(gen); // Convert the error to a bridged form. SILValue bridgedError = errorSrc.emitBridged(gen, loc, bridgedErrorProtocol); // Store to the "pointee" property. // If we can't find it, diagnose and then just don't store anything. VarDecl *pointeeProperty = ctx.getPointerPointeePropertyDecl(ptrKind); if (!pointeeProperty) { gen.SGM.diagnose(loc, diag::could_not_find_pointer_pointee_property, bridgedErrorPtrType); return; } // Otherwise, do a normal assignment. LValue lvalue = gen.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot), bridgedErrorPtrType, pointeeProperty, AccessKind::Write, AccessSemantics::Ordinary); RValue rvalue(gen, loc, bridgedErrorProtocol, gen.emitManagedRValueWithCleanup(bridgedError)); gen.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue)); }
/// Emit a store of a native error to the foreign-error slot. static void emitStoreToForeignErrorSlot(SILGenFunction &SGF, SILLocation loc, SILValue foreignErrorSlot, const BridgedErrorSource &errorSrc) { ASTContext &ctx = SGF.getASTContext(); // The foreign error slot has type SomePointer<SomeError?>, // or possibly an optional thereof. // If the pointer itself is optional, we need to branch based on // whether it's really there. if (SILType errorPtrObjectTy = foreignErrorSlot->getType().getOptionalObjectType()) { SILBasicBlock *contBB = SGF.createBasicBlock(); SILBasicBlock *noSlotBB = SGF.createBasicBlock(); SILBasicBlock *hasSlotBB = SGF.createBasicBlock(); SGF.B.createSwitchEnum(loc, foreignErrorSlot, nullptr, { { ctx.getOptionalSomeDecl(), hasSlotBB }, { ctx.getOptionalNoneDecl(), noSlotBB } }); // If we have the slot, emit a store to it. SGF.B.emitBlock(hasSlotBB); SILValue slot = hasSlotBB->createPHIArgument(errorPtrObjectTy, ValueOwnershipKind::Owned); emitStoreToForeignErrorSlot(SGF, loc, slot, errorSrc); SGF.B.createBranch(loc, contBB); // Otherwise, just release the error. SGF.B.emitBlock(noSlotBB); errorSrc.emitRelease(SGF, loc); SGF.B.createBranch(loc, contBB); // Continue. SGF.B.emitBlock(contBB); return; } // Okay, break down the components of SomePointer<SomeError?>. // TODO: this should really be an unlowered AST type? auto bridgedErrorPtrType = foreignErrorSlot->getType().getASTType(); PointerTypeKind ptrKind; CanType bridgedErrorProto = CanType(bridgedErrorPtrType->getAnyPointerElementType(ptrKind)); FullExpr scope(SGF.Cleanups, CleanupLocation::get(loc)); FormalEvaluationScope writebacks(SGF); // Convert the error to a bridged form. SILValue bridgedError = errorSrc.emitBridged(SGF, loc, bridgedErrorProto); // Store to the "pointee" property. // If we can't find it, diagnose and then just don't store anything. VarDecl *pointeeProperty = ctx.getPointerPointeePropertyDecl(ptrKind); if (!pointeeProperty) { SGF.SGM.diagnose(loc, diag::could_not_find_pointer_pointee_property, bridgedErrorPtrType); return; } // Otherwise, do a normal assignment. LValue lvalue = SGF.emitPropertyLValue(loc, ManagedValue::forUnmanaged(foreignErrorSlot), bridgedErrorPtrType, pointeeProperty, LValueOptions(), AccessKind::Write, AccessSemantics::Ordinary); RValue rvalue(SGF, loc, bridgedErrorProto, SGF.emitManagedRValueWithCleanup(bridgedError)); SGF.emitAssignToLValue(loc, std::move(rvalue), std::move(lvalue)); }