/// Return a value for an optional ".Some(x)" of the specified type. This only /// works for loadable enum types. ManagedValue SILGenFunction:: getOptionalSomeValue(SILLocation loc, ManagedValue value, const TypeLowering &optTL) { assert(optTL.isLoadable() && "Address-only optionals cannot use this"); SILType optType = optTL.getLoweredType(); CanType formalOptType = optType.getSwiftRValueType(); OptionalTypeKind OTK; auto formalObjectType = formalOptType->getAnyOptionalObjectType(OTK) ->getCanonicalType(); assert(OTK != OTK_None); auto someDecl = getASTContext().getOptionalSomeDecl(OTK); auto archetype = formalOptType->getNominalOrBoundGenericNominal() ->getGenericParams()->getPrimaryArchetypes()[0]; AbstractionPattern origType(archetype); // Reabstract input value to the type expected by the enum. value = emitSubstToOrigValue(loc, value, origType, formalObjectType); SILValue result = B.createEnum(loc, value.forward(*this), someDecl, optTL.getLoweredType()); return emitManagedRValueWithCleanup(result, optTL); }
void ArgumentSource::forwardInto(SILGenFunction &SGF, AbstractionPattern origFormalType, Initialization *dest, const TypeLowering &destTL) && { auto substFormalType = getSubstRValueType(); 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 outputValue = std::move(*this).getAsSingleValue(SGF, origFormalType, 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().getASTType(); RValue(SGF, loc, substLoweredType, outputValue).forwardInto(SGF, loc, dest); }
/// Return a value for an optional ".None" of the specified type. This only /// works for loadable enum types. SILValue SILGenFunction::getOptionalNoneValue(SILLocation loc, const TypeLowering &optTL) { assert(optTL.isLoadable() && "Address-only optionals cannot use this"); assert(optTL.getLoweredType().getAnyOptionalObjectType()); return B.createEnum(loc, SILValue(), getASTContext().getOptionalNoneDecl(), optTL.getLoweredType()); }
ManagedValue SILGenBuilder::createLoadTake(SILLocation loc, ManagedValue v, const TypeLowering &lowering) { assert(lowering.getLoweredType().getAddressType() == v.getType()); SILValue result = lowering.emitLoadOfCopy(*this, loc, v.forward(SGF), IsTake); if (lowering.isTrivial()) return ManagedValue::forUnmanaged(result); assert(!lowering.isAddressOnly() && "cannot retain an unloadable type"); return SGF.emitManagedRValueWithCleanup(result, lowering); }
/// Return a value for an optional ".Some(x)" of the specified type. This only /// works for loadable enum types. ManagedValue SILGenFunction:: getOptionalSomeValue(SILLocation loc, ManagedValue value, const TypeLowering &optTL) { assert(optTL.isLoadable() && "Address-only optionals cannot use this"); SILType optType = optTL.getLoweredType(); CanType formalOptType = optType.getSwiftRValueType(); auto formalObjectType = formalOptType.getAnyOptionalObjectType(); assert(formalObjectType); auto someDecl = getASTContext().getOptionalSomeDecl(); SILValue result = B.createEnum(loc, value.forward(*this), someDecl, optTL.getLoweredType()); return emitManagedRValueWithCleanup(result, optTL); }
void SILGenFunction::emitInjectOptionalValueInto(SILLocation loc, ArgumentSource &&value, SILValue dest, const TypeLowering &optTL) { SILType optType = optTL.getLoweredType(); OptionalTypeKind optionalKind; auto loweredPayloadTy = optType.getAnyOptionalObjectType(SGM.M, optionalKind); assert(optionalKind != OTK_None); // Project out the payload area. auto someDecl = getASTContext().getOptionalSomeDecl(optionalKind); auto destPayload = B.createInitEnumDataAddr(loc, dest, someDecl, loweredPayloadTy.getAddressType()); AbstractionPattern origType = AbstractionPattern::getOpaque(); // Emit the value into the payload area. TemporaryInitialization emitInto(destPayload, CleanupHandle::invalid()); auto &payloadTL = getTypeLowering(origType, value.getSubstType()); std::move(value).forwardInto(*this, origType, &emitInto, payloadTL); // Inject the tag. B.createInjectEnumAddr(loc, dest, someDecl); }
void SILGenFunction::emitInjectOptionalNothingInto(SILLocation loc, SILValue dest, const TypeLowering &optTL) { assert(optTL.getLoweredType().getAnyOptionalObjectType()); B.createInjectEnumAddr(loc, dest, getASTContext().getOptionalNoneDecl()); }
ManagedValue SILGenBuilder::formalAccessBufferForExpr( SILLocation loc, SILType ty, const TypeLowering &lowering, SGFContext context, llvm::function_ref<void(SILValue)> rvalueEmitter) { // If we have a single-buffer "emit into" initialization, use that for the // result. SILValue address = context.getAddressForInPlaceInitialization(SGF, loc); // If we couldn't emit into the Initialization, emit into a temporary // allocation. if (!address) { address = SGF.emitTemporaryAllocation(loc, ty.getObjectType()); } rvalueEmitter(address); // If we have a single-buffer "emit into" initialization, use that for the // result. if (context.finishInPlaceInitialization(SGF)) { return ManagedValue::forInContext(); } // Add a cleanup for the temporary we allocated. if (lowering.isTrivial()) return ManagedValue::forUnmanaged(address); return SGF.emitFormalAccessManagedBufferWithCleanup(loc, address); }
void SILGenFunction::emitInjectOptionalNothingInto(SILLocation loc, SILValue dest, const TypeLowering &optTL) { OptionalTypeKind OTK; optTL.getLoweredType().getSwiftRValueType()->getAnyOptionalObjectType(OTK); assert(OTK != OTK_None); B.createInjectEnumAddr(loc, dest, getASTContext().getOptionalNoneDecl(OTK)); }
ManagedValue SILGenBuilder::createCopyValue(SILLocation loc, ManagedValue originalValue, const TypeLowering &lowering) { if (lowering.isTrivial()) return originalValue; SILType ty = originalValue.getType(); assert(!ty.isAddress() && "Can not perform a copy value of an address typed " "value"); if (ty.isObject() && originalValue.getOwnershipKind() == ValueOwnershipKind::Any) { return originalValue; } SILValue result = lowering.emitCopyValue(*this, loc, originalValue.getValue()); return SGF.emitManagedRValueWithCleanup(result, lowering); }
// FIXME: With some changes to their callers, all of the below functions // could be re-worked to use emitInjectEnum(). ManagedValue SILGenFunction::emitInjectOptional(SILLocation loc, const TypeLowering &optTL, SGFContext ctxt, llvm::function_ref<ManagedValue(SGFContext)> generator) { SILType optTy = optTL.getLoweredType(); SILType objectTy = optTy.getAnyOptionalObjectType(); assert(objectTy && "expected type was not optional"); auto someDecl = getASTContext().getOptionalSomeDecl(); // If the value is loadable, just emit and wrap. // TODO: honor +0 contexts? if (optTL.isLoadable() || !silConv.useLoweredAddresses()) { ManagedValue objectResult = generator(SGFContext()); auto some = B.createEnum(loc, objectResult.forward(*this), someDecl, optTy); return emitManagedRValueWithCleanup(some, optTL); } // Otherwise it's address-only; try to avoid spurious copies by // evaluating into the context. // Prepare a buffer for the object value. return B.bufferForExpr( loc, optTy.getObjectType(), optTL, ctxt, [&](SILValue optBuf) { auto objectBuf = B.createInitEnumDataAddr(loc, optBuf, someDecl, objectTy); // Evaluate the value in-place into that buffer. TemporaryInitialization init(objectBuf, CleanupHandle::invalid()); ManagedValue objectResult = generator(SGFContext(&init)); if (!objectResult.isInContext()) { objectResult.forwardInto(*this, loc, objectBuf); } // Finalize the outer optional buffer. B.createInjectEnumAddr(loc, optBuf, someDecl); }); }
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc, ManagedValue addrOrValue, const TypeLowering &optTL, SGFContext C) { SILType origPayloadTy = addrOrValue.getType().getAnyOptionalObjectType(); auto someDecl = getASTContext().getOptionalSomeDecl(); ManagedValue payload; // Take the payload from the optional. Cheat a bit in the +0 // case--UncheckedTakeEnumData will never actually invalidate an Optional enum // value. SILValue payloadVal; if (!addrOrValue.getType().isAddress()) { payloadVal = B.createUncheckedEnumData(loc, addrOrValue.forward(*this), someDecl); } else { payloadVal = B.createUncheckedTakeEnumDataAddr(loc, addrOrValue.forward(*this), someDecl, origPayloadTy); if (optTL.isLoadable()) payloadVal = optTL.emitLoad(B, loc, payloadVal, LoadOwnershipQualifier::Take); } // Produce a correctly managed value. if (addrOrValue.hasCleanup()) payload = emitManagedRValueWithCleanup(payloadVal); else payload = ManagedValue::forUnmanaged(payloadVal); return payload; }
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc, ManagedValue addrOrValue, const TypeLowering &optTL, SGFContext C) { OptionalTypeKind OTK; SILType origPayloadTy = addrOrValue.getType().getAnyOptionalObjectType(SGM.M, OTK); auto formalOptionalTy = addrOrValue.getType().getSwiftRValueType(); auto formalPayloadTy = formalOptionalTy ->getAnyOptionalObjectType() ->getCanonicalType(); auto someDecl = getASTContext().getOptionalSomeDecl(OTK); ManagedValue payload; // Take the payload from the optional. Cheat a bit in the +0 // case—UncheckedTakeEnumData will never actually invalidate an Optional enum // value. SILValue payloadVal; if (!addrOrValue.getType().isAddress()) { payloadVal = B.createUncheckedEnumData(loc, addrOrValue.forward(*this), someDecl); } else { payloadVal = B.createUncheckedTakeEnumDataAddr(loc, addrOrValue.forward(*this), someDecl, origPayloadTy); if (optTL.isLoadable()) payloadVal = B.createLoad(loc, payloadVal); } // Produce a correctly managed value. if (addrOrValue.hasCleanup()) payload = emitManagedRValueWithCleanup(payloadVal); else payload = ManagedValue::forUnmanaged(payloadVal); // Reabstract it to the substituted form, if necessary. return emitOrigToSubstValue(loc, payload, AbstractionPattern::getOpaque(), formalPayloadTy, C); }
void SILGenFunction::emitInjectOptionalValueInto(SILLocation loc, ArgumentSource &&value, SILValue dest, const TypeLowering &optTL) { SILType optType = optTL.getLoweredType(); assert(dest->getType() == optType.getAddressType()); auto loweredPayloadTy = optType.getAnyOptionalObjectType(); assert(loweredPayloadTy); // Project out the payload area. auto someDecl = getASTContext().getOptionalSomeDecl(); auto destPayload = B.createInitEnumDataAddr(loc, dest, someDecl, loweredPayloadTy.getAddressType()); // Emit the value into the payload area. TemporaryInitialization emitInto(destPayload, CleanupHandle::invalid()); std::move(value).forwardInto(*this, &emitInto); // Inject the tag. B.createInjectEnumAddr(loc, dest, someDecl); }
ManagedValue SILGenFunction::emitExistentialErasure( SILLocation loc, CanType concreteFormalType, const TypeLowering &concreteTL, const TypeLowering &existentialTL, ArrayRef<ProtocolConformanceRef> conformances, SGFContext C, llvm::function_ref<ManagedValue (SGFContext)> F, bool allowEmbeddedNSError) { // Mark the needed conformances as used. for (auto conformance : conformances) SGM.useConformance(conformance); // If we're erasing to the 'Error' type, we might be able to get an NSError // representation more efficiently. auto &ctx = getASTContext(); auto nsError = ctx.getNSErrorDecl(); if (allowEmbeddedNSError && nsError && existentialTL.getSemanticType().getSwiftRValueType()->getAnyNominal() == ctx.getErrorDecl()) { // Check whether the concrete type conforms to the _BridgedStoredNSError // protocol. In that case, call the _nsError witness getter to extract the // NSError directly. auto conformance = SGM.getConformanceToBridgedStoredNSError(loc, concreteFormalType); CanType nsErrorType = nsError->getDeclaredInterfaceType()->getCanonicalType(); ProtocolConformanceRef nsErrorConformances[1] = { ProtocolConformanceRef(SGM.getNSErrorConformanceToError()) }; if (conformance && nsError && SGM.getNSErrorConformanceToError()) { if (auto witness = conformance->getWitness(SGM.getNSErrorRequirement(loc), nullptr)) { // Create a reference to the getter witness. SILDeclRef getter = getGetterDeclRef(cast<VarDecl>(witness.getDecl()), /*isDirectAccessorUse=*/true); // Compute the substitutions. ArrayRef<Substitution> substitutions = concreteFormalType->gatherAllSubstitutions( SGM.SwiftModule, nullptr); // Emit the erasure, through the getter to _nsError. return emitExistentialErasure( loc, nsErrorType, getTypeLowering(nsErrorType), existentialTL, ctx.AllocateCopy(nsErrorConformances), C, [&](SGFContext innerC) -> ManagedValue { // Call the getter. return emitGetAccessor(loc, getter, substitutions, ArgumentSource(loc, RValue(*this, loc, concreteFormalType, F(SGFContext()))), /*isSuper=*/false, /*isDirectAccessorUse=*/true, RValue(), innerC) .getAsSingleValue(*this, loc); }); } } // Check whether the concrete type is an archetype. If so, call the // _getEmbeddedNSError() witness to try to dig out the embedded NSError. if (auto archetypeType = concreteFormalType->getAs<ArchetypeType>()) { if (std::find(archetypeType->getConformsTo().begin(), archetypeType->getConformsTo().end(), ctx.getErrorDecl()) != archetypeType->getConformsTo().end()) { auto contBB = createBasicBlock(); auto isNotPresentBB = createBasicBlock(); auto isPresentBB = createBasicBlock(); SILValue existentialResult = contBB->createBBArg(existentialTL.getLoweredType()); ProtocolConformanceRef trivialErrorConformances[1] = { ProtocolConformanceRef(ctx.getErrorDecl()) }; Substitution substitutions[1] = { Substitution(concreteFormalType, ctx.AllocateCopy(trivialErrorConformances)) }; // Call swift_stdlib_getErrorEmbeddedNSError to attempt to extract an // NSError from the value. ManagedValue concreteValue = F(SGFContext()); ManagedValue potentialNSError = emitApplyOfLibraryIntrinsic(loc, SGM.getGetErrorEmbeddedNSError(loc), ctx.AllocateCopy(substitutions), { concreteValue }, SGFContext()) .getAsSingleValue(*this, loc); // Check whether we got an NSError back. SILValue hasNSError = emitDoesOptionalHaveValue(loc, potentialNSError.getValue()); B.createCondBranch(loc, hasNSError, isPresentBB, isNotPresentBB); // If we did get an NSError, emit the existential erasure from that // NSError. B.emitBlock(isPresentBB); SILValue branchArg; { // Don't allow cleanups to escape the conditional block. FullExpr presentScope(Cleanups, CleanupLocation::get(loc)); // Emit the existential erasure from the NSError. branchArg = emitExistentialErasure( loc, nsErrorType, getTypeLowering(nsErrorType), existentialTL, ctx.AllocateCopy(nsErrorConformances), C, [&](SGFContext innerC) -> ManagedValue { // Pull the NSError object out of the optional result. auto &inputTL = getTypeLowering(potentialNSError.getType()); auto nsErrorValue = emitUncheckedGetOptionalValueFrom(loc, potentialNSError, inputTL); // Perform an unchecked cast down to NSError, because it was typed // as 'AnyObject' for layering reasons. return ManagedValue(B.createUncheckedRefCast( loc, nsErrorValue.getValue(), getLoweredType(nsErrorType)), nsErrorValue.getCleanup()); }).forward(*this); } B.createBranch(loc, contBB, branchArg); // If we did not get an NSError, just directly emit the existential // (recursively). B.emitBlock(isNotPresentBB); branchArg = emitExistentialErasure(loc, concreteFormalType, concreteTL, existentialTL, conformances, SGFContext(), F, /*allowEmbeddedNSError=*/false) .forward(*this); B.createBranch(loc, contBB, branchArg); // Continue. B.emitBlock(contBB); return emitManagedRValueWithCleanup(existentialResult, existentialTL); } } } switch (existentialTL.getLoweredType().getObjectType() .getPreferredExistentialRepresentation(SGM.M, concreteFormalType)) { case ExistentialRepresentation::None: llvm_unreachable("not an existential type"); case ExistentialRepresentation::Metatype: { assert(existentialTL.isLoadable()); SILValue metatype = F(SGFContext()).getUnmanagedValue(); assert(metatype->getType().castTo<AnyMetatypeType>()->getRepresentation() == MetatypeRepresentation::Thick); auto upcast = B.createInitExistentialMetatype(loc, metatype, existentialTL.getLoweredType(), conformances); return ManagedValue::forUnmanaged(upcast); } case ExistentialRepresentation::Class: { assert(existentialTL.isLoadable()); ManagedValue sub = F(SGFContext()); SILValue v = B.createInitExistentialRef(loc, existentialTL.getLoweredType(), concreteFormalType, sub.getValue(), conformances); return ManagedValue(v, sub.getCleanup()); } case ExistentialRepresentation::Boxed: { // Allocate the existential. auto *existential = B.createAllocExistentialBox(loc, existentialTL.getLoweredType(), concreteFormalType, conformances); auto *valueAddr = B.createProjectExistentialBox(loc, concreteTL.getLoweredType(), existential); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Boxed, *this)); ManagedValue mv = F(SGFContext(init.get())); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init->getAddress()); init->finishInitialization(*this); } return emitManagedRValueWithCleanup(existential); } case ExistentialRepresentation::Opaque: { // Allocate the existential. SILValue existential = getBufferForExprResult(loc, existentialTL.getLoweredType(), C); // Allocate the concrete value inside the container. SILValue valueAddr = B.createInitExistentialAddr( loc, existential, concreteFormalType, concreteTL.getLoweredType(), conformances); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Opaque, *this)); ManagedValue mv = F(SGFContext(init.get())); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init->getAddress()); init->finishInitialization(*this); } return manageBufferForExprResult(existential, existentialTL, C); } } }
ManagedValue SILGenFunction::emitExistentialErasure( SILLocation loc, CanType concreteFormalType, const TypeLowering &concreteTL, const TypeLowering &existentialTL, const ArrayRef<ProtocolConformance *> &conformances, SGFContext C, llvm::function_ref<ManagedValue (SGFContext)> F) { // Mark the needed conformances as used. for (auto *conformance : conformances) SGM.useConformance(conformance); switch (existentialTL.getLoweredType().getObjectType() .getPreferredExistentialRepresentation(SGM.M, concreteFormalType)) { case ExistentialRepresentation::None: llvm_unreachable("not an existential type"); case ExistentialRepresentation::Metatype: { assert(existentialTL.isLoadable()); SILValue metatype = F(SGFContext()).getUnmanagedValue(); assert(metatype.getType().castTo<AnyMetatypeType>()->getRepresentation() == MetatypeRepresentation::Thick); auto upcast = B.createInitExistentialMetatype(loc, metatype, existentialTL.getLoweredType(), conformances); return ManagedValue::forUnmanaged(upcast); } case ExistentialRepresentation::Class: { assert(existentialTL.isLoadable()); ManagedValue sub = F(SGFContext()); SILValue v = B.createInitExistentialRef(loc, existentialTL.getLoweredType(), concreteFormalType, sub.getValue(), conformances); return ManagedValue(v, sub.getCleanup()); } case ExistentialRepresentation::Boxed: { // Allocate the existential. auto box = B.createAllocExistentialBox(loc, existentialTL.getLoweredType(), concreteFormalType, concreteTL.getLoweredType(), conformances); auto existential = box->getExistentialResult(); auto valueAddr = box->getValueAddressResult(); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Boxed, *this)); ManagedValue mv = F(SGFContext(init.get())); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init->getAddress()); init->finishInitialization(*this); } return emitManagedRValueWithCleanup(existential); } case ExistentialRepresentation::Opaque: { // Allocate the existential. SILValue existential = getBufferForExprResult(loc, existentialTL.getLoweredType(), C); // Allocate the concrete value inside the container. SILValue valueAddr = B.createInitExistentialAddr( loc, existential, concreteFormalType, concreteTL.getLoweredType(), conformances); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Opaque, *this)); ManagedValue mv = F(SGFContext(init.get())); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init->getAddress()); init->finishInitialization(*this); } return manageBufferForExprResult(existential, existentialTL, C); } } }
ManagedValue SILGenFunction::emitExistentialErasure( SILLocation loc, CanType concreteFormalType, const TypeLowering &concreteTL, const TypeLowering &existentialTL, ArrayRef<ProtocolConformanceRef> conformances, SGFContext C, llvm::function_ref<ManagedValue (SGFContext)> F, bool allowEmbeddedNSError) { // Mark the needed conformances as used. for (auto conformance : conformances) SGM.useConformance(conformance); // If we're erasing to the 'Error' type, we might be able to get an NSError // representation more efficiently. auto &ctx = getASTContext(); if (ctx.LangOpts.EnableObjCInterop && conformances.size() == 1 && conformances[0].getRequirement() == ctx.getErrorDecl() && ctx.getNSErrorDecl()) { auto nsErrorDecl = ctx.getNSErrorDecl(); // If the concrete type is NSError or a subclass thereof, just erase it // directly. auto nsErrorType = nsErrorDecl->getDeclaredType()->getCanonicalType(); if (nsErrorType->isExactSuperclassOf(concreteFormalType, nullptr)) { ManagedValue nsError = F(SGFContext()); if (nsErrorType != concreteFormalType) { nsError = ManagedValue(B.createUpcast(loc, nsError.getValue(), getLoweredType(nsErrorType)), nsError.getCleanup()); } return emitBridgedToNativeError(loc, nsError); } // If the concrete type is known to conform to _BridgedStoredNSError, // call the _nsError witness getter to extract the NSError directly, // then just erase the NSError. if (auto storedNSErrorConformance = SGM.getConformanceToBridgedStoredNSError(loc, concreteFormalType)) { auto nsErrorVar = SGM.getNSErrorRequirement(loc); if (!nsErrorVar) return emitUndef(loc, existentialTL.getLoweredType()); SubstitutionList nsErrorVarSubstitutions; // Devirtualize. Maybe this should be done implicitly by // emitPropertyLValue? if (storedNSErrorConformance->isConcrete()) { if (auto witnessVar = storedNSErrorConformance->getConcrete() ->getWitness(nsErrorVar, nullptr)) { nsErrorVar = cast<VarDecl>(witnessVar.getDecl()); nsErrorVarSubstitutions = witnessVar.getSubstitutions(); } } auto nativeError = F(SGFContext()); WritebackScope writebackScope(*this); auto nsError = emitRValueForPropertyLoad(loc, nativeError, concreteFormalType, /*super*/ false, nsErrorVar, nsErrorVarSubstitutions, AccessSemantics::Ordinary, nsErrorType, SGFContext()) .getAsSingleValue(*this, loc); return emitBridgedToNativeError(loc, nsError); } // Otherwise, if it's an archetype, try calling the _getEmbeddedNSError() // witness to try to dig out the embedded NSError. But don't do this // when we're being called recursively. if (isa<ArchetypeType>(concreteFormalType) && allowEmbeddedNSError) { auto contBB = createBasicBlock(); auto isNotPresentBB = createBasicBlock(); auto isPresentBB = createBasicBlock(); // Call swift_stdlib_getErrorEmbeddedNSError to attempt to extract an // NSError from the value. auto getEmbeddedNSErrorFn = SGM.getGetErrorEmbeddedNSError(loc); if (!getEmbeddedNSErrorFn) return emitUndef(loc, existentialTL.getLoweredType()); Substitution getEmbeddedNSErrorSubstitutions[1] = { Substitution(concreteFormalType, conformances) }; ManagedValue concreteValue = F(SGFContext()); ManagedValue potentialNSError = emitApplyOfLibraryIntrinsic(loc, getEmbeddedNSErrorFn, getEmbeddedNSErrorSubstitutions, { concreteValue.copy(*this, loc) }, SGFContext()) .getAsSingleValue(*this, loc); // We're going to consume 'concreteValue' in exactly one branch, // so kill its cleanup now and recreate it on both branches. (void) concreteValue.forward(*this); // Check whether we got an NSError back. std::pair<EnumElementDecl*, SILBasicBlock*> cases[] = { { ctx.getOptionalSomeDecl(), isPresentBB }, { ctx.getOptionalNoneDecl(), isNotPresentBB } }; B.createSwitchEnum(loc, potentialNSError.forward(*this), /*default*/ nullptr, cases); // If we did get an NSError, emit the existential erasure from that // NSError. B.emitBlock(isPresentBB); SILValue branchArg; { // Don't allow cleanups to escape the conditional block. FullExpr presentScope(Cleanups, CleanupLocation::get(loc)); enterDestroyCleanup(concreteValue.getValue()); // Receive the error value. It's typed as an 'AnyObject' for // layering reasons, so perform an unchecked cast down to NSError. SILType anyObjectTy = potentialNSError.getType().getAnyOptionalObjectType(); SILValue nsError = isPresentBB->createPHIArgument( anyObjectTy, ValueOwnershipKind::Owned); nsError = B.createUncheckedRefCast(loc, nsError, getLoweredType(nsErrorType)); branchArg = emitBridgedToNativeError(loc, emitManagedRValueWithCleanup(nsError)) .forward(*this); } B.createBranch(loc, contBB, branchArg); // If we did not get an NSError, just directly emit the existential. // Since this is a recursive call, make sure we don't end up in this // path again. B.emitBlock(isNotPresentBB); { FullExpr presentScope(Cleanups, CleanupLocation::get(loc)); concreteValue = emitManagedRValueWithCleanup(concreteValue.getValue()); branchArg = emitExistentialErasure(loc, concreteFormalType, concreteTL, existentialTL, conformances, SGFContext(), [&](SGFContext C) { return concreteValue; }, /*allowEmbeddedNSError=*/false) .forward(*this); } B.createBranch(loc, contBB, branchArg); // Continue. B.emitBlock(contBB); SILValue existentialResult = contBB->createPHIArgument( existentialTL.getLoweredType(), ValueOwnershipKind::Owned); return emitManagedRValueWithCleanup(existentialResult, existentialTL); } } switch (existentialTL.getLoweredType().getObjectType() .getPreferredExistentialRepresentation(SGM.M, concreteFormalType)) { case ExistentialRepresentation::None: llvm_unreachable("not an existential type"); case ExistentialRepresentation::Metatype: { assert(existentialTL.isLoadable()); SILValue metatype = F(SGFContext()).getUnmanagedValue(); assert(metatype->getType().castTo<AnyMetatypeType>()->getRepresentation() == MetatypeRepresentation::Thick); auto upcast = B.createInitExistentialMetatype(loc, metatype, existentialTL.getLoweredType(), conformances); return ManagedValue::forUnmanaged(upcast); } case ExistentialRepresentation::Class: { assert(existentialTL.isLoadable()); ManagedValue sub = F(SGFContext()); SILValue v = B.createInitExistentialRef(loc, existentialTL.getLoweredType(), concreteFormalType, sub.getValue(), conformances); return ManagedValue(v, sub.getCleanup()); } case ExistentialRepresentation::Boxed: { // Allocate the existential. auto *existential = B.createAllocExistentialBox(loc, existentialTL.getLoweredType(), concreteFormalType, conformances); auto *valueAddr = B.createProjectExistentialBox(loc, concreteTL.getLoweredType(), existential); // Initialize the concrete value in-place. ExistentialInitialization init(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Boxed, *this); ManagedValue mv = F(SGFContext(&init)); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init.getAddress()); init.finishInitialization(*this); } return emitManagedRValueWithCleanup(existential); } case ExistentialRepresentation::Opaque: { // If the concrete value is a pseudogeneric archetype, first erase it to // its upper bound. auto anyObjectProto = getASTContext() .getProtocol(KnownProtocolKind::AnyObject); auto anyObjectTy = anyObjectProto ? anyObjectProto->getDeclaredType()->getCanonicalType() : CanType(); auto eraseToAnyObject = [&, concreteFormalType, F](SGFContext C) -> ManagedValue { auto concreteValue = F(SGFContext()); auto anyObjectConformance = SGM.SwiftModule ->lookupConformance(concreteFormalType, anyObjectProto, nullptr); ProtocolConformanceRef buf[] = { *anyObjectConformance, }; auto asAnyObject = B.createInitExistentialRef(loc, SILType::getPrimitiveObjectType(anyObjectTy), concreteFormalType, concreteValue.getValue(), getASTContext().AllocateCopy(buf)); return ManagedValue(asAnyObject, concreteValue.getCleanup()); }; auto concreteTLPtr = &concreteTL; if (this->F.getLoweredFunctionType()->isPseudogeneric()) { if (anyObjectTy && concreteFormalType->is<ArchetypeType>()) { concreteFormalType = anyObjectTy; concreteTLPtr = &getTypeLowering(anyObjectTy); F = eraseToAnyObject; } } // Allocate the existential. SILValue existential = getBufferForExprResult(loc, existentialTL.getLoweredType(), C); // Allocate the concrete value inside the container. SILValue valueAddr = B.createInitExistentialAddr( loc, existential, concreteFormalType, concreteTLPtr->getLoweredType(), conformances); // Initialize the concrete value in-place. InitializationPtr init( new ExistentialInitialization(existential, valueAddr, concreteFormalType, ExistentialRepresentation::Opaque, *this)); ManagedValue mv = F(SGFContext(init.get())); if (!mv.isInContext()) { mv.forwardInto(*this, loc, init->getAddress()); init->finishInitialization(*this); } return manageBufferForExprResult(existential, existentialTL, C); } } llvm_unreachable("Unhandled ExistentialRepresentation in switch."); }