| //===--- SILGenConvert.cpp - Type Conversion Routines ---------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SILGen.h" |
| #include "Scope.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/Types.h" |
| #include "swift/Basic/Fallthrough.h" |
| #include "swift/Basic/type_traits.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/SIL/TypeLowering.h" |
| #include "Initialization.h" |
| #include "LValue.h" |
| #include "RValue.h" |
| #include "ArgumentSource.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| // FIXME: need to sit down and abstract away differences between |
| // SGF::emitInjectOptionalInto(), SGF::emitInjectOptionalValueInto(), |
| // SGF::getOptionalSomeValue(), and this function... |
| ManagedValue |
| SILGenFunction::emitInjectOptional(SILLocation loc, |
| ManagedValue v, |
| CanType inputFormalType, |
| CanType substFormalType, |
| const TypeLowering &expectedTL, |
| SGFContext ctxt) { |
| // Optional's payload is currently maximally abstracted. FIXME: Eventually |
| // it shouldn't be. |
| auto opaque = AbstractionPattern::getOpaque(); |
| |
| OptionalTypeKind substOTK; |
| auto substObjectType = substFormalType.getAnyOptionalObjectType(substOTK); |
| |
| auto loweredTy = getLoweredType(opaque, substObjectType); |
| if (v.getType() != loweredTy) |
| v = emitTransformedValue(loc, v, |
| AbstractionPattern(inputFormalType), inputFormalType, |
| opaque, substObjectType); |
| |
| auto someDecl = getASTContext().getOptionalSomeDecl(substOTK); |
| SILType optTy = getLoweredType(substFormalType); |
| if (v.getType().isAddress()) { |
| auto buf = getBufferForExprResult(loc, optTy.getObjectType(), ctxt); |
| auto payload = B.createInitEnumDataAddr(loc, buf, someDecl, |
| v.getType()); |
| // FIXME: Is it correct to use IsTake here even if v doesn't have a cleanup? |
| B.createCopyAddr(loc, v.forward(*this), payload, |
| IsTake, IsInitialization); |
| B.createInjectEnumAddr(loc, buf, someDecl); |
| v = manageBufferForExprResult(buf, expectedTL, ctxt); |
| } else { |
| auto some = B.createEnum(loc, v.getValue(), someDecl, optTy); |
| v = ManagedValue(some, v.getCleanup()); |
| } |
| |
| return v; |
| } |
| |
| 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()); |
| |
| CanType formalOptType = optType.getSwiftRValueType(); |
| auto archetype = formalOptType->getNominalOrBoundGenericNominal() |
| ->getGenericParams()->getPrimaryArchetypes()[0]; |
| AbstractionPattern origType(archetype); |
| |
| // 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) { |
| OptionalTypeKind OTK; |
| optTL.getLoweredType().getSwiftRValueType()->getAnyOptionalObjectType(OTK); |
| assert(OTK != OTK_None); |
| |
| B.createInjectEnumAddr(loc, dest, getASTContext().getOptionalNoneDecl(OTK)); |
| } |
| |
| /// 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"); |
| OptionalTypeKind OTK; |
| optTL.getLoweredType().getSwiftRValueType()->getAnyOptionalObjectType(OTK); |
| assert(OTK != OTK_None); |
| |
| return B.createEnum(loc, SILValue(), getASTContext().getOptionalNoneDecl(OTK), |
| optTL.getLoweredType()); |
| } |
| |
| /// 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); |
| } |
| |
| static Substitution getSimpleSubstitution(GenericParamList &generics, |
| CanType typeArg) { |
| assert(generics.getParams().size() == 1); |
| auto typeParamDecl = generics.getParams().front(); |
| return Substitution{typeParamDecl->getArchetype(), typeArg, {}}; |
| } |
| |
| /// Create the correct substitution for calling the given function at |
| /// the given type. |
| static Substitution getSimpleSubstitution(FuncDecl *fn, CanType typeArg) { |
| auto polyFnType = |
| cast<PolymorphicFunctionType>(fn->getType()->getCanonicalType()); |
| return getSimpleSubstitution(polyFnType->getGenericParams(), typeArg); |
| } |
| |
| static CanType getOptionalValueType(SILType optType, |
| OptionalTypeKind &optionalKind) { |
| auto generic = cast<BoundGenericType>(optType.getSwiftRValueType()); |
| optionalKind = generic->getDecl()->classifyAsOptionalType(); |
| assert(optionalKind); |
| return generic.getGenericArgs()[0]; |
| } |
| |
| void SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc, |
| SILValue addr) { |
| OptionalTypeKind OTK; |
| getOptionalValueType(addr.getType().getObjectType(), OTK); |
| |
| // Generate code to the optional is present, and if not abort with a message |
| // (provided by the stdlib). |
| SILBasicBlock *contBB = createBasicBlock(); |
| SILBasicBlock *failBB = createBasicBlock(); |
| |
| auto NoneEnumElementDecl = getASTContext().getOptionalNoneDecl(OTK); |
| B.createSwitchEnumAddr(loc, addr, /*defaultDest*/contBB, |
| { { NoneEnumElementDecl, failBB }}); |
| |
| B.emitBlock(failBB); |
| |
| // Call the standard library implementation of _diagnoseUnexpectedNilOptional. |
| if (auto diagnoseFailure = |
| getASTContext().getDiagnoseUnexpectedNilOptional(nullptr)) { |
| emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, {}, {}, |
| SGFContext()); |
| } |
| |
| B.createUnreachable(loc); |
| B.clearInsertionPoint(); |
| B.emitBlock(contBB); |
| } |
| |
| SILValue SILGenFunction::emitDoesOptionalHaveValue(SILLocation loc, |
| SILValue addrOrValue) { |
| SILType optType = addrOrValue.getType().getObjectType(); |
| OptionalTypeKind optionalKind; |
| getOptionalValueType(optType, optionalKind); |
| |
| auto boolTy = SILType::getBuiltinIntegerType(1, getASTContext()); |
| SILValue yes = B.createIntegerLiteral(loc, boolTy, 1); |
| SILValue no = B.createIntegerLiteral(loc, boolTy, 0); |
| auto someDecl = getASTContext().getOptionalSomeDecl(optionalKind); |
| |
| if (addrOrValue.getType().isAddress()) |
| return B.createSelectEnumAddr(loc, addrOrValue, boolTy, no, |
| std::make_pair(someDecl, yes)); |
| return B.createSelectEnum(loc, addrOrValue, boolTy, no, |
| std::make_pair(someDecl, yes)); |
| } |
| |
| ManagedValue SILGenFunction::emitCheckedGetOptionalValueFrom(SILLocation loc, |
| ManagedValue src, |
| const TypeLowering &optTL, |
| SGFContext C) { |
| SILType optType = src.getType().getObjectType(); |
| OptionalTypeKind optionalKind; |
| CanType valueType = getOptionalValueType(optType, optionalKind); |
| |
| FuncDecl *fn = getASTContext().getGetOptionalValueDecl(nullptr, optionalKind); |
| Substitution sub = getSimpleSubstitution(fn, valueType); |
| |
| // The intrinsic takes its parameter indirectly. |
| if (src.getType().isObject()) { |
| auto buf = emitTemporaryAllocation(loc, src.getType()); |
| B.createStore(loc, src.forward(*this), buf); |
| src = emitManagedBufferWithCleanup(buf); |
| } |
| |
| return emitApplyOfLibraryIntrinsic(loc, fn, sub, src, C); |
| } |
| |
| 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); |
| } |
| |
| /// Emit an optional-to-optional transformation. |
| ManagedValue |
| SILGenFunction::emitOptionalToOptional(SILLocation loc, |
| ManagedValue input, |
| SILType resultTy, |
| const ValueTransform &transformValue) { |
| auto contBB = createBasicBlock(); |
| auto isNotPresentBB = createBasicBlock(); |
| auto isPresentBB = createBasicBlock(); |
| |
| // Create a temporary for the output optional. |
| auto &resultTL = getTypeLowering(resultTy); |
| |
| // If the result is address-only, we need to return something in memory, |
| // otherwise the result is the BBArgument in the merge point. |
| SILValue result; |
| if (resultTL.isAddressOnly()) |
| result = emitTemporaryAllocation(loc, resultTy); |
| else |
| result = new (F.getModule()) SILArgument(contBB, resultTL.getLoweredType()); |
| |
| |
| // Branch on whether the input is optional, this doesn't consume the value. |
| auto isPresent = emitDoesOptionalHaveValue(loc, input.getValue()); |
| B.createCondBranch(loc, isPresent, isPresentBB, isNotPresentBB); |
| |
| // If it's present, apply the recursive transformation to the value. |
| B.emitBlock(isPresentBB); |
| SILValue branchArg; |
| { |
| // Don't allow cleanups to escape the conditional block. |
| FullExpr presentScope(Cleanups, CleanupLocation::get(loc)); |
| |
| CanType resultValueTy = |
| resultTy.getSwiftRValueType().getAnyOptionalObjectType(); |
| assert(resultValueTy); |
| SILType loweredResultValueTy = getLoweredType(resultValueTy); |
| |
| // Pull the value out. This will load if the value is not address-only. |
| auto &inputTL = getTypeLowering(input.getType()); |
| auto inputValue = emitUncheckedGetOptionalValueFrom(loc, input, |
| inputTL, SGFContext()); |
| |
| // Transform it. |
| auto resultValue = transformValue(*this, loc, inputValue, |
| loweredResultValueTy); |
| |
| // Inject that into the result type if the result is address-only. |
| if (resultTL.isAddressOnly()) { |
| ArgumentSource resultValueRV(loc, RValue(resultValue, resultValueTy)); |
| emitInjectOptionalValueInto(loc, std::move(resultValueRV), |
| result, resultTL); |
| } else { |
| resultValue = getOptionalSomeValue(loc, resultValue, resultTL); |
| branchArg = resultValue.forward(*this); |
| } |
| } |
| if (branchArg) |
| B.createBranch(loc, contBB, branchArg); |
| else |
| B.createBranch(loc, contBB); |
| |
| // If it's not present, inject 'nothing' into the result. |
| B.emitBlock(isNotPresentBB); |
| if (resultTL.isAddressOnly()) { |
| emitInjectOptionalNothingInto(loc, result, resultTL); |
| B.createBranch(loc, contBB); |
| } else { |
| branchArg = getOptionalNoneValue(loc, resultTL); |
| B.createBranch(loc, contBB, branchArg); |
| } |
| |
| // Continue. |
| B.emitBlock(contBB); |
| if (resultTL.isAddressOnly()) |
| return emitManagedBufferWithCleanup(result, resultTL); |
| |
| return emitManagedRValueWithCleanup(result, resultTL); |
| } |
| |
| /// Destroy the value, unless it was both uniquely referenced and consumed. |
| void SILGenFunction::OpaqueValueState::destroy(SILGenFunction &gen, |
| SILLocation loc) { |
| if (isConsumable && !hasBeenConsumed) { |
| auto &lowering = gen.getTypeLowering(value.getType().getSwiftRValueType()); |
| lowering.emitDestroyRValue(gen.B, loc, value); |
| } |
| } |
| |
| SILGenFunction::OpaqueValueRAII::~OpaqueValueRAII() { |
| auto entry = Self.OpaqueValues.find(OpaqueValue); |
| entry->second.destroy(Self, OpaqueValue); |
| Self.OpaqueValues.erase(entry); |
| } |
| |
| namespace { |
| |
| /// This is an initialization for an address-only existential in memory. |
| class ExistentialInitialization : public KnownAddressInitialization { |
| CleanupHandle Cleanup; |
| public: |
| /// \param existential The existential container |
| /// \param address Address of value in existential container |
| /// \param concreteFormalType Unlowered AST type of value |
| /// \param repr Representation of container |
| ExistentialInitialization(SILValue existential, SILValue address, |
| CanType concreteFormalType, |
| ExistentialRepresentation repr, |
| SILGenFunction &gen) |
| : KnownAddressInitialization(address) { |
| // Any early exit before we store a value into the existential must |
| // clean up the existential container. |
| Cleanup = gen.enterDeinitExistentialCleanup(existential, |
| concreteFormalType, |
| repr); |
| } |
| |
| void finishInitialization(SILGenFunction &gen) { |
| gen.Cleanups.setCleanupState(Cleanup, CleanupState::Dead); |
| } |
| }; |
| |
| } |
| |
| 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::emitClassMetatypeToObject(SILLocation loc, |
| ManagedValue v, |
| SILType resultTy) { |
| SILValue value = v.getUnmanagedValue(); |
| |
| // Convert the metatype to objc representation. |
| auto metatypeTy = value.getType().castTo<MetatypeType>(); |
| auto objcMetatypeTy = CanMetatypeType::get(metatypeTy.getInstanceType(), |
| MetatypeRepresentation::ObjC); |
| value = B.createThickToObjCMetatype(loc, value, |
| SILType::getPrimitiveObjectType(objcMetatypeTy)); |
| |
| // Convert to an object reference. |
| value = B.createObjCMetatypeToObject(loc, value, resultTy); |
| |
| return ManagedValue::forUnmanaged(value); |
| } |
| |
| ManagedValue SILGenFunction::emitExistentialMetatypeToObject(SILLocation loc, |
| ManagedValue v, |
| SILType resultTy) { |
| SILValue value = v.getUnmanagedValue(); |
| |
| // Convert the metatype to objc representation. |
| auto metatypeTy = value.getType().castTo<ExistentialMetatypeType>(); |
| auto objcMetatypeTy = CanExistentialMetatypeType::get( |
| metatypeTy.getInstanceType(), |
| MetatypeRepresentation::ObjC); |
| value = B.createThickToObjCMetatype(loc, value, |
| SILType::getPrimitiveObjectType(objcMetatypeTy)); |
| |
| // Convert to an object reference. |
| value = B.createObjCExistentialMetatypeToObject(loc, value, resultTy); |
| |
| return ManagedValue::forUnmanaged(value); |
| } |
| |
| ManagedValue SILGenFunction::emitProtocolMetatypeToObject(SILLocation loc, |
| CanType inputTy, |
| SILType resultTy) { |
| ProtocolDecl *protocol = inputTy->castTo<MetatypeType>() |
| ->getInstanceType()->castTo<ProtocolType>()->getDecl(); |
| |
| SILValue value = B.createObjCProtocol(loc, protocol, resultTy); |
| |
| // Protocol objects, despite being global objects, inherit default reference |
| // counting semantics from NSObject, so we need to retain the protocol |
| // reference when we use it to prevent it being released and attempting to |
| // deallocate itself. It doesn't matter if we ever actually clean up that |
| // retain though. |
| B.createStrongRetain(loc, value); |
| |
| return ManagedValue::forUnmanaged(value); |
| } |
| |
| SILGenFunction::OpaqueValueState |
| SILGenFunction::emitOpenExistential( |
| SILLocation loc, |
| ManagedValue existentialValue, |
| CanArchetypeType openedArchetype, |
| SILType loweredOpenedType) { |
| // Open the existential value into the opened archetype value. |
| bool isUnique = true; |
| bool canConsume; |
| SILValue archetypeValue; |
| |
| SILType existentialType = existentialValue.getType(); |
| switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) { |
| case ExistentialRepresentation::Opaque: |
| assert(existentialType.isAddress()); |
| archetypeValue = B.createOpenExistentialAddr( |
| loc, existentialValue.forward(*this), |
| loweredOpenedType); |
| if (existentialValue.hasCleanup()) { |
| canConsume = true; |
| // Leave a cleanup to deinit the existential container. |
| enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(), |
| ExistentialRepresentation::Opaque); |
| } else { |
| canConsume = false; |
| } |
| break; |
| case ExistentialRepresentation::Metatype: |
| assert(existentialType.isObject()); |
| archetypeValue = B.createOpenExistentialMetatype( |
| loc, existentialValue.forward(*this), |
| loweredOpenedType); |
| // Metatypes are always trivial. Consuming would be a no-op. |
| canConsume = false; |
| break; |
| case ExistentialRepresentation::Class: |
| assert(existentialType.isObject()); |
| archetypeValue = B.createOpenExistentialRef( |
| loc, existentialValue.forward(*this), |
| loweredOpenedType); |
| canConsume = existentialValue.hasCleanup(); |
| break; |
| case ExistentialRepresentation::Boxed: |
| if (existentialType.isAddress()) { |
| existentialValue = emitLoad(loc, existentialValue.getValue(), |
| getTypeLowering(existentialType), |
| SGFContext::AllowGuaranteedPlusZero, |
| IsNotTake); |
| } |
| |
| existentialType = existentialValue.getType(); |
| assert(existentialType.isObject()); |
| // NB: Don't forward the cleanup, because consuming a boxed value won't |
| // consume the box reference. |
| archetypeValue = B.createOpenExistentialBox( |
| loc, existentialValue.getValue(), |
| loweredOpenedType); |
| // The boxed value can't be assumed to be uniquely referenced. We can never |
| // consume it. |
| // TODO: We could use isUniquelyReferenced to shorten the duration of |
| // the box to the point that the opaque value is copied out. |
| isUnique = false; |
| canConsume = false; |
| break; |
| case ExistentialRepresentation::None: |
| llvm_unreachable("not existential"); |
| } |
| setArchetypeOpeningSite(openedArchetype, archetypeValue); |
| |
| assert(!canConsume || isUnique); |
| |
| return SILGenFunction::OpaqueValueState{ |
| archetypeValue, |
| /*isConsumable*/ canConsume, |
| /*hasBeenConsumed*/ false |
| }; |
| } |
| |
| ManagedValue SILGenFunction::manageOpaqueValue(OpaqueValueState &entry, |
| SILLocation loc, |
| SGFContext C) { |
| // If the context wants a +0 value, guaranteed or immediate, we can |
| // give it to them, because OpenExistential emission guarantees the |
| // value. |
| if (C.isGuaranteedPlusZeroOk()) { |
| return ManagedValue::forUnmanaged(entry.value); |
| } |
| |
| // If the opaque value is consumable, we can just return the |
| // value with a cleanup. There is no need to retain it separately. |
| if (entry.isConsumable) { |
| assert(!entry.hasBeenConsumed |
| && "Uniquely-referenced opaque value already consumed"); |
| entry.hasBeenConsumed = true; |
| return emitManagedRValueWithCleanup(entry.value); |
| } |
| |
| // If the context wants us to initialize a buffer, copy there instead |
| // of making a temporary allocation. |
| if (auto I = C.getEmitInto()) { |
| if (SILValue address = I->getAddressForInPlaceInitialization()) { |
| ManagedValue::forUnmanaged(entry.value).copyInto(*this, address, loc); |
| I->finishInitialization(*this); |
| return ManagedValue::forInContext(); |
| } |
| } |
| |
| // Otherwise, copy the value into a temporary. |
| return ManagedValue::forUnmanaged(entry.value).copyUnmanaged(*this, loc); |
| } |