static void buildBlockToFuncThunkBody(SILGenFunction &gen, SILLocation loc, CanSILFunctionType blockTy, CanSILFunctionType funcTy) { // Collect the native arguments, which should all be +1. Scope scope(gen.Cleanups, CleanupLocation::get(loc)); assert(blockTy->getParameters().size() == funcTy->getParameters().size() && "block and function types don't match"); SmallVector<ManagedValue, 4> args; SILBasicBlock *entry = &*gen.F.begin(); for (unsigned i : indices(funcTy->getParameters())) { auto ¶m = funcTy->getParameters()[i]; auto &blockParam = blockTy->getParameters()[i]; auto &tl = gen.getTypeLowering(param.getSILType()); assert((tl.isTrivial() ? param.getConvention() == ParameterConvention::Direct_Unowned : param.getConvention() == ParameterConvention::Direct_Owned) && "nonstandard conventions for native functions not implemented"); SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType()); auto mv = gen.emitManagedRValueWithCleanup(v, tl); args.push_back(gen.emitNativeToBridgedValue(loc, mv, SILFunctionTypeRepresentation::Block, AbstractionPattern(param.getType()), param.getType(), blockParam.getType())); } // Add the block argument. SILValue blockV = new (gen.SGM.M) SILArgument(entry, SILType::getPrimitiveObjectType(blockTy)); ManagedValue block = gen.emitManagedRValueWithCleanup(blockV); // Call the block. assert(!funcTy->hasIndirectResult() && "block thunking func with indirect result not supported"); ManagedValue result = gen.emitMonomorphicApply(loc, block, args, funcTy->getSILResult().getSwiftRValueType(), ApplyOptions::None, /*override CC*/ SILFunctionTypeRepresentation::Block, /*foreign error*/ None); // Return the result at +1. auto &resultTL = gen.getTypeLowering(funcTy->getSILResult()); auto convention = funcTy->getResult().getConvention(); assert((resultTL.isTrivial() ? convention == ResultConvention::Unowned : convention == ResultConvention::Owned) && "nonstandard conventions for return not implemented"); (void)convention; (void)resultTL; auto r = result.forward(gen); scope.pop(); gen.B.createReturn(loc, r); }
static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, SILLocation loc, CanType interfaceType, DeclContext *DC) { auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType(); // Restructure tuple arguments. if (auto tupleTy = dyn_cast<TupleType>(interfaceType)) { RValue tuple(type); for (auto fieldType : tupleTy.getElementTypes()) tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC)); return tuple; } auto &AC = SGF.getASTContext(); auto VD = new (AC) ParamDecl(VarDecl::Specifier::Default, SourceLoc(), SourceLoc(), AC.getIdentifier("$implicit_value"), SourceLoc(), AC.getIdentifier("$implicit_value"), Type(), DC); VD->setInterfaceType(interfaceType); SILFunctionArgument *arg = SGF.F.begin()->createFunctionArgument(SGF.getLoweredType(type), VD); ManagedValue mvArg; if (arg->getArgumentConvention().isOwnedConvention()) { mvArg = SGF.emitManagedRValueWithCleanup(arg); } else { mvArg = ManagedValue::forUnmanaged(arg); } return RValue(SGF, loc, type, mvArg); }
static RValue emitImplicitValueConstructorArg(SILGenFunction &gen, SILLocation loc, CanType interfaceType, DeclContext *DC) { auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType(); // Restructure tuple arguments. if (CanTupleType tupleTy = dyn_cast<TupleType>(interfaceType)) { RValue tuple(type); for (auto fieldType : tupleTy.getElementTypes()) tuple.addElement(emitImplicitValueConstructorArg(gen, loc, fieldType, DC)); return tuple; } else { auto &AC = gen.getASTContext(); auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), AC.getIdentifier("$implicit_value"), SourceLoc(), AC.getIdentifier("$implicit_value"), Type(), DC); VD->setInterfaceType(interfaceType); SILValue arg = gen.F.begin()->createFunctionArgument(gen.getLoweredType(type), VD); return RValue(gen, loc, type, gen.emitManagedRValueWithCleanup(arg)); } }
static ManagedValue emitBridgeCollectionFromNative(SILGenFunction &gen, SILLocation loc, SILDeclRef bridgeFnRef, ManagedValue collection, SILType bridgedTy) { SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef); // If the expected return is optional, we'll need to wrap it. OptionalTypeKind OTK = OTK_None; SILType origBridgedTy = bridgedTy; if (auto bridgedObjTy = bridgedTy.getAnyOptionalObjectType(gen.SGM.M, OTK)) { bridgedTy = bridgedObjTy; } // Figure out the type parameters. auto inputTy = collection.getType().getSwiftRValueType()->castTo<BoundGenericType>(); auto subs = inputTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); SILValue bridged = gen.B.createApply(loc, bridgeFn, substFnType, bridgedTy, subs, { collection.forward(gen) }); // Wrap the result if necessary. if (OTK != OTK_None) { bridged = gen.B.createEnum(loc, bridged, gen.getASTContext().getOptionalSomeDecl(OTK), origBridgedTy); } return gen.emitManagedRValueWithCleanup(bridged); }
static ManagedValue emitBridgeCollectionToNative(SILGenFunction &gen, SILLocation loc, SILDeclRef bridgeFnRef, ManagedValue collection, SILType nativeTy) { SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, bridgeFnRef); auto collectionTy = nativeTy.getSwiftRValueType()->castTo<BoundGenericType>(); auto subs = collectionTy->getSubstitutions(gen.SGM.M.getSwiftModule(), nullptr); auto substFnType = bridgeFn.getType().substGenericArgs(gen.SGM.M, subs); Type inputType = collection.getType().getSwiftRValueType(); if (!inputType->getOptionalObjectType()) { SILType loweredOptTy = gen.SGM.getLoweredType(OptionalType::get(inputType)); auto *someDecl = gen.getASTContext().getOptionalSomeDecl(); auto *enumInst = gen.B.createEnum(loc, collection.getValue(), someDecl, loweredOptTy); collection = ManagedValue(enumInst, collection.getCleanup()); } SILValue result = gen.B.createApply(loc, bridgeFn, substFnType, nativeTy, subs, { collection.forward(gen) }); return gen.emitManagedRValueWithCleanup(result); }
/// Specialized emitter for Builtin.castReferenceFromBridgeObject. static ManagedValue emitBuiltinCastReferenceFromBridgeObject( SILGenFunction &gen, SILLocation loc, SubstitutionList subs, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1 && "cast should have one argument"); assert(subs.size() == 1 && "cast should have a type substitution"); // The substitution determines the destination type. SILType destType = gen.getLoweredType(subs[0].getReplacement()); // Bail if the source type is not a class reference of some kind. if (!subs[0].getReplacement()->isBridgeableObjectType() || !destType.isObject()) { gen.SGM.diagnose(loc, diag::invalid_sil_builtin, "castReferenceFromBridgeObject dest must be an object type"); // Recover by propagating an undef result. SILValue result = SILUndef::get(destType, gen.SGM.M); return ManagedValue::forUnmanaged(result); } SILValue result = gen.B.createBridgeObjectToRef(loc, args[0].forward(gen), destType); return gen.emitManagedRValueWithCleanup(result); }
/// Specialized emitter for Builtin.castReference. static ManagedValue emitBuiltinCastReference(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1 && "castReference should be given one argument"); assert(substitutions.size() == 2 && "castReference should have two subs"); auto fromTy = substitutions[0].getReplacement(); auto toTy = substitutions[1].getReplacement(); auto &fromTL = gen.getTypeLowering(fromTy); auto &toTL = gen.getTypeLowering(toTy); assert(!fromTL.isTrivial() && !toTL.isTrivial() && "expected ref type"); if (fromTL.isLoadable() || toTL.isLoadable()) { if (auto refCast = gen.B.tryCreateUncheckedRefCast(loc, args[0].getValue(), toTL.getLoweredType())) { // Create a reference cast, forwarding the cleanup. // The cast takes the source reference. return ManagedValue(refCast, args[0].getCleanup()); } } // We are either casting between address-only types, or cannot promote to a // cast of reference values. // // If the from/to types are invalid, then use a cast that will fail at // runtime. We cannot catch these errors with SIL verification because they // may legitimately occur during code specialization on dynamically // unreachable paths. // // TODO: For now, we leave invalid casts in address form so that the runtime // will trap. We could emit a noreturn call here instead which would provide // more information to the optimizer. SILValue srcVal = args[0].forward(gen); SILValue fromAddr; if (fromTL.isLoadable()) { // Move the loadable value into a "source temp". Since the source and // dest are RC identical, store the reference into the source temp without // a retain. The cast will load the reference from the source temp and // store it into a dest temp effectively forwarding the cleanup. fromAddr = gen.emitTemporaryAllocation(loc, srcVal->getType()); gen.B.createStore(loc, srcVal, fromAddr); } else { // The cast loads directly from the source address. fromAddr = srcVal; } // Create a "dest temp" to hold the reference after casting it. SILValue toAddr = gen.emitTemporaryAllocation(loc, toTL.getLoweredType()); gen.B.createUncheckedRefCastAddr(loc, fromAddr, fromTy->getCanonicalType(), toAddr, toTy->getCanonicalType()); // Forward it along and register a cleanup. if (toTL.isAddressOnly()) return gen.emitManagedBufferWithCleanup(toAddr); // Load the destination value. auto result = gen.B.createLoad(loc, toAddr); return gen.emitManagedRValueWithCleanup(result); }
/// Emit a copy of this value with independent ownership. ManagedValue ManagedValue::copy(SILGenFunction &gen, SILLocation l) { if (!cleanup.isValid()) { assert(gen.getTypeLowering(getType()).isTrivial()); return *this; } auto &lowering = gen.getTypeLowering(getType()); assert(!lowering.isTrivial() && "trivial value has cleanup?"); if (!lowering.isAddressOnly()) { lowering.emitRetainValue(gen.B, l, getValue()); return gen.emitManagedRValueWithCleanup(getValue(), lowering); } SILValue buf = gen.emitTemporaryAllocation(l, getType()); gen.B.createCopyAddr(l, getValue(), buf, IsNotTake, IsInitialization); return gen.emitManagedRValueWithCleanup(buf, lowering); }
/// This is the same operation as 'copy', but works on +0 values that don't /// have cleanups. It returns a +1 value with one. ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) { if (getType().isObject()) { return SGF.B.createCopyValue(loc, *this); } SILValue result = SGF.emitTemporaryAllocation(loc, getType()); SGF.B.createCopyAddr(loc, getValue(), result, IsNotTake, IsInitialization); return SGF.emitManagedRValueWithCleanup(result); }
static void boxIndirectEnumPayload(SILGenFunction &gen, ManagedValue &payload, SILLocation loc, EnumElementDecl *element) { // If the payload is indirect, we'll need to box it. if (payload && (element->isIndirect() || element->getParentEnum()->isIndirect())) { auto box = gen.B.createAllocBox(loc, payload.getType()); payload.forwardInto(gen, loc, box->getAddressResult()); payload = gen.emitManagedRValueWithCleanup(box); } }
static SILValue emitBridgeReturnValue(SILGenFunction &gen, SILLocation loc, SILValue result, SILFunctionTypeRepresentation fnTypeRepr, CanType bridgedTy) { Scope scope(gen.Cleanups, CleanupLocation::get(loc)); ManagedValue native = gen.emitManagedRValueWithCleanup(result); ManagedValue bridged = gen.emitNativeToBridgedValue(loc, native, fnTypeRepr, bridgedTy); return bridged.forward(gen); }
/// Emit a copy of this value with independent ownership. ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) { auto &lowering = SGF.getTypeLowering(getType()); if (lowering.isTrivial()) return *this; if (getType().isObject()) { return SGF.B.createCopyValue(loc, *this, lowering); } SILValue buf = SGF.emitTemporaryAllocation(loc, getType()); SGF.B.createCopyAddr(loc, getValue(), buf, IsNotTake, IsInitialization); return SGF.emitManagedRValueWithCleanup(buf, lowering); }
static ManagedValue emitBridgeStringToNSString(SILGenFunction &gen, SILLocation loc, ManagedValue str) { // func _convertStringToNSString(String) -> NSString SILValue stringToNSStringFn = gen.emitGlobalFunctionRef(loc, gen.SGM.getStringToNSStringFn()); SILValue nsstr = gen.B.createApply(loc, stringToNSStringFn, stringToNSStringFn.getType(), gen.getLoweredType(gen.SGM.Types.getNSStringType()), {}, str.forward(gen)); return gen.emitManagedRValueWithCleanup(nsstr); }
static ManagedValue emitBridgeForeignBoolToBool(SILGenFunction &gen, SILLocation loc, ManagedValue foreignBool, SILDeclRef bridgingFnRef) { // func _convertObjCBoolToBool(ObjCBool) -> Bool SILValue bridgingFn = gen.emitGlobalFunctionRef(loc, bridgingFnRef); SILType resultTy = gen.getLoweredLoadableType(gen.SGM.Types.getBoolType()); SILValue result = gen.B.createApply(loc, bridgingFn, bridgingFn->getType(), resultTy, {}, foreignBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); }
static ManagedValue emitBridgeBoolToObjCBool(SILGenFunction &gen, SILLocation loc, ManagedValue swiftBool) { // func _convertBoolToObjCBool(Bool) -> ObjCBool SILValue boolToObjCBoolFn = gen.emitGlobalFunctionRef(loc, gen.SGM.getBoolToObjCBoolFn()); SILType resultTy =gen.getLoweredLoadableType(gen.SGM.Types.getObjCBoolType()); SILValue result = gen.B.createApply(loc, boolToObjCBoolFn, boolToObjCBoolFn->getType(), resultTy, {}, swiftBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); }
/// 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); }
/// Bridge the given Swift value to its corresponding Objective-C /// object, using the appropriate witness for the /// _ObjectiveCBridgeable._bridgeToObjectiveC requirement. static Optional<ManagedValue> emitBridgeNativeToObjectiveC(SILGenFunction &gen, SILLocation loc, ManagedValue swiftValue, ProtocolConformance *conformance) { // Dig out the nominal type we're bridging from. Type swiftValueType = swiftValue.getSwiftType()->getRValueType(); // Find the _bridgeToObjectiveC requirement. auto requirement = gen.SGM.getBridgeToObjectiveCRequirement(loc); if (!requirement) return None; // Retrieve the _bridgeToObjectiveC witness. auto witness = conformance->getWitness(requirement, nullptr); assert(witness); // Determine the type we're bridging to. auto objcTypeReq = gen.SGM.getBridgedObjectiveCTypeRequirement(loc); if (!objcTypeReq) return None; Type objcType = conformance->getTypeWitness(objcTypeReq, nullptr).getReplacement(); assert(objcType); // Create a reference to the witness. SILDeclRef witnessConstant(witness.getDecl()); auto witnessRef = gen.emitGlobalFunctionRef(loc, witnessConstant); // Determine the substitutions. ArrayRef<Substitution> substitutions; auto witnessFnTy = witnessRef->getType(); if (auto valueTypeBGT = swiftValueType->getAs<BoundGenericType>()) { // Compute the substitutions. substitutions = valueTypeBGT->getSubstitutions(gen.SGM.SwiftModule, nullptr); // Substitute into the witness function tye. witnessFnTy = witnessFnTy.substGenericArgs(gen.SGM.M, substitutions); } // Call the witness. SILType resultTy = gen.getLoweredType(objcType); SILValue bridgedValue = gen.B.createApply(loc, witnessRef, witnessFnTy, resultTy, substitutions, swiftValue.borrow() .getUnmanagedValue()); return gen.emitManagedRValueWithCleanup(bridgedValue); }
ManagedValue RValue::getAsSingleValue(SILGenFunction &gen, SILLocation l) && { // Avoid killing and re-emitting the cleanup if the enclosed value isn't a // tuple. if (!isa<TupleType>(type)) { assert(values.size() == 1 && "exploded non-tuple?!"); ManagedValue result = values[0]; makeUsed(); return result; } // Forward into a single value, then install a cleanup on the resulting // imploded value. return gen.emitManagedRValueWithCleanup( std::move(*this).forwardAsSingleValue(gen, l)); }
/// This is the same operation as 'copy', but works on +0 values that don't /// have cleanups. It returns a +1 value with one. ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &gen, SILLocation loc) { auto &lowering = gen.getTypeLowering(getType()); if (lowering.isTrivial()) return *this; SILValue result; if (!lowering.isAddressOnly()) { lowering.emitRetainValue(gen.B, loc, getValue()); result = getValue(); } else { result = gen.emitTemporaryAllocation(loc, getType()); gen.B.createCopyAddr(loc, getValue(), result, IsNotTake,IsInitialization); } return gen.emitManagedRValueWithCleanup(result, lowering); }
static ManagedValue emitBuiltinTryPin(SILGenFunction &SGF, SILLocation loc, SubstitutionList subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1); if (!requireIsOptionalNativeObject(SGF, loc, subs[0].getReplacement())) { return SGF.emitUndef(loc, subs[0].getReplacement()); } // The value was produced at +1, but pinning is only a conditional // retain, so we have to leave the cleanup in place. TODO: try to // emit the argument at +0. SILValue result = SGF.B.createStrongPin(loc, args[0].getValue(), SGF.B.getDefaultAtomicity()); // The handle, if non-null, is effectively +1. return SGF.emitManagedRValueWithCleanup(result); }
static ManagedValue emitBridgeNSStringToString(SILGenFunction &gen, SILLocation loc, ManagedValue nsstr) { SILValue bridgeFn = gen.emitGlobalFunctionRef(loc, gen.SGM.getNSStringToStringFn()); Type inputType = nsstr.getType().getSwiftRValueType(); if (!inputType->getOptionalObjectType()) { SILType loweredOptTy = gen.SGM.getLoweredType(OptionalType::get(inputType)); auto *someDecl = gen.getASTContext().getOptionalSomeDecl(); auto *enumInst = gen.B.createEnum(loc, nsstr.getValue(), someDecl, loweredOptTy); nsstr = ManagedValue(enumInst, nsstr.getCleanup()); } SILType nativeTy = gen.getLoweredType(gen.SGM.Types.getStringType()); SILValue str = gen.B.createApply(loc, bridgeFn, bridgeFn.getType(), nativeTy, {}, { nsstr.forward(gen) }); return gen.emitManagedRValueWithCleanup(str); }
static RValue emitImplicitValueConstructorArg(SILGenFunction &gen, SILLocation loc, CanType ty, DeclContext *DC) { // Restructure tuple arguments. if (CanTupleType tupleTy = dyn_cast<TupleType>(ty)) { RValue tuple(ty); for (auto fieldType : tupleTy.getElementTypes()) tuple.addElement(emitImplicitValueConstructorArg(gen, loc, fieldType, DC)); return tuple; } else { auto &AC = gen.getASTContext(); auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), AC.getIdentifier("$implicit_value"), SourceLoc(), AC.getIdentifier("$implicit_value"), ty, DC); SILValue arg = new (gen.F.getModule()) SILArgument(gen.F.begin(), gen.getLoweredType(ty), VD); return RValue(gen, loc, ty, gen.emitManagedRValueWithCleanup(arg)); } }
static void buildFuncToBlockInvokeBody(SILGenFunction &gen, SILLocation loc, CanSILFunctionType blockTy, CanSILBlockStorageType blockStorageTy, CanSILFunctionType funcTy) { Scope scope(gen.Cleanups, CleanupLocation::get(loc)); SILBasicBlock *entry = &*gen.F.begin(); // Get the captured native function value out of the block. auto storageAddrTy = SILType::getPrimitiveAddressType(blockStorageTy); auto storage = new (gen.SGM.M) SILArgument(entry, storageAddrTy); auto capture = gen.B.createProjectBlockStorage(loc, storage); auto &funcTL = gen.getTypeLowering(funcTy); auto fn = gen.emitLoad(loc, capture, funcTL, SGFContext(), IsNotTake); // Collect the block arguments, which may have nonstandard conventions. assert(blockTy->getParameters().size() == funcTy->getParameters().size() && "block and function types don't match"); SmallVector<ManagedValue, 4> args; for (unsigned i : indices(funcTy->getParameters())) { auto &funcParam = funcTy->getParameters()[i]; auto ¶m = blockTy->getParameters()[i]; SILValue v = new (gen.SGM.M) SILArgument(entry, param.getSILType()); ManagedValue mv; // If the parameter is a block, we need to copy it to ensure it lives on // the heap. The adapted closure value might outlive the block's original // scope. if (param.getSILType().isBlockPointerCompatible()) { // We still need to consume the original block if it was owned. switch (param.getConvention()) { case ParameterConvention::Direct_Owned: gen.emitManagedRValueWithCleanup(v); break; case ParameterConvention::Direct_Deallocating: case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: break; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: llvm_unreachable("indirect params to blocks not supported"); } SILValue blockCopy = gen.B.createCopyBlock(loc, v); mv = gen.emitManagedRValueWithCleanup(blockCopy); } else { switch (param.getConvention()) { case ParameterConvention::Direct_Owned: // Consume owned parameters at +1. mv = gen.emitManagedRValueWithCleanup(v); break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: // We need to independently retain the value. mv = gen.emitManagedRetain(loc, v); break; case ParameterConvention::Direct_Deallocating: // We do not need to retain the value since the value is already being // deallocated. mv = ManagedValue::forUnmanaged(v); break; case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: llvm_unreachable("indirect arguments to blocks not supported"); } } args.push_back(gen.emitBridgedToNativeValue(loc, mv, SILFunctionTypeRepresentation::CFunctionPointer, funcParam.getType())); } // Call the native function. assert(!funcTy->hasIndirectResults() && "block thunking func with indirect result not supported"); assert(funcTy->getNumDirectResults() <= 1 && "block thunking func with multiple results not supported"); ManagedValue result = gen.emitMonomorphicApply(loc, fn, args, funcTy->getSILResult().getSwiftRValueType(), ApplyOptions::None, None, None) .getAsSingleValue(gen, loc); // Bridge the result back to ObjC. result = gen.emitNativeToBridgedValue(loc, result, SILFunctionTypeRepresentation::CFunctionPointer, blockTy->getSILResult().getSwiftRValueType()); auto resultVal = result.forward(gen); scope.pop(); gen.B.createReturn(loc, resultVal); }
/// 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)); }
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); }
/// 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)); }