RValue::RValue(SILGenFunction &gen, SILLocation l, CanType formalType, ManagedValue v) : type(formalType), elementsToBeAdded(0) { assert(v && "creating r-value with consumed value"); if (v.isInContext()) { type = CanType(); elementsToBeAdded = Used; return; } ExplodeTupleValue(values, gen, l).visit(formalType, v); assert(values.size() == getRValueSize(type)); }
static ManagedValue emitBridgeBoolToDarwinBoolean(SILGenFunction &gen, SILLocation loc, ManagedValue swiftBool) { // func _convertBoolToDarwinBoolean(Bool) -> DarwinBoolean SILValue boolToDarwinBooleanFn = gen.emitGlobalFunctionRef(loc, gen.SGM.getBoolToDarwinBooleanFn()); SILType resultTy = gen.getLoweredLoadableType(gen.SGM.Types.getDarwinBooleanType()); SILValue result = gen.B.createApply(loc, boolToDarwinBooleanFn, boolToDarwinBooleanFn.getType(), resultTy, {}, swiftBool.forward(gen)); return gen.emitManagedRValueWithCleanup(result); }
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; }
/// 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(); (void)formalOptType; assert(formalOptType.getAnyOptionalObjectType()); auto someDecl = getASTContext().getOptionalSomeDecl(); SILValue result = B.createEnum(loc, value.forward(*this), someDecl, optTL.getLoweredType()); return emitManagedRValueWithCleanup(result, optTL); }
/// Emit an open-coded static implementation for materializeForSet. void SILGenFunction::emitMaterializeForSet(FuncDecl *decl) { assert(decl->getAccessorKind() == AccessorKind::IsMaterializeForSet); MagicFunctionName = SILGenModule::getMagicFunctionName(decl); F.setBare(IsBare); SmallVector<ManagedValue, 4> params; collectThunkParams(RegularLocation(decl), params, /*allowPlusZero*/ true); ManagedValue self = params.back(); SILValue resultBuffer = params[0].getUnmanagedValue(); SILValue callbackBuffer = params[1].getUnmanagedValue(); auto indices = ArrayRef<ManagedValue>(params).slice(2).drop_back(); MaterializeForSetEmitter emitter(SGM, /*conformance=*/ nullptr, /*requirement=*/ nullptr, decl, getForwardingSubstitutions(), self.getType()); emitter.emit(*this, self, resultBuffer, callbackBuffer, indices); }
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 emitManagedRValueWithCleanup(value); }
ManagedValue SILGenBuilder::createAllocRefDynamic( SILLocation loc, ManagedValue operand, SILType refType, bool objc, ArrayRef<SILType> inputElementTypes, ArrayRef<ManagedValue> inputElementCountOperands) { llvm::SmallVector<SILType, 8> elementTypes(inputElementTypes.begin(), inputElementTypes.end()); llvm::SmallVector<SILValue, 8> elementCountOperands; std::transform(std::begin(inputElementCountOperands), std::end(inputElementCountOperands), std::back_inserter(elementCountOperands), [](ManagedValue mv) -> SILValue { return mv.getValue(); }); AllocRefDynamicInst *i = createAllocRefDynamic(loc, operand.getValue(), refType, objc, elementTypes, elementCountOperands); return SGF.emitManagedRValueWithCleanup(i); }
/// Bridge ErrorType to a foreign error type. ManagedValue SILGenFunction::emitNativeToBridgedError(SILLocation loc, ManagedValue nativeError, CanType bridgedErrorType) { assert(bridgedErrorType == SGM.Types.getNSErrorType() && "only handling NSError for now"); auto bridgeFn = emitGlobalFunctionRef(loc, SGM.getErrorTypeToNSErrorFn()); auto bridgeFnType = bridgeFn.getType().castTo<SILFunctionType>(); assert(bridgeFnType->getResult().getConvention() == ResultConvention::Owned); assert(bridgeFnType->getParameters()[0].getConvention() == ParameterConvention::Direct_Owned); SILValue bridgedError = B.createApply(loc, bridgeFn, bridgeFn.getType(), bridgeFnType->getResult().getSILType(), {}, nativeError.forward(*this)); return emitManagedRValueWithCleanup(bridgedError); }
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); }
/// Step out of the current control flow to emit a foreign error block, /// which loads from the error slot and jumps to the error slot. void SILGenFunction::emitForeignErrorBlock(SILLocation loc, SILBasicBlock *errorBB, ManagedValue errorSlot) { SavedInsertionPoint savedIP(*this, errorBB, FunctionSection::Postmatter); // Load the error (taking responsibility for it). In theory, this // is happening within conditional code, so we need to be only // conditionally claiming the value. In practice, claiming it // unconditionally is fine because we want to assume it's nil in the // other path. SILValue errorV = B.createLoad(loc, errorSlot.forward(*this)); ManagedValue error = emitManagedRValueWithCleanup(errorV); // Turn the error into an ErrorProtocol value. error = emitBridgedToNativeError(loc, error); // Propagate. FullExpr scope(Cleanups, CleanupLocation::get(loc)); emitThrow(loc, error); }
void SILGenFunction::emitThrow(SILLocation loc, ManagedValue exnMV, bool emitWillThrow) { assert(ThrowDest.isValid() && "calling emitThrow with invalid throw destination!"); // Claim the exception value. If we need to handle throwing // cleanups, the correct thing to do here is to recreate the // exception's cleanup when emitting each cleanup we branch through. // But for now we aren't bothering. SILValue exn = exnMV.forward(*this); if (emitWillThrow) { // Generate a call to the 'swift_willThrow' runtime function to allow the // debugger to catch the throw event. B.createBuiltin(loc, SGM.getASTContext().getIdentifier("willThrow"), SGM.Types.getEmptyTupleType(), {}, {exn}); } // Branch to the cleanup destination. Cleanups.emitBranchAndCleanups(ThrowDest, loc, exn); }
/// Perform a foreign error check by testing whether the call result is zero. /// The call result is otherwise ignored. static void emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue result, ManagedValue errorSlot, bool suppressErrorCheck, bool zeroIsError) { // Just ignore the call result if we're suppressing the error check. if (suppressErrorCheck) { return; } SILValue resultValue = emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue()); CanType resultType = resultValue->getType().getSwiftRValueType(); if (!resultType->isBuiltinIntegerType(1)) { SILValue zero = gen.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = gen.getASTContext(); resultValue = gen.B.createBuiltinBinaryFunction(loc, "cmp_ne", resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); } SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = gen.createBasicBlock(); if (zeroIsError) gen.B.createCondBranch(loc, resultValue, contBB, errorBB); else gen.B.createCondBranch(loc, resultValue, errorBB, contBB); gen.emitForeignErrorBlock(loc, errorBB, errorSlot); gen.B.emitBlock(contBB); }
/// 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); AbstractionPattern origType = AbstractionPattern::getOpaque(); // 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); }
/// 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); }
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); }
// FIXME: With some changes to their callers, all of the below functions // could be re-worked to use emitInjectEnum(). 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; }
ManagedValue SILGenBuilder:: createValueMetatype(SILLocation loc, SILType metatype, ManagedValue base) { SILValue v = createValueMetatype(loc, metatype, base.getValue()); return ManagedValue::forUnmanaged(v); }
ManagedValue SILGenBuilder::createTupleElementAddr(SILLocation Loc, ManagedValue Value, unsigned Index) { SILType Type = Value.getType().getTupleElementType(Index); return createTupleElementAddr(Loc, Value, Index, Type); }
ManagedValue SILGenBuilder::createUpcast(SILLocation loc, ManagedValue original, SILType type) { CleanupCloner cloner(*this, original); SILValue convertedValue = createUpcast(loc, original.forward(SGF), type); return cloner.clone(convertedValue); }
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(); 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); } } }
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) { assert(!ctor->isFactoryInit() && "factories should not be emitted here"); // Emit the prolog. Since we're just going to forward our args directly // to the initializer, don't allocate local variables for them. RegularLocation Loc(ctor); Loc.markAutoGenerated(); // Forward the constructor arguments. // FIXME: Handle 'self' along with the other body patterns. SmallVector<SILValue, 8> args; bindParametersForForwarding(ctor->getParameterList(1), args); SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor); // Allocate the "self" value. VarDecl *selfDecl = ctor->getImplicitSelfDecl(); SILType selfTy = getLoweredType(selfDecl->getType()); assert(selfTy.hasReferenceSemantics() && "can't emit a value type ctor here"); // Use alloc_ref to allocate the object. // TODO: allow custom allocation? // FIXME: should have a cleanup in case of exception auto selfClassDecl = ctor->getDeclContext()->getAsClassOrClassExtensionContext(); SILValue selfValue; // Allocate the 'self' value. bool useObjCAllocation = usesObjCAllocator(selfClassDecl); if (ctor->isConvenienceInit() || ctor->hasClangNode()) { // For a convenience initializer or an initializer synthesized // for an Objective-C class, allocate using the metatype. SILValue allocArg = selfMetaValue; // When using Objective-C allocation, convert the metatype // argument to an Objective-C metatype. if (useObjCAllocation) { auto metaTy = allocArg->getType().castTo<MetatypeType>(); metaTy = CanMetatypeType::get(metaTy.getInstanceType(), MetatypeRepresentation::ObjC); allocArg = B.createThickToObjCMetatype(Loc, allocArg, getLoweredType(metaTy)); } selfValue = B.createAllocRefDynamic(Loc, allocArg, selfTy, useObjCAllocation, {}, {}); } else { // For a designated initializer, we know that the static type being // allocated is the type of the class that defines the designated // initializer. selfValue = B.createAllocRef(Loc, selfTy, useObjCAllocation, false, {}, {}); } args.push_back(selfValue); // Call the initializer. Always use the Swift entry point, which will be a // bridging thunk if we're calling ObjC. SILDeclRef initConstant = SILDeclRef(ctor, SILDeclRef::Kind::Initializer, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isObjC=*/false); ManagedValue initVal; SILType initTy; ArrayRef<Substitution> subs; // Call the initializer. ArrayRef<Substitution> forwardingSubs; if (auto *genericEnv = ctor->getGenericEnvironmentOfContext()) { auto *genericSig = ctor->getGenericSignatureOfContext(); forwardingSubs = genericEnv->getForwardingSubstitutions( SGM.SwiftModule, genericSig); } std::tie(initVal, initTy, subs) = emitSiblingMethodRef(Loc, selfValue, initConstant, forwardingSubs); SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this), initTy, subs, args); // Return the initialized 'self'. B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), initedSelfValue); }
void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) { CanType enumTy = element->getParentEnum() ->getDeclaredTypeInContext() ->getCanonicalType(); auto &enumTI = getTypeLowering(enumTy); RegularLocation Loc(element); CleanupLocation CleanupLoc(element); Loc.markAutoGenerated(); // Emit the indirect return slot. std::unique_ptr<Initialization> dest; if (enumTI.isAddressOnly()) { auto &AC = getASTContext(); auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), CanInOutType::get(enumTy), element->getDeclContext()); auto resultSlot = new (SGM.M) SILArgument(F.begin(), enumTI.getLoweredType(), VD); dest = std::unique_ptr<Initialization>( new KnownAddressInitialization(resultSlot)); } Scope scope(Cleanups, CleanupLoc); // Emit the exploded constructor argument. ArgumentSource payload; if (element->hasArgumentType()) { RValue arg = emitImplicitValueConstructorArg (*this, Loc, element->getArgumentType()->getCanonicalType(), element->getDeclContext()); payload = ArgumentSource(Loc, std::move(arg)); } // Emit the metatype argument. emitConstructorMetatypeArg(*this, element); // If possible, emit the enum directly into the indirect return. SGFContext C = (dest ? SGFContext(dest.get()) : SGFContext()); ManagedValue mv = emitInjectEnum(Loc, std::move(payload), enumTI.getLoweredType(), element, C); // Return the enum. auto ReturnLoc = ImplicitReturnLocation::getImplicitReturnLoc(Loc); if (mv.isInContext()) { assert(enumTI.isAddressOnly()); scope.pop(); B.createReturn(ReturnLoc, emitEmptyTuple(Loc)); } else { assert(enumTI.isLoadable()); SILValue result = mv.forward(*this); scope.pop(); B.createReturn(ReturnLoc, result); } }
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."); }
void StmtEmitter::visitForEachStmt(ForEachStmt *S) { // Emit the 'iterator' variable that we'll be using for iteration. LexicalScope OuterForScope(SGF.Cleanups, SGF, CleanupLocation(S)); SGF.visitPatternBindingDecl(S->getIterator()); // If we ever reach an unreachable point, stop emitting statements. // This will need revision if we ever add goto. if (!SGF.B.hasValidInsertionPoint()) return; // If generator's optional result is address-only, create a stack allocation // to hold the results. This will be initialized on every entry into the loop // header and consumed by the loop body. On loop exit, the terminating value // will be in the buffer. auto optTy = S->getIteratorNext()->getType()->getCanonicalType(); auto &optTL = SGF.getTypeLowering(optTy); SILValue nextBufOrValue; if (optTL.isAddressOnly()) nextBufOrValue = SGF.emitTemporaryAllocation(S, optTL.getLoweredType()); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Set the destinations for 'break' and 'continue'. JumpDest endDest = createJumpDest(S->getBody()); SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest }); // Advance the generator. Use a scope to ensure that any temporary stack // allocations in the subexpression are immediately released. if (optTL.isAddressOnly()) { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); auto nextInit = SGF.useBufferAsTemporary(nextBufOrValue, optTL); SGF.emitExprInto(S->getIteratorNext(), nextInit.get()); nextInit->getManagedAddress().forward(SGF); } else { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); nextBufOrValue = SGF.emitRValueAsSingleValue(S->getIteratorNext()).forward(SGF); } // Continue if the value is present. Condition Cond = SGF.emitCondition( SGF.emitDoesOptionalHaveValue(S, nextBufOrValue), S, /*hasFalseCode=*/false, /*invertValue=*/false); if (Cond.hasTrue()) { Cond.enterTrue(SGF); SGF.emitProfilerIncrement(S->getBody()); // Emit the loop body. // The declared variable(s) for the current element are destroyed // at the end of each loop iteration. { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getBody())); // Emit the initialization for the pattern. If any of the bound patterns // fail (because this is a 'for case' pattern with a refutable pattern, // the code should jump to the continue block. InitializationPtr initLoopVars = SGF.emitPatternBindingInitialization(S->getPattern(), loopDest); ManagedValue val; // If we had a loadable "next" generator value, we know it is present. // Get the value out of the optional, and wrap it up with a cleanup so // that any exits out of this scope properly clean it up. if (optTL.isLoadable()) { val = SGF.emitManagedRValueWithCleanup(nextBufOrValue); } else { val = SGF.emitManagedBufferWithCleanup(nextBufOrValue); } val = SGF.emitUncheckedGetOptionalValueFrom(S, val, optTL, SGFContext(initLoopVars.get())); if (!val.isInContext()) RValue(SGF, S, optTy.getAnyOptionalObjectType(), val) .forwardInto(SGF, S, initLoopVars.get()); // Now that the pattern has been initialized, check any where condition. // If it fails, loop around as if 'continue' happened. if (auto *Where = S->getWhere()) { auto cond = SGF.emitCondition(Where, /*hasFalse*/false, /*invert*/true); // If self is null, branch to the epilog. cond.enterTrue(SGF); SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, { }); cond.exitTrue(SGF); cond.complete(SGF); } visit(S->getBody()); } // Loop back to the header. if (SGF.B.hasValidInsertionPoint()) { // Associate the loop body's closing brace with this branch. RegularLocation L(S->getBody()); L.pointToEnd(); SGF.B.createBranch(L, loopDest.getBlock()); } Cond.exitTrue(SGF); } // Complete the conditional execution. Cond.complete(SGF); emitOrDeleteBlock(SGF, endDest, S); SGF.BreakContinueDestStack.pop_back(); // We do not need to destroy the value in the 'nextBuf' slot here, because // either the 'for' loop finished naturally and the buffer contains '.None', // or we exited by 'break' and the value in the buffer was consumed. }
ManagedValue SILGenBuilder::createProjectBox(SILLocation loc, ManagedValue mv, unsigned index) { auto *pbi = SILBuilder::createProjectBox(loc, mv.getValue(), index); return ManagedValue::forUnmanaged(pbi); }
/// Emit an optional-to-optional transformation. ManagedValue SILGenFunction::emitOptionalToOptional(SILLocation loc, ManagedValue input, SILType resultTy, ValueTransformRef 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 = contBB->createPHIArgument(resultTL.getLoweredType(), ValueOwnershipKind::Owned); // 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(*this, loc, resultValueTy, resultValue)); 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); }
void SILGenBuilder::createStoreBorrow(SILLocation loc, ManagedValue value, SILValue address) { assert(value.getOwnershipKind() == ValueOwnershipKind::Guaranteed); createStoreBorrow(loc, value.getValue(), address); }
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; ManagedValue archetypeMV; SILType existentialType = existentialValue.getType(); switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) { case ExistentialRepresentation::Opaque: { if (existentialType.isAddress()) { SILValue 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); archetypeMV = emitManagedBufferWithCleanup(archetypeValue); } else { canConsume = false; archetypeMV = ManagedValue::forUnmanaged(archetypeValue); } } else { SILValue archetypeValue = B.createOpenExistentialOpaque( loc, existentialValue.forward(*this), loweredOpenedType); assert(!existentialValue.hasCleanup()); canConsume = false; archetypeMV = ManagedValue::forUnmanaged(archetypeValue); } break; } case ExistentialRepresentation::Metatype: assert(existentialType.isObject()); archetypeMV = ManagedValue::forUnmanaged( 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()); SILValue archetypeValue = B.createOpenExistentialRef( loc, existentialValue.forward(*this), loweredOpenedType); canConsume = existentialValue.hasCleanup(); archetypeMV = (canConsume ? emitManagedRValueWithCleanup(archetypeValue) : ManagedValue::forUnmanaged(archetypeValue)); 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. archetypeMV = ManagedValue::forUnmanaged( 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, archetypeMV.getValue()); assert(!canConsume || isUnique); (void) isUnique; return SILGenFunction::OpaqueValueState{ archetypeMV, /*isConsumable*/ canConsume, /*hasBeenConsumed*/ false }; }
ManagedValue SILGenBuilder::createUncheckedAddrCast(SILLocation loc, ManagedValue op, SILType resultTy) { CleanupCloner cloner(*this, op); SILValue cast = createUncheckedAddrCast(loc, op.forward(SGF), resultTy); return cloner.clone(cast); }