void ArgumentSource::forwardInto(SILGenFunction &SGF, AbstractionPattern origFormalType, Initialization *dest, const TypeLowering &destTL) && { auto substFormalType = getSubstType(); assert(destTL.getLoweredType() == SGF.getLoweredType(origFormalType, substFormalType)); // If there are no abstraction changes, we can just forward // normally. if (origFormalType.isExactType(substFormalType) || destTL.getLoweredType() == SGF.getLoweredType(substFormalType)) { std::move(*this).forwardInto(SGF, dest); return; } // Otherwise, emit as a single independent value. SILLocation loc = getLocation(); ManagedValue inputValue = std::move(*this).getAsSingleValue(SGF); // Reabstract. ManagedValue outputValue = SGF.emitSubstToOrigValue(loc, inputValue, origFormalType, substFormalType, SGFContext(dest)); if (outputValue.isInContext()) return; // Use RValue's forward-into-initialization code. We have to lie to // RValue about the formal type (by using the lowered type) because // we're emitting into an abstracted value, which RValue doesn't // really handle. auto substLoweredType = destTL.getLoweredType().getSwiftRValueType(); RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, dest, loc); }
ManagedValue ArgumentSource::getAsSingleValue(SILGenFunction &gen, AbstractionPattern origFormalType, SGFContext C) && { auto loc = getLocation(); auto substFormalType = getSubstType(); ManagedValue outputValue = std::move(*this).getAsSingleValue(gen); return gen.emitSubstToOrigValue(loc, outputValue, origFormalType, substFormalType, C); }
static ManagedValue adjustForConditionalCheckedCastOperand(SILLocation loc, ManagedValue src, CanType sourceType, CanType targetType, SILGenFunction &SGF) { // Reabstract to the most general abstraction, and put it into a // temporary if necessary. // Figure out if we need the value to be in a temporary. bool requiresAddress = !canUseScalarCheckedCastInstructions(SGF.SGM.M, sourceType, targetType); AbstractionPattern abstraction = SGF.SGM.M.Types.getMostGeneralAbstraction(); auto &srcAbstractTL = SGF.getTypeLowering(abstraction, sourceType); bool hasAbstraction = (src.getType() != srcAbstractTL.getLoweredType()); // Fast path: no re-abstraction required. if (!hasAbstraction && (!requiresAddress || src.getType().isAddress())) { return src; } std::unique_ptr<TemporaryInitialization> init; SGFContext ctx; if (requiresAddress) { init = SGF.emitTemporary(loc, srcAbstractTL); // Okay, if all we need to do is drop the value in an address, // this is easy. if (!hasAbstraction) { SGF.B.createStore(loc, src.forward(SGF), init->getAddress()); init->finishInitialization(SGF); return init->getManagedAddress(); } ctx = SGFContext(init.get()); } assert(hasAbstraction); assert(src.getType().isObject() && "address-only type with abstraction difference?"); // Produce the value at +1. return SGF.emitSubstToOrigValue(loc, src, abstraction, sourceType); }
RValue Lowering::emitConditionalCheckedCast(SILGenFunction &SGF, SILLocation loc, ManagedValue operand, Type operandType, Type optTargetType, CheckedCastKind castKind, SGFContext C) { // Drill into the result type. OptionalTypeKind optKind; CanType resultObjectType = optTargetType->getCanonicalType().getAnyOptionalObjectType(optKind); 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(optKind); auto &resultTL = SGF.getTypeLowering(optTargetType); // Optional<T> currently fully abstracts its object. auto abstraction = SGF.SGM.Types.getMostGeneralAbstraction(); auto &abstractResultObjectTL = SGF.getTypeLowering(abstraction, resultObjectType); auto &resultObjectTL = SGF.getTypeLowering(resultObjectType); bool hasAbstraction = (resultObjectTL.getLoweredType() != abstractResultObjectTL.getLoweredType()); // Set up a result buffer if desirable/required. SILValue resultBuffer; SILValue resultObjectBuffer; Optional<TemporaryInitialization> resultObjectTemp; SGFContext resultObjectCtx; if (resultTL.isAddressOnly() || (!hasAbstraction && C.getEmitInto() && C.getEmitInto()->getAddressOrNull())) { resultBuffer = SGF.getBufferForExprResult(loc, resultTL.getLoweredType(), C); resultObjectBuffer = SGF.B.createInitEnumDataAddr(loc, resultBuffer, someDecl, abstractResultObjectTL.getLoweredType().getAddressType()); resultObjectTemp.emplace(resultObjectBuffer, CleanupHandle::invalid()); if (!hasAbstraction) 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) { if (hasAbstraction) objectValue = SGF.emitSubstToOrigValue(loc, objectValue, abstraction, resultObjectType); 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() && hasAbstraction) { objectValue = SGF.emitSubstToOrigValue(loc, objectValue, abstraction, resultObjectType, SGFContext(&resultObjectTemp.getValue())); } 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(optKind); // 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); }