SILValue Lowering::emitIsa(SILGenFunction &SGF, SILLocation loc, Expr *operand, Type targetType, CheckedCastKind castKind) { // Handle collection downcasts separately. if (castKind == CheckedCastKind::ArrayDowncast || castKind == CheckedCastKind::DictionaryDowncast || castKind == CheckedCastKind::SetDowncast) { ManagedValue operandMV = SGF.emitRValueAsSingleValue(operand); ManagedValue optValue = emitCollectionDowncastExpr( SGF, operandMV, operand->getType(), loc, targetType, SGFContext(), /*conditional=*/true) .getAsSingleValue(SGF, loc); // Materialize the input. SILValue optValueTemp; if (optValue.getType().isAddress()) { optValueTemp = optValue.forward(SGF); } else { optValueTemp = SGF.emitTemporaryAllocation(loc, optValue.getType()); optValue.forwardInto(SGF, loc, optValueTemp); } return SGF.emitDoesOptionalHaveValue(loc, optValueTemp); } // Prepare a jump destination here. ExitableFullExpr scope(SGF, CleanupLocation::get(loc)); auto i1Ty = SILType::getBuiltinIntegerType(1, SGF.getASTContext()); SGF.emitCheckedCastBranch(loc, operand, targetType, SGFContext(), [&](ManagedValue value) { SILValue yes = SGF.B.createIntegerLiteral(loc, i1Ty, 1); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, yes); }, [&] { SILValue no = SGF.B.createIntegerLiteral(loc, i1Ty, 0); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, no); }); auto contBB = scope.exit(); auto isa = new (SGF.SGM.M) SILArgument(contBB, i1Ty); return isa; }
RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF, SILLocation loc, ManagedValue operand, Type operandType, Type optTargetType, CheckedCastKind castKind, SGFContext C) { // Drill into the result type. CanType resultObjectType = optTargetType->getCanonicalType().getAnyOptionalObjectType(); assert(resultObjectType); // Handle collection downcasts directly; they have specific library // entry points. if (castKind == CheckedCastKind::ArrayDowncast || castKind == CheckedCastKind::DictionaryDowncast || castKind == CheckedCastKind::SetDowncast) { return emitCollectionDowncastExpr(SGF, operand, operandType, loc, resultObjectType, C, /*conditional=*/true); } operand = adjustForConditionalCheckedCastOperand(loc, operand, operandType->getCanonicalType(), resultObjectType, SGF); auto someDecl = SGF.getASTContext().getOptionalSomeDecl(); auto &resultTL = SGF.getTypeLowering(optTargetType); // Set up a result buffer if desirable/required. SILValue resultBuffer; SILValue resultObjectBuffer; Optional<TemporaryInitialization> resultObjectTemp; SGFContext resultObjectCtx; if (resultTL.isAddressOnly() || (C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) { SILType resultTy = resultTL.getLoweredType(); resultBuffer = SGF.getBufferForExprResult(loc, resultTy, C); resultObjectBuffer = SGF.B.createInitEnumDataAddr(loc, resultBuffer, someDecl, resultTy.getAnyOptionalObjectType().getAddressType()); resultObjectTemp.emplace(resultObjectBuffer, CleanupHandle::invalid()); resultObjectCtx = SGFContext(&resultObjectTemp.getValue()); } // Prepare a jump destination here. ExitableFullExpr scope(SGF, CleanupLocation::get(loc)); auto operandCMV = ConsumableManagedValue::forOwned(operand); SGF.emitCheckedCastBranch(loc, operandCMV, operandType, resultObjectType, resultObjectCtx, // The success path. [&](ManagedValue objectValue) { // If we're not emitting into a temporary, just wrap up the result // in Some and go to the continuation block. if (!resultObjectTemp) { auto some = SGF.B.createEnum(loc, objectValue.forward(SGF), someDecl, resultTL.getLoweredType()); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { some }); return; } // Otherwise, make sure the value is in the context. if (!objectValue.isInContext()) { objectValue.forwardInto(SGF, loc, resultObjectBuffer); } SGF.B.createInjectEnumAddr(loc, resultBuffer, someDecl); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc); }, // The failure path. [&] { auto noneDecl = SGF.getASTContext().getOptionalNoneDecl(); // If we're not emitting into a temporary, just wrap up the result // in None and go to the continuation block. if (!resultObjectTemp) { auto none = SGF.B.createEnum(loc, nullptr, noneDecl, resultTL.getLoweredType()); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc, { none }); // Just construct the enum directly in the context. } else { SGF.B.createInjectEnumAddr(loc, resultBuffer, noneDecl); SGF.Cleanups.emitBranchAndCleanups(scope.getExitDest(), loc); } }); // Enter the continuation block. auto contBB = scope.exit(); ManagedValue result; if (resultObjectTemp) { result = SGF.manageBufferForExprResult(resultBuffer, resultTL, C); } else { auto argument = new (SGF.F.getModule()) SILArgument(contBB, resultTL.getLoweredType()); result = SGF.emitManagedRValueWithCleanup(argument, resultTL); } return RValue(SGF, loc, optTargetType->getCanonicalType(), result); }