/// Perform a foreign error check by testing whether the call result is zero. /// The call result is otherwise ignored. static void emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue result, ManagedValue errorSlot, bool suppressErrorCheck, bool zeroIsError) { // Just ignore the call result if we're suppressing the error check. if (suppressErrorCheck) { return; } SILValue resultValue = emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue()); SILValue zero = gen.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = gen.getASTContext(); SILValue resultIsError = gen.B.createBuiltinBinaryFunction(loc, zeroIsError ? "cmp_eq" : "cmp_ne", resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createCondBranch(loc, resultIsError, errorBB, contBB); gen.emitForeignErrorBlock(loc, errorBB, errorSlot); gen.B.emitBlock(contBB); }
/// Perform a foreign error check by testing whether the error was nil. static void emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue errorSlot, bool suppressErrorCheck) { // If we're suppressing the check, just don't check. if (suppressErrorCheck) return; SILValue optionalError = gen.B.createLoad(loc, errorSlot.getValue()); OptionalTypeKind optKind; optionalError->getType().getAnyOptionalObjectType(gen.SGM.M, optKind); ASTContext &ctx = gen.getASTContext(); // Switch on the optional error. SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createSwitchEnum(loc, optionalError, /*default*/ nullptr, { { ctx.getOptionalSomeDecl(optKind), errorBB }, { ctx.getOptionalNoneDecl(optKind), contBB } }); // Emit the error block. Just be lazy and reload the error there. gen.emitForeignErrorBlock(loc, errorBB, errorSlot); // Return the result. gen.B.emitBlock(contBB); return; }
/// Perform a foreign error check by testing whether the error was nil. static void emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue errorSlot, bool suppressErrorCheck) { // If we're suppressing the check, just don't check. if (suppressErrorCheck) return; SILValue optionalError = gen.B.emitLoadValueOperation( loc, errorSlot.forward(gen), LoadOwnershipQualifier::Take); ASTContext &ctx = gen.getASTContext(); // Switch on the optional error. SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); errorBB->createArgument(optionalError->getType().unwrapAnyOptionalType()); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createSwitchEnum(loc, optionalError, /*default*/ nullptr, { { ctx.getOptionalSomeDecl(), errorBB }, { ctx.getOptionalNoneDecl(), contBB } }); // Emit the error block. Pass in none for the errorSlot since we have passed // in the errorSlot as our BB argument so we can pass ownership correctly. In // emitForeignErrorBlock, we will create the appropriate cleanup for the // argument. gen.emitForeignErrorBlock(loc, errorBB, None); // Return the result. gen.B.emitBlock(contBB); return; }
/// Perform a foreign error check by testing whether the call result is zero. /// The call result is otherwise ignored. static void emitResultIsZeroErrorCheck(SILGenFunction &SGF, SILLocation loc, ManagedValue result, ManagedValue errorSlot, bool suppressErrorCheck, bool zeroIsError) { // Just ignore the call result if we're suppressing the error check. if (suppressErrorCheck) { return; } SILValue resultValue = emitUnwrapIntegerResult(SGF, loc, result.getUnmanagedValue()); CanType resultType = resultValue->getType().getSwiftRValueType(); if (!resultType->isBuiltinIntegerType(1)) { SILValue zero = SGF.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = SGF.getASTContext(); resultValue = SGF.B.createBuiltinBinaryFunction(loc, "cmp_ne", resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); } SILBasicBlock *errorBB = SGF.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = SGF.createBasicBlock(); if (zeroIsError) SGF.B.createCondBranch(loc, resultValue, contBB, errorBB); else SGF.B.createCondBranch(loc, resultValue, errorBB, contBB); SGF.emitForeignErrorBlock(loc, errorBB, errorSlot); SGF.B.emitBlock(contBB); }
/// Perform a foreign error check by testing whether the call result is nil. static ManagedValue emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue origResult, ManagedValue errorSlot, bool suppressErrorCheck) { // Take local ownership of the optional result value. SILValue optionalResult = origResult.forward(gen); OptionalTypeKind optKind; SILType resultObjectType = optionalResult->getType().getAnyOptionalObjectType(gen.SGM.M, optKind); ASTContext &ctx = gen.getASTContext(); // If we're suppressing the check, just do an unchecked take. if (suppressErrorCheck) { SILValue objectResult = gen.B.createUncheckedEnumData(loc, optionalResult, ctx.getOptionalSomeDecl(optKind)); return gen.emitManagedRValueWithCleanup(objectResult); } // Switch on the optional result. SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createSwitchEnum(loc, optionalResult, /*default*/ nullptr, { { ctx.getOptionalSomeDecl(optKind), contBB }, { ctx.getOptionalNoneDecl(optKind), errorBB } }); // Emit the error block. gen.emitForeignErrorBlock(loc, errorBB, errorSlot); // In the continuation block, take ownership of the now non-optional // result value. gen.B.emitBlock(contBB); SILValue objectResult = contBB->createBBArg(resultObjectType); return gen.emitManagedRValueWithCleanup(objectResult); }
/// 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)); }