//===--- SILGenApply.cpp - Constructs call sites for SILGen ---------------===// // // 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 "LValue.h" #include "RValue.h" #include "Scope.h" #include "Initialization.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Builtins.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/Module.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/Range.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/PrettyStackTrace.h" using namespace swift; using namespace Lowering; /// Retrieve the type to use for a method found via dynamic lookup. static CanAnyFunctionType getDynamicMethodFormalType(SILGenModule &SGM, SILValue proto, ValueDecl *member, SILDeclRef methodName, Type memberType) { auto &ctx = SGM.getASTContext(); CanType selfTy; if (member->isInstanceMember()) { selfTy = ctx.TheUnknownObjectType; } else { selfTy = proto.getType().getSwiftType(); } auto extInfo = FunctionType::ExtInfo() .withCallingConv(SGM.getConstantCC(methodName)) .withRepresentation(FunctionType::Representation::Thin); return CanFunctionType::get(selfTy, memberType->getCanonicalType(), extInfo); } /// Replace the 'self' parameter in the given type. static CanSILFunctionType replaceSelfTypeForDynamicLookup(ASTContext &ctx, CanSILFunctionType fnType, CanType newSelfType, SILDeclRef methodName) { auto oldParams = fnType->getInterfaceParameters(); SmallVector newParams; newParams.append(oldParams.begin(), oldParams.end() - 1); newParams.push_back({newSelfType, oldParams.back().getConvention()}); auto newResult = fnType->getInterfaceResult(); // If the method returns Self, substitute AnyObject for the result type. if (auto fnDecl = dyn_cast(methodName.getDecl())) { if (fnDecl->hasDynamicSelf()) { auto anyObjectTy = ctx.getProtocol(KnownProtocolKind::AnyObject) ->getDeclaredType(); auto newResultTy = newResult.getType()->replaceCovariantResultType(anyObjectTy, 0); newResult = SILResultInfo(newResultTy->getCanonicalType(), newResult.getConvention()); } } return SILFunctionType::get(nullptr, fnType->getExtInfo(), fnType->getCalleeConvention(), newParams, newResult, ctx); } /// Retrieve the type to use for a method found via dynamic lookup. static CanSILFunctionType getDynamicMethodLoweredType(SILGenModule &SGM, SILValue proto, SILDeclRef methodName) { auto &ctx = SGM.getASTContext(); // Determine the opaque 'self' parameter type. CanType selfTy; if (methodName.getDecl()->isInstanceMember()) { selfTy = ctx.TheUnknownObjectType; } else { selfTy = proto.getType().getSwiftType(); } // Replace the 'self' parameter type in the method type with it. auto methodTy = SGM.getConstantType(methodName).castTo(); return replaceSelfTypeForDynamicLookup(ctx, methodTy, selfTy, methodName); } namespace { /// Abstractly represents a callee, and knows how to emit the entry point /// reference for a callee at any valid uncurry level. class Callee { public: enum class Kind { /// An indirect function value. IndirectValue, /// A direct standalone function call, referenceable by a FunctionRefInst. StandaloneFunction, VirtualMethod_First, /// A method call using class method dispatch. ClassMethod = VirtualMethod_First, /// A method call using super method dispatch. SuperMethod, VirtualMethod_Last = SuperMethod, GenericMethod_First, /// A method call using archetype dispatch. WitnessMethod = GenericMethod_First, /// A method call using protocol dispatch. ProtocolMethod, /// A method call using dynamic lookup. DynamicMethod, GenericMethod_Last = DynamicMethod }; const Kind kind; using SpecializedEmitter = ManagedValue (*)(SILGenFunction &, SILLocation, ArrayRef, ArrayRef, SGFContext); // Move, don't copy. Callee(const Callee &) = delete; Callee &operator=(const Callee &) = delete; private: union { ManagedValue indirectValue; SILDeclRef standaloneFunction; struct { SILValue selfValue; SILDeclRef methodName; } method; }; ArrayRef substitutions; CanType OrigFormalOldType, OrigFormalInterfaceType; CanAnyFunctionType SubstFormalType; Optional specializeLoc; bool isTransparent; bool HasSubstitutions = false; // The pointer back to the AST node that produced the callee. SILLocation Loc; static SpecializedEmitter getSpecializedEmitterForSILBuiltin(SILDeclRef c, SILModule &M); Callee(ManagedValue indirectValue, CanType origFormalType, CanAnyFunctionType substFormalType, bool isTransparent, SILLocation L) : kind(Kind::IndirectValue), indirectValue(indirectValue), OrigFormalOldType(origFormalType), OrigFormalInterfaceType(origFormalType), SubstFormalType(substFormalType), isTransparent(isTransparent), Loc(L) {} static CanAnyFunctionType getConstantFormalType(SILGenFunction &gen, SILValue selfValue, SILDeclRef fn) SIL_FUNCTION_TYPE_DEPRECATED { return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0)).FormalType; } static CanAnyFunctionType getConstantFormalInterfaceType(SILGenFunction &gen, SILValue selfValue, SILDeclRef fn) { return gen.SGM.Types.getConstantInfo(fn.atUncurryLevel(0)) .FormalInterfaceType; } Callee(SILGenFunction &gen, SILDeclRef standaloneFunction, CanAnyFunctionType substFormalType, SILLocation l) : kind(Kind::StandaloneFunction), standaloneFunction(standaloneFunction), OrigFormalOldType(getConstantFormalType(gen, SILValue(), standaloneFunction)), OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, SILValue(), standaloneFunction)), SubstFormalType(substFormalType), isTransparent(standaloneFunction.isTransparent()), Loc(l) { } Callee(Kind methodKind, SILGenFunction &gen, SILValue selfValue, SILDeclRef methodName, CanAnyFunctionType substFormalType, SILLocation l) : kind(methodKind), method{selfValue, methodName}, OrigFormalOldType(getConstantFormalType(gen, selfValue, methodName)), OrigFormalInterfaceType(getConstantFormalInterfaceType(gen, selfValue, methodName)), SubstFormalType(substFormalType), isTransparent(false), Loc(l) { } static CanArchetypeType getArchetypeForSelf(CanType selfType) { if (auto mt = dyn_cast(selfType)) { return cast(mt.getInstanceType()); } else { return cast(selfType); } } /// Build a clause that looks like 'origParamType' but uses 'selfType' /// in place of the underlying archetype. static CanType buildSubstSelfType(CanType origParamType, CanType selfType, ASTContext &ctx) { assert(!isa(origParamType) && "Self can't be @lvalue"); if (auto lv = dyn_cast(origParamType)) { selfType = buildSubstSelfType(lv.getObjectType(), selfType, ctx); return CanInOutType::get(selfType); } if (auto tuple = dyn_cast(origParamType)) { assert(tuple->getNumElements() == 1); selfType = buildSubstSelfType(tuple.getElementType(0), selfType, ctx); auto field = tuple->getFields()[0].getWithType(selfType); return CanType(TupleType::get(field, ctx)); } // These first two asserts will crash before they return if // they're actually wrong. assert(getArchetypeForSelf(origParamType)); assert(getArchetypeForSelf(selfType)); assert(isa(origParamType) == isa(selfType)); return selfType; } CanSILFunctionType getSubstFunctionType(SILGenModule &SGM, CanSILFunctionType origFnType, CanAnyFunctionType origLoweredType, unsigned uncurryLevel) const { if (!HasSubstitutions) return origFnType; assert(origLoweredType); auto substLoweredType = SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel, origLoweredType->getExtInfo()); auto substLoweredInterfaceType = SGM.Types.getLoweredASTFunctionType(SubstFormalType, uncurryLevel, origLoweredType->getExtInfo()); return SGM.Types.substFunctionType(origFnType, origLoweredType, substLoweredType, substLoweredInterfaceType); } /// Return the value being passed as 'self' for this protocol callee. CanType getProtocolSelfType(SILGenModule &SGM) const { if (kind == Kind::ProtocolMethod) { auto member = method.methodName.getDecl(); auto proto = cast(member->getDeclContext()); auto type = proto->getSelf()->getArchetype()->getCanonicalType(); if (!member->isInstanceMember()) type = CanMetatypeType::get(type); return type; } else if (kind == Kind::WitnessMethod) { return method.selfValue.getType().getSwiftRValueType(); } else { llvm_unreachable("bad callee kind for protocol method"); } } /// Add the 'self' clause back to the substituted formal type of /// this protocol method. void addProtocolSelfToFormalType(SILGenModule &SGM, SILDeclRef name) { // The result types of the expressions yielding protocol values // (reflected in SubstFormalType) reflect an implicit level of // function application, including some extra polymorphic // substitution. HasSubstitutions = true; auto &ctx = SGM.getASTContext(); // Add the 'self' parameter back. We want it to look like a // substitution of the appropriate clause from the original type. auto polyFormalType = cast(OrigFormalOldType); auto selfType = getProtocolSelfType(SGM); auto substSelfType = buildSubstSelfType(polyFormalType.getInput(), selfType, ctx); // Existential witnesses are always "thick" with the polymorphic info, // unless @objc. auto rep = name.isForeign ? FunctionType::Representation::Thin : FunctionType::Representation::Thick; auto extInfo = FunctionType::ExtInfo(AbstractCC::Method, rep, /*noreturn*/ false); SubstFormalType = CanFunctionType::get(substSelfType, SubstFormalType, extInfo); } SILType getProtocolClosureType(SILGenModule &SGM, SILDeclRef constant, SILConstantInfo &constantInfo, CanArchetypeType &archetype) const { auto &C = SGM.getASTContext(); CanType selfType = getProtocolSelfType(SGM); // Find the archetype. archetype = getArchetypeForSelf(selfType); // addProtocolSelfToFormalType initializes SubstFormalType->isThin() // appropriately for the archetype kind. FunctionType::Representation rep = SubstFormalType->getRepresentation(); // We may need to make the OrigLoweredType thick so that // computing the substFnType below preserves this information. if (rep != FunctionType::Representation::Thin) { constantInfo.LoweredType = adjustFunctionType(constantInfo.LoweredType, rep); constantInfo.LoweredInterfaceType = adjustFunctionType(constantInfo.LoweredInterfaceType, rep); } // The expected result of witness_method is a partial application // of the archetype method to the expected archetype. CanAnyFunctionType partialSubstFormalType = cast( cast(OrigFormalOldType) ->substGenericArgs(SGM.SwiftModule, archetype) ->getCanonicalType()); // If the requirement is generic, sever its connection to the substituted // outer parameter list. if (auto polyMethod = dyn_cast( partialSubstFormalType.getResult())) { auto origParams = &polyMethod->getGenericParams(); auto emptyOuterParams = GenericParamList::getEmpty(C); auto params = origParams->cloneWithOuterParameters(C, emptyOuterParams); polyMethod = CanPolymorphicFunctionType::get(polyMethod.getInput(), polyMethod.getResult(), params, polyMethod->getExtInfo()); partialSubstFormalType = CanFunctionType::get(partialSubstFormalType.getInput(), polyMethod); } // Same thing for the interface type. auto partialSubstInterfaceType = cast( cast(OrigFormalInterfaceType) ->partialSubstGenericArgs(SGM.SwiftModule, archetype) ->getCanonicalType()); auto partialSubstUncurriedType = SGM.Types.getConstantFunctionType(constant, partialSubstFormalType, partialSubstInterfaceType, rep); return SILType::getPrimitiveObjectType(partialSubstUncurriedType); } /// Add the 'self' type to the substituted function type of this /// dynamic callee. void addDynamicCalleeSelfToFormalType(SILGenModule &SGM) { assert(kind == Kind::DynamicMethod); // Drop the original self clause. CanType methodType = OrigFormalOldType; methodType = cast(methodType).getResult(); // Replace it with the dynamic self type. OrigFormalOldType = OrigFormalInterfaceType = getDynamicMethodFormalType(SGM, method.selfValue, method.methodName.getDecl(), method.methodName, methodType); // Add a self clause to the substituted type. auto origFormalType = cast(OrigFormalOldType); auto selfType = origFormalType.getInput(); SubstFormalType = CanFunctionType::get(selfType, SubstFormalType, origFormalType->getExtInfo()); } public: static Callee forIndirect(ManagedValue indirectValue, CanType origFormalType, CanAnyFunctionType substFormalType, bool isTransparent, SILLocation l) { return Callee(indirectValue, origFormalType, substFormalType, isTransparent, l); } static Callee forDirect(SILGenFunction &gen, SILDeclRef c, CanAnyFunctionType substFormalType, SILLocation l) { return Callee(gen, c, substFormalType, l); } static Callee forClassMethod(SILGenFunction &gen, SILValue selfValue, SILDeclRef name, CanAnyFunctionType substFormalType, SILLocation l) { return Callee(Kind::ClassMethod, gen, selfValue, name, substFormalType, l); } static Callee forSuperMethod(SILGenFunction &gen, SILValue selfValue, SILDeclRef name, CanAnyFunctionType substFormalType, SILLocation l) { return Callee(Kind::SuperMethod, gen, selfValue, name, substFormalType, l); } static Callee forArchetype(SILGenFunction &gen, SILValue value, SILDeclRef name, CanAnyFunctionType substFormalType, SILLocation l) { Callee callee(Kind::WitnessMethod, gen, value, name, substFormalType, l); callee.addProtocolSelfToFormalType(gen.SGM, name); return callee; } static Callee forProtocol(SILGenFunction &gen, SILValue proto, SILDeclRef name, CanAnyFunctionType substFormalType, SILLocation l) { Callee callee(Kind::ProtocolMethod, gen, proto, name, substFormalType, l); callee.addProtocolSelfToFormalType(gen.SGM, name); return callee; } static Callee forDynamic(SILGenFunction &gen, SILValue proto, SILDeclRef name, CanAnyFunctionType substFormalType, SILLocation l) { Callee callee(Kind::DynamicMethod, gen, proto, name, substFormalType, l); callee.addDynamicCalleeSelfToFormalType(gen.SGM); return callee; } Callee(Callee &&) = default; Callee &operator=(Callee &&) = default; void setSubstitutions(SILGenFunction &gen, SILLocation loc, ArrayRef newSubs, unsigned callDepth) { // Currently generic methods of generic types are the deepest we should // be able to stack specializations. // FIXME: Generic local functions can add type parameters to arbitrary // depth. assert(callDepth < 2 && "specialization below 'self' or argument depth?!"); assert(substitutions.empty() && "Already have substitutions?"); substitutions = newSubs; assert(getNaturalUncurryLevel() >= callDepth && "specializations below uncurry level?!"); specializeLoc = loc; HasSubstitutions = true; } CanType getOrigFormalType() const { return OrigFormalOldType; } CanAnyFunctionType getSubstFormalType() const { return SubstFormalType; } unsigned getNaturalUncurryLevel() const { switch (kind) { case Kind::IndirectValue: return 0; case Kind::StandaloneFunction: return standaloneFunction.uncurryLevel; case Kind::ClassMethod: case Kind::SuperMethod: case Kind::WitnessMethod: case Kind::ProtocolMethod: case Kind::DynamicMethod: return method.methodName.uncurryLevel; } } std::tuple getAtUncurryLevel(SILGenFunction &gen, unsigned level) const { ManagedValue mv; bool transparent = isTransparent; SILConstantInfo constantInfo = {}; switch (kind) { case Kind::IndirectValue: assert(level == 0 && "can't curry indirect function"); mv = indirectValue; assert(!HasSubstitutions); break; case Kind::StandaloneFunction: { assert(level <= standaloneFunction.uncurryLevel && "uncurrying past natural uncurry level of standalone function"); if (level < standaloneFunction.uncurryLevel) transparent = false; auto constant = standaloneFunction.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); SILValue ref = gen.emitGlobalFunctionRef(Loc, constant, constantInfo); mv = ManagedValue::forUnmanaged(ref); break; } case Kind::ClassMethod: { assert(level <= method.methodName.uncurryLevel && "uncurrying past natural uncurry level of method"); auto constant = method.methodName.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); // If the call is curried, emit a direct call to the curry thunk. if (level < method.methodName.uncurryLevel) { SILValue ref = gen.emitGlobalFunctionRef(Loc, constant, constantInfo); mv = ManagedValue::forUnmanaged(ref); transparent = false; break; } // Otherwise, do the dynamic dispatch inline. SILValue methodVal = gen.B.createClassMethod(Loc, method.selfValue, constant, constantInfo.getSILType(), /*volatile*/ constant.isForeign); mv = ManagedValue::forUnmanaged(methodVal); break; } case Kind::SuperMethod: { assert(level <= method.methodName.uncurryLevel && "uncurrying past natural uncurry level of method"); assert(level >= 1 && "currying 'self' of super method dispatch not yet supported"); auto constant = method.methodName.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); SILValue methodVal = gen.B.createSuperMethod(Loc, method.selfValue, constant, constantInfo.getSILType(), /*volatile*/ constant.isForeign); mv = ManagedValue::forUnmanaged(methodVal); break; } case Kind::WitnessMethod: { assert(level >= 1 && "currying 'self' of generic method dispatch not yet supported"); assert(level <= method.methodName.uncurryLevel && "uncurrying past natural uncurry level of method"); auto constant = method.methodName.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); // Look up the witness for the archetype. auto selfType = getProtocolSelfType(gen.SGM); auto archetype = getArchetypeForSelf(selfType); SILValue fn = gen.B.createWitnessMethod(Loc, SILType::getPrimitiveObjectType(archetype), /*conformance*/ nullptr, constant, constantInfo.getSILType(), constant.isForeign); mv = ManagedValue::forUnmanaged(fn); break; } case Kind::ProtocolMethod: { assert(level >= 1 && "currying 'self' of generic method dispatch not yet supported"); assert(level <= method.methodName.uncurryLevel && "uncurrying past natural uncurry level of method"); auto constant = method.methodName.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); CanArchetypeType archetype; // not used SILType closureType = getProtocolClosureType(gen.SGM, constant, constantInfo, archetype); SILValue fn = gen.B.createProtocolMethod(Loc, method.selfValue, constant, closureType, /*volatile*/ constant.isForeign); mv = ManagedValue::forUnmanaged(fn); break; } case Kind::DynamicMethod: { assert(level >= 1 && "currying 'self' of dynamic method dispatch not yet supported"); assert(level <= method.methodName.uncurryLevel && "uncurrying past natural uncurry level of method"); auto constant = method.methodName.atUncurryLevel(level); constantInfo = gen.getConstantInfo(constant); auto closureType = replaceSelfTypeForDynamicLookup(gen.getASTContext(), constantInfo.SILFnType, method.selfValue.getType().getSwiftRValueType(), method.methodName); SILValue fn = gen.B.createDynamicMethod(Loc, method.selfValue, constant, SILType::getPrimitiveObjectType(closureType), /*volatile*/ constant.isForeign); mv = ManagedValue::forUnmanaged(fn); break; } } CanSILFunctionType substFnType = getSubstFunctionType(gen.SGM, mv.getType().castTo(), constantInfo.LoweredType, level); return std::make_tuple(mv, substFnType, transparent); } ArrayRef getSubstitutions() const { return substitutions; } /// Return a specialized emission function if this is a function with a known /// lowering, such as a builtin, or return null if there is no specialized /// emitter. Optional getSpecializedEmitter(SILGenModule &SGM, unsigned uncurryLevel) const { // Currently we have no curried known functions. if (uncurryLevel != 0) return Nothing; switch (kind) { case Kind::StandaloneFunction: { if (SpecializedEmitter e = getSpecializedEmitterForSILBuiltin(standaloneFunction, SGM.M)) { return e; } SWIFT_FALLTHROUGH; } case Kind::IndirectValue: case Kind::ClassMethod: case Kind::SuperMethod: case Kind::WitnessMethod: case Kind::ProtocolMethod: case Kind::DynamicMethod: return Nothing; } llvm_unreachable("bad callee kind"); } }; /// Get the 'Self' type of a AnyObject operand to use as the result type of /// projecting the object instance handle. SILType getSelfTypeForDynamicLookup(SILGenFunction &gen, SILValue existential) { CanType ty = existential.getType().getSwiftRValueType(); ProtocolDecl *proto = cast(ty)->getDecl(); // AnyObject is a class protocol so its projection should be loadable. return gen.getLoweredLoadableType(proto->getSelf()->getArchetype()); } /// An ASTVisitor for building SIL function calls. /// Nested ApplyExprs applied to an underlying curried function or method /// reference are flattened into a single SIL apply to the most uncurried entry /// point fitting the call site, avoiding pointless intermediate closure /// construction. class SILGenApply : public Lowering::ExprVisitor { public: SILGenFunction &gen; Optional callee; RValue selfParam; Expr *SelfApplyExpr = nullptr; std::vector callSites; Expr *sideEffect = nullptr; unsigned callDepth = 0; SILGenApply(SILGenFunction &gen) : gen(gen) {} void setCallee(Callee &&c) { assert((selfParam ? callDepth == 1 : callDepth == 0) && "setting callee at non-zero call depth?!"); assert(!callee && "already set callee!"); callee.emplace(std::move(c)); } void setSideEffect(Expr *sideEffectExpr) { assert(!sideEffect && "already set side effect!"); sideEffect = sideEffectExpr; } void setSelfParam(RValue &&theSelfParam, Expr *theSelfApplyExpr) { assert(!selfParam && "already set this!"); selfParam = std::move(theSelfParam); SelfApplyExpr = theSelfApplyExpr; ++callDepth; } void decompose(Expr *e) { visit(e); } /// Get the type of the function for substitution purposes. /// /// \param otherCtorRefUsesAllocating If true, the OtherConstructorDeclRef /// refers to the initializing CanFunctionType getSubstFnType(bool otherCtorRefUsesAllocating = false) { // TODO: optimize this if there are no specializes in play auto getSiteType = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) { if (otherCtorRefUsesAllocating) { // We have a reference to an initializing constructor, but we will // actually be using the allocating constructor. Update the type // appropriately. // FIXME: Re-derive the type from the declaration + substitutions? auto ctorRef = cast( site->getFn()->getSemanticsProvidingExpr()); auto fnType = ctorRef->getType()->castTo(); auto selfTy = MetatypeType::get( fnType->getInput()->getInOutObjectType()); return CanFunctionType::get(selfTy->getCanonicalType(), fnType->getResult()->getCanonicalType(), fnType->getExtInfo()); } return cast(site->getFn()->getType()->getCanonicalType()); }; CanFunctionType fnType; auto addSite = [&](ApplyExpr *site, bool otherCtorRefUsesAllocating) { auto siteType = getSiteType(site, otherCtorRefUsesAllocating); // If this is the first call site, use its formal type directly. if (!fnType) { fnType = siteType; return; } fnType = CanFunctionType::get(siteType.getInput(), fnType, siteType->getExtInfo()); }; for (auto callSite : callSites) { addSite(callSite, false); } if (auto selfApply = dyn_cast_or_null(SelfApplyExpr)) { addSite(selfApply, otherCtorRefUsesAllocating); } assert(fnType && "found no call sites?"); return fnType; } /// Fall back to an unknown, indirect callee. void visitExpr(Expr *e) { // This marks all calls to auto closure typed variables as transparent. // As of writing, local variable auto closures are currently allowed by // the parser, but the plan is that they will be disallowed, so this will // actually only apply to auto closure parameters, which is what we want auto *t = e->getType()->castTo(); bool isTransparent = t->getExtInfo().isAutoClosure(); ManagedValue fn = gen.emitRValueAsSingleValue(e); auto origType = cast(e->getType()->getCanonicalType()); setCallee(Callee::forIndirect(fn, origType, getSubstFnType(), isTransparent, e)); } void visitLoadExpr(LoadExpr *e) { bool isTransparent = false; if (DeclRefExpr *d = dyn_cast(e->getSubExpr())) { // This marks all calls to auto closure typed variables as transparent. // As of writing, local variable auto closures are currently allowed by // the parser, but the plan is that they will be disallowed, so this will // actually only apply to auto closure parameters, which is what we want Type Ty = d->getDecl()->getType()->getInOutObjectType(); // If the decl type is a function type, figure out if it is an auto // closure. if (auto *AnyF = Ty->getAs()) { isTransparent = AnyF->getExtInfo().isAutoClosure(); } } // TODO: preserve the function pointer at its original abstraction level ManagedValue fn = gen.emitRValueAsSingleValue(e); auto origType = cast(e->getType()->getCanonicalType()); setCallee(Callee::forIndirect(fn, origType, getSubstFnType(), isTransparent, e)); } /// Add a call site to the curry. void visitApplyExpr(ApplyExpr *e) { if (e->isSuper()) { applySuper(e); } else if (applyInitDelegation(e)) { // Already done } else { callSites.push_back(e); visit(e->getFn()); } ++callDepth; } /// Given a metatype value for the type, allocate an Objective-C /// object (with alloc_ref_dynamic) of that type. /// /// \returns the self object. ManagedValue allocateObjCObject(ManagedValue selfMeta, SILLocation loc) { auto metaType = selfMeta.getType().castTo(); CanType type = metaType.getInstanceType(); // Convert to an Objective-C metatype representation, if needed. ManagedValue selfMetaObjC; if (metaType->getRepresentation() == MetatypeRepresentation::ObjC) { selfMetaObjC = selfMeta; } else { CanAnyMetatypeType objcMetaType; if (isa(metaType)) { objcMetaType = CanMetatypeType::get(type, MetatypeRepresentation::ObjC); } else { objcMetaType = CanExistentialMetatypeType::get(type, MetatypeRepresentation::ObjC); } selfMetaObjC = ManagedValue( gen.B.emitThickToObjCMetatype( loc, selfMeta.getValue(), gen.SGM.getLoweredType(objcMetaType)), selfMeta.getCleanup()); } // Allocate the object. return ManagedValue(gen.B.createAllocRefDynamic( loc, selfMetaObjC.getValue(), gen.SGM.getLoweredType(type), /*objc=*/true), selfMetaObjC.getCleanup()); } // // Known callees. // void visitDeclRefExpr(DeclRefExpr *e) { // If we need to perform dynamic dispatch for the given function, // emit class_method to do so. if (auto afd = dyn_cast(e->getDecl())) { Optional kind; bool isDynamicallyDispatched = false; bool requiresAllocRefDynamic = false; if (auto fd = dyn_cast(afd)) { // If this declaration is in a class but not marked @final, then it is // always dynamically dispatched. if ((isa(fd->getDeclContext()) || fd->isObjC()) && !fd->isFinal()) { isDynamicallyDispatched = true; kind = SILDeclRef::Kind::Func; } } // Abstract constructors are dynamically dispatched when the 'self' value // is not statically derived. else if (auto ctor = dyn_cast(afd)) { ApplyExpr *thisCallSite = callSites.back(); if (ctor->isRequired() && thisCallSite->getArg()->getType()->is() && !thisCallSite->getArg()->isStaticallyDerivedMetatype()) { isDynamicallyDispatched = true; if (gen.SGM.requiresObjCDispatch(afd)) { // When we're performing Objective-C dispatch, we don't have an // allocating constructor to call. So, perform an alloc_ref_dynamic // and pass that along to the initializer. requiresAllocRefDynamic = true; kind = SILDeclRef::Kind::Initializer; } else { kind = SILDeclRef::Kind::Allocator; } } } if (isDynamicallyDispatched) { ApplyExpr *thisCallSite = callSites.back(); callSites.pop_back(); RValue self = gen.emitRValue(thisCallSite->getArg()); // If we require a dynamic allocation of the object here, do so now. if (requiresAllocRefDynamic) { SILLocation loc = thisCallSite->getArg(); auto selfValue = allocateObjCObject( std::move(self).getAsSingleValue(gen, loc), loc); self = RValue(gen, loc, selfValue.getType().getSwiftRValueType(), selfValue); } setSelfParam(std::move(self), thisCallSite); SILDeclRef constant(afd, kind.getValue(), SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, gen.SGM.requiresObjCDispatch(afd)); setCallee(Callee::forClassMethod(gen, selfParam.peekScalarValue(), constant, getSubstFnType(), e)); // setSelfParam bumps the callDepth, but we aren't really past the // 'self' call depth in this case. --callDepth; // If there are substitutions, add them. if (e->getDeclRef().isSpecialized()) { callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(), callDepth); } return; } } // If this is a direct reference to a vardecl, it must be a let constant // (which doesn't need to be loaded). Just emit its value directly. if (auto *vd = dyn_cast(e->getDecl())) { (void)vd; assert(vd->isLet() && "Direct reference to vardecl that isn't a let?"); visitExpr(e); return; } // FIXME: Store context values for local funcs in a way that we can // apply them directly as an added "call site" here. SILDeclRef constant(e->getDecl(), SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, gen.SGM.requiresObjCDispatch(e->getDecl())); // Obtain a reference for a local closure. if (gen.LocalFunctions.count(constant)) { ManagedValue localFn = gen.emitRValueForDecl(e, e->getDeclRef(), e->getType()); auto type = cast(e->getType()->getCanonicalType()); setCallee(Callee::forIndirect(localFn, type, type, false, e)); // Otherwise, stash the SILDeclRef. } else { setCallee(Callee::forDirect(gen, constant, getSubstFnType(), e)); } // If there are substitutions, add them. if (e->getDeclRef().isSpecialized()) { callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(), callDepth); } } void visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *e) { // FIXME: We might need to go through ObjC dispatch for references to // constructors imported from Clang (which won't have a direct entry point) // or to delegate to a designated initializer. setCallee(Callee::forDirect(gen, SILDeclRef(e->getDecl(), SILDeclRef::Kind::Initializer), getSubstFnType(), e)); // If there are substitutions, add them. if (e->getDeclRef().isSpecialized()) callee->setSubstitutions(gen, e, e->getDeclRef().getSubstitutions(), callDepth); } void visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e) { setSideEffect(e->getLHS()); visit(e->getRHS()); } /// Skip over all of the 'Self'-related substitutions within the given set /// of substitutions. ArrayRef getNonSelfSubstitutions(ArrayRef subs) { unsigned innerIdx = 0, n = subs.size(); for (; innerIdx != n; ++innerIdx) { auto archetype = subs[innerIdx].Archetype; while (archetype->getParent()) archetype = archetype->getParent(); if (!archetype->getSelfProtocol()) { break; } } return subs.slice(innerIdx); } void visitMemberRefExpr(MemberRefExpr *e) { auto *fd = dyn_cast(e->getMember().getDecl()); // If the base is a non-protocol, non-archetype type, then this is a load of // a function pointer out of a vardecl. Just emit it as an rvalue. if (!fd) return visitExpr(e); // We have four cases to deal with here: // // 1) for a "static" / "type" method, the base is a metatype. // 2) for a classbound protocol, the base is a class-bound protocol rvalue, // which is loadable. // 3) for a mutating method, the base has inout type. // 4) for a nonmutating method, the base is a general protocol/archetype // rvalue, which is address-only. The base is passed at +0, so it isn't // consumed. // // In the last case, the AST has this call typed as being applied to an // rvalue, but the witness is actually expecting a pointer to the +0 value // in memory. We access this with the project_existential instruction, or // just pass in the address since archetypes are address-only. auto baseVal = gen.emitRValueAsSingleValue(e->getBase(), SGFContext::AllowPlusZero); auto *proto = cast(fd->getDeclContext()); auto baseTy = e->getBase()->getType()->getLValueOrInOutObjectType(); // Figure out the kind of declaration reference we're working with. SILDeclRef::Kind kind = SILDeclRef::Kind::Func; if (isa(fd)) { if (proto->isObjC()) { // For Objective-C initializers, we only have an initializing // initializer. We need to allocate the object ourselves. kind = SILDeclRef::Kind::Initializer; baseVal = allocateObjCObject(baseVal, e->getBase()); } else { // For non-Objective-C initializers, we have an allocating // initializer to call. kind = SILDeclRef::Kind::Allocator; } } if (!baseTy->isExistentialType()) { setSelfParam(RValue(gen, e->getBase(), baseVal.getType().getSwiftType(), baseVal), e); } else if (fd->isInstanceMember()) { // Attach the existential cleanup to the projection so that it gets // consumed (or not) when the call is applied to it (or isn't). ManagedValue proj; SILType protoSelfTy = gen.getLoweredType(proto->getSelf()->getArchetype()); if (baseVal.getType().isClassExistentialType()) { SILValue val = gen.B.createProjectExistentialRef(e, baseVal.getValue(), protoSelfTy); proj = ManagedValue(val, baseVal.getCleanup()); } else { assert(protoSelfTy.isAddress() && "Self should be address-only"); SILValue val = gen.B.createProjectExistential(e, baseVal.getValue(), protoSelfTy); proj = ManagedValue::forUnmanaged(val); } setSelfParam(RValue(gen, e, protoSelfTy.getSwiftType(), proj), e); } else { assert(baseVal.getType().is() && "non-existential-metatype for existential static method?!"); // FIXME: It is impossible to invoke a class method on a protocol // directly, it must be done through an archetype. setSelfParam(RValue(gen, e, baseVal.getType().getSwiftRValueType(), baseVal), e); } // Method calls through ObjC protocols require ObjC dispatch. bool isObjC = proto->isObjC(); ArrayRef subs = e->getMember().getSubstitutions(); if (!baseTy->getRValueInstanceType()->isExistentialType()) { setCallee(Callee::forArchetype(gen, selfParam.peekScalarValue(), SILDeclRef(fd, kind).asForeign(isObjC), getSubstFnType(), e)); } else { // The declaration is always specialized (due to Self); ignore the // substitutions related to Self. Skip the substitutions involving Self. subs = getNonSelfSubstitutions(subs); setCallee(Callee::forProtocol(gen, baseVal.getValue(), SILDeclRef(fd, kind).asForeign(isObjC), getSubstFnType(), e)); } // If there are substitutions, add them now. if (!subs.empty()) { callee->setSubstitutions(gen, e, subs, callDepth); } } void visitFunctionConversionExpr(FunctionConversionExpr *e) { // FIXME: Check whether this function conversion requires us to build a // thunk. visit(e->getSubExpr()); } void visitCovariantFunctionConversionExpr(CovariantFunctionConversionExpr *e){ // FIXME: These expressions merely adjust the result type for DynamicSelf // in an unchecked, ABI-compatible manner. They shouldn't prevent us form // forming a complete call. visitExpr(e); } void visitIdentityExpr(IdentityExpr *e) { visit(e->getSubExpr()); } void applySuper(ApplyExpr *apply) { // Load the 'super' argument. Expr *arg = apply->getArg(); ManagedValue super = gen.emitRValueAsSingleValue(arg); // The callee for a super call has to be either a method or constructor. Expr *fn = apply->getFn(); ArrayRef substitutions; SILDeclRef constant; if (auto *ctorRef = dyn_cast(fn)) { constant = SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, gen.SGM.requiresObjCSuperDispatch(ctorRef->getDecl())); if (ctorRef->getDeclRef().isSpecialized()) substitutions = ctorRef->getDeclRef().getSubstitutions(); } else if (auto *declRef = dyn_cast(fn)) { assert(isa(declRef->getDecl()) && "non-function super call?!"); constant = SILDeclRef(declRef->getDecl(), SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, gen.SGM.requiresObjCSuperDispatch(declRef->getDecl())); if (declRef->getDeclRef().isSpecialized()) substitutions = declRef->getDeclRef().getSubstitutions(); } else llvm_unreachable("invalid super callee"); CanType superFormalType = arg->getType()->getCanonicalType(); setSelfParam(RValue(gen, apply, superFormalType, super), apply); SILValue superMethod; if (constant.isForeign) { SILValue Input = super.getValue(); while (auto *UI = dyn_cast(Input)) Input = UI->getOperand(); // ObjC super calls require dynamic dispatch. setCallee(Callee::forSuperMethod(gen, Input, constant, getSubstFnType(), fn)); } else { // Native Swift super calls are direct. setCallee(Callee::forDirect(gen, constant, getSubstFnType(), fn)); } // If there are any substitutions for the callee, apply them now. if (!substitutions.empty()) callee->setSubstitutions(gen, fn, substitutions, callDepth-1); } /// Try to emit the given application as initializer delegation. bool applyInitDelegation(ApplyExpr *expr) { // Dig out the constructor we're delegating to. Expr *fn = expr->getFn(); auto ctorRef = dyn_cast( fn->getSemanticsProvidingExpr()); if (!ctorRef) return false; // Determine whether we'll need to use an allocating constructor (vs. the // initializing constructor). auto nominal = ctorRef->getDecl()->getDeclContext() ->getDeclaredTypeOfContext()->getAnyNominal(); bool useAllocatingCtor = isa(nominal) || isa(nominal); // Load the 'self' argument. Expr *arg = expr->getArg(); ManagedValue self = gen.emitRValueAsSingleValue(arg); // If we're using the allocating constructor, we need to pass along the // metatype. if (useAllocatingCtor) { auto cleanup = self.getCleanup(); SILValue selfMeta = gen.emitMetatypeOfValue(expr, self.forward(gen)); self = ManagedValue(selfMeta, cleanup); } CanType selfFormalType = arg->getType()->getCanonicalType(); setSelfParam(RValue(gen, expr, selfFormalType, self), expr); // Determine the callee. For structs and enums, this is the allocating // constructor (because there is no initializing constructor). For classes, // this is the initializing constructor, to which we will dynamically // dispatch. if (isa(nominal)) { // If the constructor is a convenience initializer, use // dynamic dispatch to the initializing constructor. setCallee(Callee::forClassMethod( gen, self.getValue(), SILDeclRef(ctorRef->getDecl(), SILDeclRef::Kind::Initializer, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, gen.SGM.requiresObjCDispatch(ctorRef->getDecl())), getSubstFnType(), fn)); } else { // Directly call the peer constructor. setCallee(Callee::forDirect(gen, SILDeclRef(ctorRef->getDecl(), useAllocatingCtor ? SILDeclRef::Kind::Allocator : SILDeclRef::Kind::Initializer, SILDeclRef::ConstructAtBestResilienceExpansion), getSubstFnType(useAllocatingCtor), fn)); } // Set up the substitutions, if we have any. if (ctorRef->getDeclRef().isSpecialized()) callee->setSubstitutions(gen, fn, ctorRef->getDeclRef().getSubstitutions(), callDepth-1); return true; } Callee getCallee() { assert(callee && "did not find callee?!"); return *std::move(callee); } /// Ignore parentheses and implicit conversions. static Expr *ignoreParensAndImpConversions(Expr *expr) { while (true) { if (auto ice = dyn_cast(expr)) { expr = ice->getSubExpr(); continue; } // Simple optional-to-optional conversions. This doesn't work // for the full generality of OptionalEvaluationExpr, but it // works given that we check the result for certain forms. if (auto eval = dyn_cast(expr)) { if (auto inject = dyn_cast(eval->getSubExpr())) { if (auto bind = dyn_cast(inject->getSubExpr())) { if (bind->getDepth() == 0) return bind->getSubExpr(); } } } auto valueProviding = expr->getValueProvidingExpr(); if (valueProviding != expr) { expr = valueProviding; continue; } return expr; } } void visitForceValueExpr(ForceValueExpr *e) { // If this application is a dynamic member reference that is forced to // succeed with the '!' operator, emit it as a direct invocation of the // method we found. if (emitForcedDynamicMemberRef(e)) return; visitExpr(e); } /// If this application forces a dynamic member reference with !, emit /// a direct reference to the member. bool emitForcedDynamicMemberRef(ForceValueExpr *e) { // Check whether the argument is a dynamic member reference. auto arg = ignoreParensAndImpConversions(e->getSubExpr()); auto dynamicMemberRef = dyn_cast(arg); if (!dynamicMemberRef) return false; // objc_msgSend() already contains the dynamic method lookup check, which // allows us to avoid emitting a specific test for the dynamic method. // Bail out early if we aren't using Objective-C dispatch. if (!gen.SGM.requiresObjCDispatch(dynamicMemberRef->getMember().getDecl())) return false; // Since we'll be collapsing this call site, make sure there's another // call site that will actually perform the invocation. if (callSites.empty()) return false; // Only methods can be forced. auto *fd = dyn_cast(dynamicMemberRef->getMember().getDecl()); if (!fd) return false; // We found it. Emit the base. ManagedValue existential = gen.emitRValueAsSingleValue(dynamicMemberRef->getBase()); assert(fd->isObjC() && "Dynamic member references require @objc"); SILValue val; if (fd->isInstanceMember()) { assert(fd->isInstanceMember() && "Non-instance dynamic member reference"); // Attach the existential cleanup to the projection so that it gets // consumed (or not) when the call is applied to it (or isn't). val = gen.B.createProjectExistentialRef(dynamicMemberRef, existential.getValue(), getSelfTypeForDynamicLookup(gen, existential.getValue())); val = gen.B.createUncheckedRefCast(dynamicMemberRef, val, SILType::getUnknownObjectType(gen.getASTContext())); ManagedValue proj(val, existential.getCleanup()); setSelfParam(RValue(gen, dynamicMemberRef, proj.getType().getSwiftRValueType(), proj), dynamicMemberRef); } else { assert(existential.getType().is() && "non-dynamic-lookup-metatype for static method?!"); val = existential.getValue(); ManagedValue proj(val, existential.getCleanup()); setSelfParam(RValue(gen, dynamicMemberRef, existential.getType().getSwiftRValueType(), existential), dynamicMemberRef); } // Determine the type of the method we referenced, by replacing the // class type of the 'Self' parameter with Builtin.UnknownObject. SILDeclRef member(fd, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isObjC=*/true); setCallee(Callee::forDynamic(gen, val, member, getSubstFnType(), e)); return true; } }; } // end anonymous namespace #ifndef NDEBUG static bool areOnlyAbstractionDifferent(CanType type1, CanType type2) { assert(type1->isLegalSILType()); assert(type2->isLegalSILType()); // Exact equality is fine. if (type1 == type2) return true; // Either both types should be tuples or neither should be. if (auto tuple1 = dyn_cast(type1)) { auto tuple2 = dyn_cast(type2); if (!tuple2) return false; if (tuple1->getNumElements() != tuple2->getNumElements()) return false; for (auto i : indices(tuple2->getElementTypes())) if (!areOnlyAbstractionDifferent(tuple1.getElementType(i), tuple2.getElementType(i))) return false; return true; } if (isa(type2)) return false; // Either both types should be metatypes or neither should be. if (auto meta1 = dyn_cast(type1)) { auto meta2 = dyn_cast(type2); if (!meta2) return false; if (meta1.getInstanceType() != meta2.getInstanceType()) return false; return true; } // Either both types should be functions or neither should be. if (auto fn1 = dyn_cast(type1)) { auto fn2 = dyn_cast(type2); if (!fn2) return false; // TODO: maybe there are checks we can do here? (void) fn1; (void) fn2; return true; } if (isa(type2)) return false; llvm_unreachable("no other types should differ by abstraction"); } #endif static bool isNative(AbstractCC cc) { switch (cc) { case AbstractCC::C: case AbstractCC::ObjCMethod: return false; case AbstractCC::Freestanding: case AbstractCC::Method: case AbstractCC::WitnessMethod: return true; } llvm_unreachable("bad CC"); } /// Given two SIL types which are representations of the same type, /// check whether they have an abstraction difference. static bool hasAbstractionDifference(AbstractCC cc, CanType type1, CanType type2) { assert(!isNative(cc) || areOnlyAbstractionDifferent(type1, type2)); // Assuming that we've applied the same substitutions to both types, // abstraction equality should equal type equality. return (type1 != type2); } /// Emit a raw apply operation, performing no additional lowering of /// either the arguments or the result. static SILValue emitRawApply(SILGenFunction &gen, SILLocation loc, ManagedValue fn, ArrayRef subs, ArrayRef args, CanSILFunctionType substFnType, bool transparent, SILValue resultAddr) { // Get the callee value. SILValue fnValue = substFnType->isCalleeConsumed() ? fn.forward(gen) : fn.getValue(); SmallVector argValues; // Add the buffer for the indirect return if needed. assert(bool(resultAddr) == substFnType->hasIndirectResult()); if (substFnType->hasIndirectResult()) { assert(resultAddr.getType() == substFnType->getIndirectInterfaceResult().getSILType().getAddressType()); argValues.push_back(resultAddr); } auto inputTypes = substFnType->getInterfaceParametersWithoutIndirectResult(); assert(inputTypes.size() == args.size()); // Gather the arguments. for (auto i : indices(args)) { auto argValue = (inputTypes[i].isConsumed() ? args[i].forward(gen) : args[i].getValue()); #ifndef NDEBUG if (argValue.getType() != inputTypes[i].getSILType()) { auto &out = llvm::errs(); out << "TYPE MISMATCH IN ARGUMENT " << i << " OF APPLY AT "; printSILLocationDescription(out, loc, gen.getASTContext()); out << " argument value: "; argValue.print(out); out << " parameter type: "; inputTypes[i].print(out); out << "\n"; abort(); } #endif argValues.push_back(argValue); } auto resultType = substFnType->getInterfaceResult().getSILType(); auto calleeType = SILType::getPrimitiveObjectType(substFnType); SILValue result = gen.B.createApply(loc, fnValue, calleeType, resultType, subs, argValues, transparent); return result; } /// Emit a function application, assuming that the arguments have been /// lowered appropriately for the abstraction level but that the /// result does need to be turned back into something matching a /// formal type. static ManagedValue emitApply(SILGenFunction &gen, SILLocation loc, ManagedValue fn, ArrayRef subs, ArrayRef args, CanSILFunctionType substFnType, AbstractionPattern origResultType, CanType substResultType, bool transparent, Optional overrideCC, SGFContext evalContext) { auto &formalResultTL = gen.getTypeLowering(substResultType); auto loweredFormalResultType = formalResultTL.getLoweredType(); AbstractCC cc = overrideCC ? *overrideCC : substFnType->getAbstractCC(); SILType actualResultType = substFnType->getSemanticInterfaceResultSILType(); // Check whether there are abstraction differences (beyond just // direct vs. indirect) between the lowered formal result type and // the actual result type we got back. Note that this will also // include bridging differences. bool hasAbsDiffs = hasAbstractionDifference(cc, loweredFormalResultType.getSwiftRValueType(), actualResultType.getSwiftRValueType()); // Prepare a result address if necessary. SILValue resultAddr; bool emittedIntoContext = false; if (substFnType->hasIndirectResult()) { // Get the result type with the abstraction prescribed by the // function we're calling. assert(actualResultType.isAddress()); // The context will expect the natural representation of the // result type. If there's no abstraction difference between that // and the actual form of the result, then we can emit directly // into the context. emittedIntoContext = !hasAbsDiffs; if (emittedIntoContext) { resultAddr = gen.getBufferForExprResult(loc, actualResultType, evalContext); // Otherwise, we need a temporary of the right abstraction. } else { resultAddr = gen.emitTemporaryAllocation(loc, actualResultType.getObjectType()); } } // If the function returns an inner pointer, we'll need to lifetime-extend // the 'self' parameter. SILValue lifetimeExtendedSelf; if (substFnType->getInterfaceResult().getConvention() == ResultConvention::UnownedInnerPointer) { lifetimeExtendedSelf = args.back().getValue(); switch (substFnType->getInterfaceParameters().back().getConvention()) { case swift::ParameterConvention::Direct_Owned: // If the callee will consume the 'self' parameter, let's retain it so we // can keep it alive. gen.B.emitRetainValueOperation(loc, lifetimeExtendedSelf); break; case swift::ParameterConvention::Direct_Guaranteed: case swift::ParameterConvention::Direct_Unowned: // We'll manually manage the argument's lifetime after the call. Disable // its cleanup. args.back().forwardCleanup(gen); break; case swift::ParameterConvention::Indirect_In: case swift::ParameterConvention::Indirect_Inout: case swift::ParameterConvention::Indirect_Out: // We may need to support this at some point, but currently only imported // objc methods are returns_inner_pointer. llvm_unreachable("indirect self argument to method that returns_inner_pointer?!"); } } // Emit the raw application. SILValue scalarResult = emitRawApply(gen, loc, fn, subs, args, substFnType, transparent, resultAddr); // If we emitted into the eval context, then it's because there was // no abstraction difference *or* bridging to do. But our caller // might not expect to get a result indirectly. if (emittedIntoContext) { assert(substFnType->hasIndirectResult()); assert(!hasAbsDiffs); auto managedBuffer = gen.manageBufferForExprResult(resultAddr, formalResultTL, evalContext); // managedBuffer will be null here to indicate that we satisfied // the evalContext. If so, we're done. // We are also done if the expected type is address-only. if (managedBuffer.isInContext() || formalResultTL.isAddressOnly()) return managedBuffer; // Otherwise, deactivate the cleanup we just entered; we're about // to take from the address. resultAddr = managedBuffer.forward(gen); } // Get the type lowering for the actual result representation. // This is very likely to be the same as that for the formal result. auto &actualResultTL = (actualResultType == loweredFormalResultType ? formalResultTL : gen.getTypeLowering(actualResultType)); // If the expected result is an address, manage the result address. if (formalResultTL.isAddressOnly()) { assert(resultAddr); auto managedActualResult = gen.emitManagedBufferWithCleanup(resultAddr, actualResultTL); if (!hasAbsDiffs) return managedActualResult; return gen.emitOrigToSubstValue(loc, managedActualResult, origResultType, substResultType, evalContext); } // Okay, we want a scalar result. assert(!actualResultTL.isAddressOnly() && "actual result is address-only when formal result is not?"); ManagedValue managedScalar; // If we got an indirect result, emit a take out of the result address. if (substFnType->hasIndirectResult()) { managedScalar = gen.emitLoad(loc, resultAddr, actualResultTL, SGFContext(), IsTake); // Otherwise, manage the direct result. } else { switch (substFnType->getInterfaceResult().getConvention()) { case ResultConvention::Owned: // Already retained. break; case ResultConvention::Autoreleased: // Autoreleased. Retain using retain_autoreleased. gen.B.createStrongRetainAutoreleased(loc, scalarResult); break; case ResultConvention::UnownedInnerPointer: // Autorelease the 'self' value to lifetime-extend it. assert(lifetimeExtendedSelf.isValid() && "did not save lifetime-extended self param"); gen.B.createAutoreleaseValue(loc, lifetimeExtendedSelf); SWIFT_FALLTHROUGH; case ResultConvention::Unowned: // Unretained. Retain the value. actualResultTL.emitRetainValue(gen.B, loc, scalarResult); break; } managedScalar = gen.emitManagedRValueWithCleanup(scalarResult, actualResultTL); } // Fast path: no abstraction differences or bridging. if (!hasAbsDiffs) return managedScalar; // Remove abstraction differences. if (origResultType.getAsType() != substResultType) { managedScalar = gen.emitOrigToSubstValue(loc, managedScalar, origResultType, substResultType, SGFContext()); } // Convert the result to a native value. return gen.emitBridgedToNativeValue(loc, managedScalar, cc, substResultType); } ManagedValue SILGenFunction::emitMonomorphicApply(SILLocation loc, ManagedValue fn, ArrayRef args, CanType resultType, bool transparent, Optional overrideCC) { auto fnType = fn.getType().castTo(); assert(!fnType->isPolymorphic()); return emitApply(*this, loc, fn, {}, args, fnType, AbstractionPattern(resultType), resultType, transparent, overrideCC, SGFContext()); } /// Count the number of SILParameterInfos that are needed in order to /// pass the given argument. This wouldn't be necessary if we uncurried /// left-to-right. static unsigned getFlattenedValueCount(AbstractionPattern origType, CanType substType) { if (auto origTuple = dyn_cast(origType.getAsType())) { auto substTuple = cast(substType); unsigned count = 0; assert(origTuple->getNumElements() == substTuple->getNumElements()); for (auto i : indices(origTuple.getElementTypes())) { count += getFlattenedValueCount(origType.getTupleElementType(i), substTuple.getElementType(i)); } return count; } // Most general form of an unmaterializable type. if (auto substTuple = dyn_cast(substType)) { assert(origType.isOpaque()); if (!substTuple->isMaterializable()) { unsigned count = 0; for (auto substElt : substTuple.getElementTypes()) { count += getFlattenedValueCount(origType, substElt); } return count; } } return 1; } static AbstractionPattern claimNextParamClause(AbstractionPattern &type) { auto result = type.getFunctionInputType(); type = type.getFunctionResultType(); return result; } static CanType claimNextParamClause(CanAnyFunctionType &type) { auto result = type.getInput(); type = dyn_cast(type.getResult()); return result; } namespace { class ArgEmitter { SILGenFunction &SGF; AbstractCC CC; ArrayRef ParamInfos; SmallVectorImpl &Args; public: ArgEmitter(SILGenFunction &SGF, AbstractCC cc, ArrayRef paramInfos, SmallVectorImpl &args) : SGF(SGF), CC(cc), ParamInfos(paramInfos), Args(args) {} void emit(RValueSource &&arg, AbstractionPattern origParamType) { // If it was a tuple in the original type, the parameters will // have been exploded. if (isa(origParamType.getAsType())) { emitExpanded(std::move(arg), origParamType); return; } auto substArgType = arg.getSubstType(); // Otherwise, if the substituted type is a tuple, then we should // emit the tuple in its most general form, because there's a // substitution of an opaque archetype to a tuple or function // type in play. The most general convention is generally to // pass the entire tuple indirectly, but if it's not // materializable, the convention is actually to break it up // into materializable chunks. See the comment in SILType.cpp. if (isUnmaterializableTupleType(substArgType)) { assert(origParamType.isOpaque()); emitExpanded(std::move(arg), origParamType); return; } // Okay, everything else will be passed as a single value, one // way or another. // The substituted parameter type. Might be different from the // substituted argument type by abstraction and/or bridging. auto param = claimNextParameter(); auto loweredSubstArgType = SGF.getLoweredType(substArgType).getSwiftRValueType(); // If the caller takes the argument indirectly, the argument has an // inout type. if (param.isIndirectInOut()) { assert(isa(substArgType)); emitInOut(std::move(arg), loweredSubstArgType, param.getType(), origParamType, substArgType); return; } // If the original type is passed indirectly, copy to memory if // it's not already there. (Note that this potentially includes // conventions which pass indirectly without transferring // ownership, like Itanium C++.) if (param.isIndirect()) { assert(!param.isIndirectResult()); auto value = std::move(arg).materialize(SGF, origParamType, param.getSILType()); Args.push_back(value); return; } // Okay, if the original parameter is passed directly, then we // just need to handle abstraction differences and bridging. emitDirect(std::move(arg), origParamType, param); } private: SILParameterInfo claimNextParameter() { assert(!ParamInfos.empty()); auto param = ParamInfos.front(); ParamInfos = ParamInfos.slice(1); return param; } bool isUnmaterializableTupleType(CanType type) { if (auto tuple = dyn_cast(type)) if (!tuple->isMaterializable()) return true; return false; } /// Emit an argument as an expanded tuple. void emitExpanded(RValueSource &&arg, AbstractionPattern origParamType) { CanTupleType substArgType = cast(arg.getSubstType()); // The original type isn't necessarily a tuple. assert(origParamType.matchesTuple(substArgType)); // If we're working with an r-value, just expand it out and emit // all the elements individually. if (arg.isRValue()) { auto loc = arg.getKnownRValueLocation(); SmallVector elts; std::move(arg).asKnownRValue().extractElements(elts); for (auto i : indices(substArgType.getElementTypes())) { emit({ loc, std::move(elts[i]) }, origParamType.getTupleElementType(i)); } return; } // Otherwise, we're working with an expression. Expr *e = std::move(arg).asKnownExpr(); e = e->getSemanticsProvidingExpr(); // If the source expression is a tuple literal, we can break it // up directly. if (auto tuple = dyn_cast(e)) { for (auto i : indices(tuple->getElements())) { emit(tuple->getElements()[i], origParamType.getTupleElementType(i)); } return; } // TODO: tuple shuffles, etc. // Fall back to the r-value case. emitExpanded({ e, SGF.emitRValue(e) }, origParamType); } void emitInOut(RValueSource &&arg, CanType loweredSubstArgType, CanType loweredSubstParamType, AbstractionPattern origType, CanType substType) { if (arg.isRValue()) { emitInOut(arg.getKnownRValueLocation(), std::move(arg).asKnownRValue(), loweredSubstArgType, loweredSubstParamType, origType, substType); } else { Expr *e = std::move(arg).asKnownExpr(); emitInOut(e, SGF.emitRValue(e), loweredSubstArgType, loweredSubstParamType, origType, substType); } } void emitInOut(SILLocation loc, RValue &&rvalue, CanType loweredSubstArgType, CanType loweredSubstParamType, AbstractionPattern origType, CanType substType) { if (hasAbstractionDifference(CC, loweredSubstParamType, loweredSubstArgType)) { // This could actually just be type-bridging. In any case, // it can be dealt with with writeback. llvm::errs() << "Unimplemented: abstraction difference in l-value\n"; llvm::errs() << "\n "; loweredSubstParamType.dump(); llvm::errs() << "\n "; loweredSubstArgType.dump(); abort(); } std::move(rvalue).getAll(Args); return; } void emitDirect(RValueSource &&arg, AbstractionPattern origParamType, SILParameterInfo param) { if (arg.isRValue()) { emitDirect(arg.getKnownRValueLocation(), std::move(arg).asKnownRValue(), origParamType, param); } else { Expr *e = std::move(arg).asKnownExpr(); emitDirect(e, SGF.emitRValue(e), origParamType, param); } } void emitDirect(SILLocation loc, RValue &&arg, AbstractionPattern origParamType, SILParameterInfo param) { auto value = std::move(arg).getScalarValue(); if (isNative(CC)) { value = SGF.emitSubstToOrigValue(loc, value, origParamType, arg.getType()); } else { value = SGF.emitNativeToBridgedValue(loc, value, CC, origParamType.getAsType(), arg.getType(), param.getType()); } Args.push_back(value); } }; /// A structure for conveniently claiming sets of uncurried parameters. struct ParamLowering { ArrayRef Params; AbstractCC CC; ParamLowering(CanSILFunctionType fnType) : Params(fnType->getInterfaceParametersWithoutIndirectResult()), CC(fnType->getAbstractCC()) {} ArrayRef claimParams(AbstractionPattern origParamType, CanType substParamType) { unsigned count = getFlattenedValueCount(origParamType, substParamType); assert(count <= Params.size()); auto result = Params.slice(Params.size() - count, count); Params = Params.slice(0, Params.size() - count); return result; } ~ParamLowering() { assert(Params.empty() && "didn't consume all the parameters"); } }; class CallSite { public: SILLocation Loc; CanType SubstResultType; private: RValueSource ArgValue; public: CallSite(ApplyExpr *apply) : Loc(apply), SubstResultType(apply->getType()->getCanonicalType()), ArgValue(apply->getArg()) { } CallSite(SILLocation loc, Expr *expr, Type resultType) : Loc(loc), SubstResultType(resultType->getCanonicalType()), ArgValue(expr) { } CallSite(SILLocation loc, RValueSource &&value, Type resultType) : Loc(loc), SubstResultType(resultType->getCanonicalType()), ArgValue(std::move(value)) { } /// Return the substituted, unlowered AST type of the argument. CanType getSubstArgType() const { return ArgValue.getSubstType(); } /// Return the substituted, unlowered AST type of the result of /// this application. CanType getSubstResultType() const { return SubstResultType; } void emit(SILGenFunction &gen, AbstractionPattern origParamType, ParamLowering &lowering, SmallVectorImpl &args) && { auto params = lowering.claimParams(origParamType, getSubstArgType()); ArgEmitter emitter(gen, lowering.CC, params, args); emitter.emit(std::move(ArgValue), origParamType); } }; class CallEmission { SILGenFunction &gen; std::vector uncurriedSites; std::vector extraSites; Callee callee; Optional initialWritebackScope; unsigned uncurries; bool applied; public: CallEmission(SILGenFunction &gen, Callee &&callee) : gen(gen), callee(std::move(callee)), uncurries(callee.getNaturalUncurryLevel() + 1), applied(false) {} CallEmission(SILGenFunction &gen, Callee &&callee, WritebackScope &&writebackScope) : CallEmission(gen, std::move(callee)) { initialWritebackScope.emplace(std::move(writebackScope)); } void addCallSite(CallSite &&site) { assert(!applied && "already applied!"); // Append to the main argument list if we have uncurry levels remaining. if (uncurries > 0) { --uncurries; uncurriedSites.push_back(std::move(site)); return; } // Otherwise, apply these arguments to the result of the previous call. extraSites.push_back(std::move(site)); } template void addCallSite(T &&...args) { addCallSite(CallSite{std::forward(args)...}); } ManagedValue apply(SGFContext C = SGFContext()) { assert(!applied && "already applied!"); applied = true; // Get the callee value at the needed uncurry level. unsigned uncurryLevel = callee.getNaturalUncurryLevel() - uncurries; // Get either the specialized emitter for a known function, or the // function value for a normal callee. Callee::SpecializedEmitter specializedEmitter = nullptr; CanSILFunctionType substFnType; ManagedValue mv; bool transparent; AbstractionPattern origFormalType(callee.getOrigFormalType()); CanAnyFunctionType formalType = callee.getSubstFormalType(); // Check for a specialized emitter. auto maybeEmitter = callee.getSpecializedEmitter(gen.SGM, uncurryLevel); if (maybeEmitter) { specializedEmitter = maybeEmitter.getValue(); // We want to emit the arguments as fully-substituted values // because that's what the specialized emitters expect. origFormalType = AbstractionPattern(formalType); substFnType = gen.getLoweredType(formalType, uncurryLevel) .castTo(); transparent = false; // irrelevant } else { std::tie(mv, substFnType, transparent) = callee.getAtUncurryLevel(gen, uncurryLevel); } // Emit the arguments. Optional uncurriedLoc; SmallVector, 2> args; args.reserve(uncurriedSites.size()); { ParamLowering paramLowering(substFnType); // Collect the arguments to the uncurried call. for (auto &site : uncurriedSites) { AbstractionPattern origParamType = claimNextParamClause(origFormalType); uncurriedLoc = site.Loc; args.push_back({}); std::move(site).emit(gen, origParamType, paramLowering, args.back()); } } assert(uncurriedLoc); // Uncurry the arguments in calling convention order. SmallVector uncurriedArgs; for (auto &argSet : reversed(args)) uncurriedArgs.append(argSet.begin(), argSet.end()); args = {}; // We use the context emit-into initialization only for the outermost // call. SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); // Emit the uncurried call. ManagedValue result; if (specializedEmitter) result = specializedEmitter(gen, uncurriedLoc.getValue(), callee.getSubstitutions(), uncurriedArgs, uncurriedContext); else result = emitApply(gen, uncurriedLoc.getValue(), mv, callee.getSubstitutions(), uncurriedArgs, substFnType, origFormalType, uncurriedSites.back().getSubstResultType(), transparent, Nothing, uncurriedContext); // End the initial writeback scope, if any. initialWritebackScope.reset(); // If there are remaining call sites, apply them to the result function. // Each chained call gets its own writeback scope. claimNextParamClause(formalType); for (unsigned i = 0, size = extraSites.size(); i < size; ++i) { WritebackScope scope(gen); auto substFnType = result.getType().castTo(); ParamLowering paramLowering(substFnType); uncurriedArgs.clear(); // The result function has already been reabstracted to the substituted // type. AbstractionPattern origParamType(claimNextParamClause(formalType)); std::move(extraSites[i]).emit(gen, origParamType, paramLowering, uncurriedArgs); SGFContext context = i == size - 1 ? C : SGFContext(); SILLocation loc = extraSites[i].Loc; result = emitApply(gen, loc, result, {}, uncurriedArgs, substFnType, origFormalType, extraSites[i].getSubstResultType(), false, Nothing, context); } return result; } ~CallEmission() { assert(applied && "never applied!"); } // Movable, but not copyable. CallEmission(CallEmission &&e) : gen(e.gen), uncurriedSites(std::move(e.uncurriedSites)), extraSites(std::move(e.extraSites)), callee(std::move(e.callee)), uncurries(e.uncurries), applied(e.applied) { e.applied = true; } private: CallEmission(const CallEmission &) = delete; CallEmission &operator=(const CallEmission &) = delete; }; static ManagedValue emitBuiltinRetain(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { // The value was produced at +1; we can produce an unbalanced // retain simply by disabling the cleanup. args[0].forward(gen); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } static ManagedValue emitBuiltinRelease(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { // The value was produced at +1, so to produce an unbalanced // release we need to leave the cleanup intact and then do a *second* // release. gen.B.createReleaseValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } static ManagedValue emitBuiltinAutorelease(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { // The value was produced at +1, so to produce an unbalanced // autorelease we need to leave the cleanup intact. gen.B.createAutoreleaseValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } /// Specialized emitter for Builtin.load and Builtin.take. static ManagedValue emitBuiltinLoadOrTake(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C, IsTake_t isTake) { assert(substitutions.size() == 1 && "load should have single substitution"); assert(args.size() == 1 && "load should have a single argument"); // The substitution gives the type of the load. This is always a // first-class type; there is no way to e.g. produce a @weak load // with this builtin. auto &rvalueTL = gen.getTypeLowering(substitutions[0].Replacement); SILType loadedType = rvalueTL.getLoweredType(); // Convert the pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), loadedType.getAddressType()); // Perform the load. return gen.emitLoad(loc, addr, rvalueTL, C, isTake); } static ManagedValue emitBuiltinLoad(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { return emitBuiltinLoadOrTake(gen, loc, substitutions, args, C, IsNotTake); } static ManagedValue emitBuiltinTake(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { return emitBuiltinLoadOrTake(gen, loc, substitutions, args, C, IsTake); } /// Specialized emitter for Builtin.destroy. static ManagedValue emitBuiltinDestroy(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 2 && "destroy should have two arguments"); assert(substitutions.size() == 1 && "destroy should have a single substitution"); // The substitution determines the type of the thing we're destroying. auto &ti = gen.getTypeLowering(substitutions[0].Replacement); // Destroy is a no-op for trivial types. if (ti.isTrivial()) return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); SILType destroyType = ti.getLoweredType(); // Convert the pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args[1].getUnmanagedValue(), destroyType.getAddressType()); // Destroy the value indirectly. Canonicalization will promote to loads // and releases if appropriate. gen.B.emitDestroyAddr(loc, addr); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } /// Specialized emitter for Builtin.assign and Builtin.init. static ManagedValue emitBuiltinAssignOrInit(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C, bool isInitialization) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions[0].Replacement->getCanonicalType(); SILType assignType = gen.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType()); // Build the value to be assigned, reconstructing tuples if needed. ManagedValue src = RValue(args.slice(0, args.size() - 1), assignFormalType) .getAsSingleValue(gen, loc); if (isInitialization) src.forwardInto(gen, loc, addr); else src.assignInto(gen, loc, addr); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } static ManagedValue emitBuiltinAssign(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { return emitBuiltinAssignOrInit(gen, loc, substitutions, args, C, /*isInitialization*/ false); } static ManagedValue emitBuiltinInit(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { return emitBuiltinAssignOrInit(gen, loc, substitutions, args, C, /*isInitialization*/ true); } /// Specialized emitter for Builtin.fixLifetime. static ManagedValue emitBuiltinFixLifetime(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { for (auto arg : args) { gen.B.createFixLifetime(loc, arg.getValue()); } return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } /// Specialized emitter for Builtin.castToNativeObject. static ManagedValue emitBuiltinCastToNativeObject(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "cast should have a single argument"); assert(substitutions.size() == 1 && "cast should have a type substitution"); // Bail if the source type is not a class reference of some kind. if (!substitutions[0].Replacement->mayHaveSuperclass() && !substitutions[0].Replacement->isClassExistentialType()) { gen.SGM.diagnose(loc, diag::invalid_sil_builtin, "castToNativeObject source must be a class"); // FIXME: Recovery? llvm::report_fatal_error("unable to set up the ObjC bridge!"); } // Save the cleanup on the argument so we can forward it onto the cast // result. auto cleanup = args[0].getCleanup(); // Take the reference type argument and cast it to NativeObject. SILType objPointerType = SILType::getNativeObjectType(gen.F.getASTContext()); SILValue arg = args[0].getValue(); // If the argument is existential, project it. if (substitutions[0].Replacement->isClassExistentialType()) { SmallVector protocols; substitutions[0].Replacement->getAnyExistentialTypeProtocols(protocols); ProtocolDecl *proto = *std::find_if(protocols.begin(), protocols.end(), [](ProtocolDecl *proto) { return proto->requiresClass(); }); SILType protoSelfTy = gen.getLoweredType( proto->getSelf()->getArchetype()); arg = gen.B.createProjectExistentialRef(loc, arg, protoSelfTy); } SILValue result = gen.B.createUncheckedRefCast(loc, arg, objPointerType); // Return the cast result with the original cleanup. return ManagedValue(result, cleanup); } /// Specialized emitter for Builtin.castFromNativeObject. static ManagedValue emitBuiltinCastFromNativeObject(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "cast should have a single argument"); assert(substitutions.size() == 1 && "cast should have a single substitution"); // Bail if the source type is not a class reference of some kind. if (!substitutions[0].Replacement->mayHaveSuperclass()) { gen.SGM.diagnose(loc, diag::invalid_sil_builtin, "castFromNativeObject dest must be a class"); // FIXME: Recovery? llvm::report_fatal_error("unable to set up the ObjC bridge!"); } // Save the cleanup on the argument so we can forward it onto the cast // result. auto cleanup = args[0].getCleanup(); // The substitution determines the destination type. // FIXME: Archetype destination type? SILType destType = gen.getLoweredLoadableType(substitutions[0].Replacement); // Take the reference type argument and cast it. SILValue result = gen.B.createUncheckedRefCast(loc, args[0].getValue(), destType); // Return the cast result with the original cleanup. return ManagedValue(result, cleanup); } /// Specialized emitter for Builtin.bridgeToRawPointer. static ManagedValue emitBuiltinBridgeToRawPointer(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "bridge should have a single argument"); // Take the reference type argument and cast it to RawPointer. // RawPointers do not have ownership semantics, so the cleanup on the // argument remains. SILType rawPointerType = SILType::getRawPointerType(gen.F.getASTContext()); SILValue result = gen.B.createRefToRawPointer(loc, args[0].getValue(), rawPointerType); return ManagedValue::forUnmanaged(result); } /// Specialized emitter for Builtin.bridgeFromRawPointer. static ManagedValue emitBuiltinBridgeFromRawPointer(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(substitutions.size() == 1 && "bridge should have a single substitution"); assert(args.size() == 1 && "bridge should have a single argument"); // The substitution determines the destination type. // FIXME: Archetype destination type? auto &destLowering = gen.getTypeLowering(substitutions[0].Replacement); assert(destLowering.isLoadable()); SILType destType = destLowering.getLoweredType(); // Take the raw pointer argument and cast it to the destination type. SILValue result = gen.B.createRawPointerToRef(loc, args[0].getUnmanagedValue(), destType); // The result has ownership semantics, so retain it with a cleanup. return gen.emitManagedRetain(loc, result, destLowering); } /// Specialized emitter for Builtin.addressof. static ManagedValue emitBuiltinAddressOf(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "addressof should have a single argument"); // Take the address argument and cast it to RawPointer. SILType rawPointerType = SILType::getRawPointerType(gen.F.getASTContext()); SILValue result = gen.B.createAddressToPointer(loc, args[0].getUnmanagedValue(), rawPointerType); return ManagedValue::forUnmanaged(result); } /// Specialized emitter for Builtin.typeof. static ManagedValue emitBuiltinTypeOf(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "typeof should have a single argument"); // Get the metatype of the argument. SILValue metaTy = gen.emitMetatypeOfValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(metaTy); } /// Specialized emitter for Builtin.gep. static ManagedValue emitBuiltinGep(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 2 && "gep should be given two arguments"); SILValue offsetPtr = gen.B.createIndexRawPointer(loc, args[0].getUnmanagedValue(), args[1].getUnmanagedValue()); return ManagedValue::forUnmanaged(offsetPtr); } /// Specialized emitter for Builtin.condfail. static ManagedValue emitBuiltinCondFail(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(args.size() == 1 && "condfail should be given one argument"); gen.B.createCondFail(loc, args[0].getUnmanagedValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); } /// The type of trait builtins. static SILType getTypeTraitSILType(ASTContext &C) { auto param = CanGenericTypeParamType::get(0, 0, C); auto reqt = Requirement(RequirementKind::WitnessMarker, param, param); auto metaTy = CanMetatypeType::get(param, MetatypeRepresentation::Thick); auto sig = GenericSignature::get(param.getPointer(), reqt) ->getCanonicalSignature(); auto boolTy = BuiltinIntegerType::get(1, C) ->getCanonicalType(); auto fnTy = SILFunctionType::get(sig, AnyFunctionType::ExtInfo() .withRepresentation(FunctionType::Representation::Thin), ParameterConvention::Direct_Unowned, SILParameterInfo(metaTy, ParameterConvention::Direct_Unowned), SILResultInfo(boolTy, ResultConvention::Unowned), C); return SILType::getPrimitiveObjectType(fnTy); } /// Specialized emitter for type traits. template static ManagedValue emitBuiltinTypeTrait(SILGenFunction &gen, SILLocation loc, ArrayRef substitutions, ArrayRef args, SGFContext C) { assert(substitutions.size() == 1 && "type trait should take a single type parameter"); assert(args.size() == 1 && "type trait should take a single argument"); bool result; auto traitTy = substitutions[0].Replacement->getCanonicalType(); switch ((traitTy.getPointer()->*Trait)()) { // If the type obviously has or lacks the trait, emit a constant result. case TypeTraitResult::IsNot: result = false; break; case TypeTraitResult::Is: result = true; break; // If not, emit the builtin call normally. Specialization may be able to // eliminate it later, or we'll lower it away at IRGen time. case TypeTraitResult::CanBe: { auto &C = gen.getASTContext(); auto builtin = gen.B.createBuiltinFunctionRef(loc, C.getIdentifier(getBuiltinName(Kind)), getTypeTraitSILType(C)); auto builtinTy = builtin->getType().castTo(); auto substTy = builtinTy->substInterfaceGenericArgs(gen.SGM.M, gen.SGM.M.getSwiftModule(), substitutions); auto apply = gen.B.createApply(loc, builtin, SILType::getPrimitiveObjectType(substTy), builtinTy->getInterfaceResult().getSILType(), substitutions, args[0].getValue()); return ManagedValue::forUnmanaged(apply); } } // Produce the result as an integer literal constant. auto val = gen.B.createIntegerLiteral(loc, SILType::getBuiltinIntegerType(1, gen.getASTContext()), (uintmax_t)result); return ManagedValue::forUnmanaged(val); } Callee::SpecializedEmitter Callee::getSpecializedEmitterForSILBuiltin(SILDeclRef function, SILModule &SILM) { // Filter out non-function members and non-builtin modules. if (function.kind != SILDeclRef::Kind::Func) return nullptr; if (!function.hasDecl()) return nullptr; ValueDecl *decl = function.getDecl(); if (!isa(decl->getDeclContext())) return nullptr; const BuiltinInfo &Builtin = SILM.getBuiltinInfo(decl->getName()); // Match SIL builtins to their emitters. #define BUILTIN(Id, Name, Attrs) #define BUILTIN_SIL_OPERATION(Id, Name, Overload) \ if (Builtin.ID == BuiltinValueKind::Id) \ return &emitBuiltin##Id; // Lower away type trait builtins when they're trivially solvable. #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \ if (Builtin.ID == BuiltinValueKind::Id) \ return &emitBuiltinTypeTrait<&TypeBase::Name, BuiltinValueKind::Id>; #include "swift/AST/Builtins.def" return nullptr; } } // end anonymous namespace static CallEmission prepareApplyExpr(SILGenFunction &gen, Expr *e) { // Set up writebacks for the call(s). WritebackScope writebacks(gen); SILGenApply apply(gen); // Decompose the call site. apply.decompose(e); // Evaluate and discard the side effect if present. if (apply.sideEffect) gen.emitRValue(apply.sideEffect); // Build the call. // Pass the writeback scope on to CallEmission so it can thread scopes through // nested calls. CallEmission emission(gen, apply.getCallee(), std::move(writebacks)); // Apply 'self' if provided. if (apply.selfParam) emission.addCallSite(RegularLocation(e), RValueSource(apply.SelfApplyExpr, std::move(apply.selfParam)), apply.SelfApplyExpr->getType()); // Apply arguments from call sites, innermost to outermost. for (auto site = apply.callSites.rbegin(), end = apply.callSites.rend(); site != end; ++site) { emission.addCallSite(*site); } return emission; } RValue SILGenFunction::emitApplyExpr(ApplyExpr *e, SGFContext c) { return RValue(*this, e, prepareApplyExpr(*this, e).apply(c)); } ManagedValue SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, FuncDecl *fn, ArrayRef subs, ArrayRef args, SGFContext ctx) { auto origFormalType = cast(fn->getType()->getCanonicalType()); auto substFormalType = origFormalType; if (!subs.empty()) { auto polyFnType = cast(substFormalType); auto applied = polyFnType->substGenericArgs(SGM.SwiftModule, subs); substFormalType = cast(applied->getCanonicalType()); } auto callee = Callee::forDirect(*this, SILDeclRef(fn), substFormalType, loc); callee.setSubstitutions(*this, loc, subs, 0); ManagedValue mv; CanSILFunctionType substFnType; bool transparent; std::tie(mv, substFnType, transparent) = callee.getAtUncurryLevel(*this, 0); assert(substFnType->getAbstractCC() == AbstractCC::Freestanding); return emitApply(*this, loc, mv, subs, args, substFnType, AbstractionPattern(origFormalType.getResult()), substFormalType.getResult(), transparent, Nothing, ctx); } /// emitArrayInjectionCall - Form an array "Array" out of an NativeObject /// (which represents the retain count), a base pointer to some elements, and a /// length. ManagedValue SILGenFunction::emitArrayInjectionCall(ManagedValue ObjectPtr, SILValue BasePtr, SILValue Length, Expr *ArrayInjectionFunction, SILLocation Loc) { // Bitcast the BasePtr (an lvalue) to Builtin.RawPointer if it isn't already. if (BasePtr.getType() != SILType::getRawPointerType(F.getASTContext())) BasePtr = B.createAddressToPointer(Loc, BasePtr, SILType::getRawPointerType(F.getASTContext())); // Construct a call to the injection function. CallEmission emission = prepareApplyExpr(*this, ArrayInjectionFunction); auto *injectionFnTy = ArrayInjectionFunction->getType()->getAs(); auto injectionArgsTy = cast(injectionFnTy->getInput()->getCanonicalType()); RValue InjectionArgs(injectionArgsTy); InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(0), ManagedValue::forUnmanaged(BasePtr))); InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(1), ObjectPtr)); InjectionArgs.addElement(RValue(*this, Loc, injectionArgsTy.getElementType(2), ManagedValue::forUnmanaged(Length))); emission.addCallSite(Loc, RValueSource(Loc, std::move(InjectionArgs)), injectionFnTy->getResult()); return emission.apply(); } static Callee getBaseAccessorFunctionRef(SILGenFunction &gen, SILLocation loc, SILDeclRef constant, RValueSource &selfValue, bool isSuper, CanAnyFunctionType substAccessorType, ArrayRef &substitutions){ auto *decl = cast(constant.getDecl()); // If this is a method in a protocol, generate it as a protocol call. if (auto *protoDecl = dyn_cast(decl->getDeclContext())) { // Method calls through ObjC protocols require ObjC dispatch. constant = constant.asForeign(protoDecl->isObjC()); // The protocol self is implicitly decurried. substAccessorType = CanAnyFunctionType(substAccessorType->getResult() ->castTo()); // If this is an archetype case, construct an archetype call. if (!selfValue.getSubstType()->getInOutObjectType()->isAnyExistentialType()) { SILValue baseVal = selfValue.forceAndPeekRValue(gen).peekScalarValue(); return Callee::forArchetype(gen, baseVal, constant, substAccessorType, loc); } // If this is a protocol (not archetype) use, project out the underlying // existential. ManagedValue baseVal = std::move(selfValue).getAsSingleValue(gen, SGFContext::AllowPlusZero); SILType protoSelfTy = gen.getLoweredType(protoDecl->getSelf()->getArchetype()); auto selfLoc = selfValue.getLocation(); ManagedValue projVal; if (baseVal.getType().isClassExistentialType()) { // Attach the existential cleanup to the projection so that it gets // consumed (or not) when the call is applied to it (or isn't). SILValue val = gen.B.createProjectExistentialRef(loc, baseVal.getValue(), protoSelfTy); projVal = ManagedValue(val, baseVal.getCleanup()); } else { assert(protoSelfTy.isAddress() && "Self should be address-only"); SILValue val = gen.B.createProjectExistential(selfLoc, baseVal.getValue(), protoSelfTy); projVal = ManagedValue::forUnmanaged(val); } // Update the self value to use the projection. selfValue = RValueSource(selfLoc, RValue(gen, selfLoc, protoSelfTy.getSwiftType(), projVal)); assert(substitutions.size() >= 1); substitutions = substitutions.slice(1); return Callee::forProtocol(gen, baseVal.getValue(), constant, substAccessorType, loc); } bool isClassDispatch = false; if (auto ctx = decl->getDeclContext()->getDeclaredTypeOfContext()) isClassDispatch = ctx->getClassOrBoundGenericClass(); // Dispatch in a struct/enum or to an @final method is always direct. if (!isClassDispatch || decl->isFinal()) return Callee::forDirect(gen, constant, substAccessorType, loc); // Otherwise, if we have a non-final class dispatch to a normal method, // perform a dynamic dispatch. auto self = selfValue.forceAndPeekRValue(gen).peekScalarValue(); if (!isSuper) return Callee::forClassMethod(gen, self, constant, substAccessorType, loc); // If this is a "super." dispatch, we either do a direct dispatch in the case // of swift classes or an objc super call. while (auto *upcast = dyn_cast(self)) self = upcast->getOperand(); if (constant.isForeign) return Callee::forSuperMethod(gen, self, constant, substAccessorType,loc); return Callee::forDirect(gen, constant, substAccessorType, loc); } static Callee emitSpecializedAccessorFunctionRef(SILGenFunction &gen, SILLocation loc, SILDeclRef constant, ArrayRef substitutions, RValueSource &selfValue, bool isSuper) { // If the accessor is a local constant, use it. // FIXME: Can local properties ever be generic? if (gen.LocalFunctions.count(constant)) { SILValue v = gen.LocalFunctions[constant]; auto formalType = gen.SGM.Types.getConstantFormalTypeWithoutCaptures(constant); return Callee::forIndirect(gen.emitManagedRetain(loc, v), formalType, formalType, false, loc); } SILConstantInfo constantInfo = gen.getConstantInfo(constant); // Apply substitutions to the callee type. CanAnyFunctionType substAccessorType = constantInfo.FormalType; if (!substitutions.empty()) { auto polyFn = cast(substAccessorType); auto substFn = polyFn->substGenericArgs(gen.SGM.SwiftModule, substitutions); substAccessorType = cast(substFn->getCanonicalType()); } // Get the accessor function. The type will be a polymorphic function if // the Self type is generic. // FIXME: Dynamic dispatch for archetype/existential methods. Callee callee = getBaseAccessorFunctionRef(gen, loc, constant, selfValue, isSuper, substAccessorType, substitutions); // If there are substitutions, specialize the generic accessor. // FIXME: Generic subscript operator could add another layer of // substitutions. if (!substitutions.empty()) { callee.setSubstitutions(gen, loc, substitutions, 0); } return callee; } RValueSource SILGenFunction::prepareAccessorBaseArg(SILLocation loc, ManagedValue base, AbstractFunctionDecl *decl){ if (base.isLValue()) { // inout bases get passed by their address. if (decl->getImplicitSelfDecl()->getType()->is()) return RValueSource(loc, RValue(*this, loc, base.getType().getSwiftType(), base)); // When calling an accessor, the base may be provided as an inout value, // even though we only need an rvalue. In this case, load the value out of // the address. // TODO: this causes us to materialize stuff (at the SIL level) that will // just be loaded - unnecessarily dumping stuff in memory. base = emitLoad(loc, base.getValue(), getTypeLowering(base.getType().getObjectType()), SGFContext(), IsNotTake); } return RValueSource(loc, RValue(*this, loc, base.getType().getSwiftType(), base)); } /// Emit a call to a getter. ManagedValue SILGenFunction:: emitGetAccessor(SILLocation loc, AbstractStorageDecl *decl, ArrayRef substitutions, RValueSource &&selfValue, bool isSuper, RValue &&subscripts, SGFContext c) { SILDeclRef get(decl->getGetter(), SILDeclRef::Kind::Func, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, decl->usesObjCGetterAndSetter()); Callee getter = emitSpecializedAccessorFunctionRef(*this, loc, get, substitutions, selfValue, isSuper); CanAnyFunctionType accessType = getter.getSubstFormalType(); CallEmission emission(*this, std::move(getter)); // Self -> if (selfValue) { emission.addCallSite(loc, std::move(selfValue), accessType.getResult()); accessType = cast(accessType.getResult()); } // Index or () if none. if (!subscripts) subscripts = emitEmptyTupleRValue(loc); emission.addCallSite(loc, RValueSource(loc, std::move(subscripts)), accessType.getResult()); // T return emission.apply(c); } void SILGenFunction::emitSetAccessor(SILLocation loc, AbstractStorageDecl *decl, ArrayRef substitutions, RValueSource &&selfValue, bool isSuper, RValue &&subscripts, RValue &&setValue) { SILDeclRef set(decl->getSetter(), SILDeclRef::Kind::Func, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, decl->usesObjCGetterAndSetter()); Callee setter = emitSpecializedAccessorFunctionRef(*this, loc, set, substitutions, selfValue, isSuper); CanAnyFunctionType accessType = setter.getSubstFormalType(); CallEmission emission(*this, std::move(setter)); // Self -> if (selfValue) { emission.addCallSite(loc, std::move(selfValue), accessType.getResult()); accessType = cast(accessType.getResult()); } // (value) or (value, indices) if (subscripts) { // If we have a value and index list, create a new rvalue to represent the // both of them together. The value goes first. SmallVector Elts; std::move(setValue).getAll(Elts); std::move(subscripts).getAll(Elts); setValue = RValue(Elts, accessType.getInput()); } else { setValue.rewriteType(accessType.getInput()); } emission.addCallSite(loc, RValueSource(loc, std::move(setValue)), accessType.getResult()); // () emission.apply(); } ManagedValue SILGenFunction::emitApplyConversionFunction(SILLocation loc, Expr *funcExpr, Type resultType, RValue &&operand) { // Walk the function expression, which should produce a reference to the // callee, leaving the final curry level unapplied. CallEmission emission = prepareApplyExpr(*this, funcExpr); // Rewrite the operand type to the expected argument type, to handle tuple // conversions etc. operand.rewriteType(funcExpr->getType()->castTo()->getInput() ->getCanonicalType()); // Add the operand as the final callsite. emission.addCallSite(loc, RValueSource(loc, std::move(operand)), resultType); return emission.apply(); } // Create a partial application of a dynamic method, applying bridging thunks // if necessary. static SILValue emitDynamicPartialApply(SILGenFunction &gen, SILLocation loc, SILValue method, SILValue self, CanFunctionType methodTy) { // Pop the self type off of the function type. // Just to be weird, partially applying an objc method produces a native // function (?!) auto fnTy = method.getType().castTo(); // If the original method has an @unowned_inner_pointer return, the partial // application thunk will lifetime-extend 'self' for us. auto resultInfo = fnTy->getInterfaceResult(); if (resultInfo.getConvention() == ResultConvention::UnownedInnerPointer) resultInfo = SILResultInfo(resultInfo.getType(), ResultConvention::Unowned); auto partialApplyTy = SILFunctionType::get(fnTy->getGenericSignature(), fnTy->getExtInfo() .withCallingConv(AbstractCC::Freestanding) .withRepresentation(FunctionType::Representation::Thick), ParameterConvention::Direct_Owned, fnTy->getInterfaceParameters() .slice(0, fnTy->getInterfaceParameters().size() - 1), resultInfo, gen.getASTContext()); // Retain 'self' because the partial apply will take ownership. // We can't simply forward 'self' because the partial apply is conditional. gen.B.emitRetainValueOperation(loc, self); SILValue result = gen.B.createPartialApply(loc, method, method.getType(), {}, self, SILType::getPrimitiveObjectType(partialApplyTy)); // If necessary, thunk to the native ownership conventions and bridged types. auto nativeTy = gen.getLoweredLoadableType(methodTy).castTo(); if (nativeTy != partialApplyTy) { result = gen.emitBlockToFunc(loc, ManagedValue::forUnmanaged(result), nativeTy).forward(gen); } return result; } RValue SILGenFunction::emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, SGFContext c) { // Emit the operand. ManagedValue existential = emitRValueAsSingleValue(e->getBase()); SILValue operand = existential.getValue(); if (e->getMember().getDecl()->isInstanceMember()) { operand = B.createProjectExistentialRef(e, operand, getSelfTypeForDynamicLookup(*this, operand)); operand = B.createUncheckedRefCast(e, operand, SILType::getUnknownObjectType(getASTContext())); } else { auto metatype = operand.getType().castTo(); assert(metatype->getRepresentation() == MetatypeRepresentation::Thick); metatype = CanExistentialMetatypeType::get(metatype.getInstanceType(), MetatypeRepresentation::ObjC); operand = B.createThickToObjCMetatype(e, operand, SILType::getPrimitiveObjectType(metatype)); } // Create the has-member block. SILBasicBlock *hasMemberBB = new (F.getModule()) SILBasicBlock(&F); // Create the no-member block. SILBasicBlock *noMemberBB = new (F.getModule()) SILBasicBlock(&F); // Create the continuation block. SILBasicBlock *contBB = new (F.getModule()) SILBasicBlock(&F); // The continuation block const TypeLowering &optTL = getTypeLowering(e->getType()); auto loweredOptTy = optTL.getLoweredType(); SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy); // Create the branch. FuncDecl *memberFunc; if (auto *VD = dyn_cast(e->getMember().getDecl())) memberFunc = VD->getGetter(); else memberFunc = cast(e->getMember().getDecl()); SILDeclRef member(memberFunc, SILDeclRef::Kind::Func, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isObjC=*/true); B.createDynamicMethodBranch(e, operand, member, hasMemberBB, noMemberBB); // Create the has-member branch. { B.emitBlock(hasMemberBB); FullExpr hasMemberScope(Cleanups, CleanupLocation(e)); // The argument to the has-member block is the uncurried method. auto valueTy = e->getType()->getCanonicalType().getAnyOptionalObjectType(); auto methodTy = valueTy; // For a computed variable, we want the getter. if (isa(e->getMember().getDecl())) methodTy = CanFunctionType::get(TupleType::getEmpty(getASTContext()), methodTy); auto dynamicMethodTy = getDynamicMethodLoweredType(SGM, operand, member); auto loweredMethodTy = SILType::getPrimitiveObjectType(dynamicMethodTy); SILValue memberArg = new (F.getModule()) SILArgument(loweredMethodTy, hasMemberBB); // Create the result value. SILValue result = emitDynamicPartialApply(*this, e, memberArg, operand, cast(methodTy)); if (isa(e->getMember().getDecl())) { result = B.createApply(e, result, result.getType(), getLoweredType(valueTy), {}, {}); } // Package up the result in an optional. RValue resultRV = RValue(*this, e, valueTy, emitManagedRValueWithCleanup(result)); emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL); // Branch to the continuation block. B.createBranch(e, contBB); } // Create the no-member branch. { B.emitBlock(noMemberBB); emitInjectOptionalNothingInto(e, optTemp, optTL); // Branch to the continuation block. B.createBranch(e, contBB); } // Emit the continuation block. B.emitBlock(contBB); // Package up the result. auto optResult = B.createLoad(e, optTemp); return RValue(*this, e, emitManagedRValueWithCleanup(optResult, optTL)); } RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, SGFContext c) { // Emit the base operand. ManagedValue existential = emitRValueAsSingleValue(e->getBase()); SILValue base = existential.getValue(); base = B.createProjectExistentialRef(e, base, getSelfTypeForDynamicLookup(*this, base)); base = B.createUncheckedRefCast(e, base, SILType::getUnknownObjectType(getASTContext())); // Emit the index. RValue index = emitRValue(e->getIndex()); // Create the has-member block. SILBasicBlock *hasMemberBB = new (F.getModule()) SILBasicBlock(&F); // Create the no-member block. SILBasicBlock *noMemberBB = new (F.getModule()) SILBasicBlock(&F); // Create the continuation block. SILBasicBlock *contBB = new (F.getModule()) SILBasicBlock(&F); // The continuation block const TypeLowering &optTL = getTypeLowering(e->getType()); auto loweredOptTy = optTL.getLoweredType(); SILValue optTemp = emitTemporaryAllocation(e, loweredOptTy); // Create the branch. auto subscriptDecl = cast(e->getMember().getDecl()); SILDeclRef member(subscriptDecl->getGetter(), SILDeclRef::Kind::Func, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isObjC=*/true); B.createDynamicMethodBranch(e, base, member, hasMemberBB, noMemberBB); // Create the has-member branch. { B.emitBlock(hasMemberBB); FullExpr hasMemberScope(Cleanups, CleanupLocation(e)); // The argument to the has-member block is the uncurried method. auto valueTy = e->getType()->getCanonicalType().getAnyOptionalObjectType(); auto methodTy = subscriptDecl->getGetter()->getType()->castTo() ->getResult()->getCanonicalType(); auto dynamicMethodTy = getDynamicMethodLoweredType(SGM, base, member); auto loweredMethodTy = SILType::getPrimitiveObjectType(dynamicMethodTy); SILValue memberArg = new (F.getModule()) SILArgument(loweredMethodTy, hasMemberBB); // Emit the application of 'self'. SILValue result = emitDynamicPartialApply(*this, e, memberArg, base, cast(methodTy)); // Emit the index. llvm::SmallVector indexArgs; std::move(index).forwardAll(*this, indexArgs); auto &valueTL = getTypeLowering(valueTy); result = B.createApply(e, result, result.getType(), valueTL.getLoweredType(), {}, indexArgs); // Package up the result in an optional. RValue resultRV = RValue(*this, e, valueTy, emitManagedRValueWithCleanup(result, valueTL)); emitInjectOptionalValueInto(e, {e, std::move(resultRV)}, optTemp, optTL); // Branch to the continuation block. B.createBranch(e, contBB); } // Create the no-member branch. { B.emitBlock(noMemberBB); emitInjectOptionalNothingInto(e, optTemp, optTL); // Branch to the continuation block. B.createBranch(e, contBB); } // Emit the continuation block. B.emitBlock(contBB); // Package up the result. auto optValue = B.createLoad(e, optTemp); return RValue(*this, e, emitManagedRValueWithCleanup(optValue, optTL)); }