diff --git a/CHANGELOG.md b/CHANGELOG.md index 51f925bef5dff..c1b5224699cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ Swift Next * [SR-75][]: - Unapplied references to protocol methods methods are now supported. Previously this + Unapplied references to protocol methods are now supported. Previously this only worked for methods defined in structs, enums and classes. ```swift @@ -57,7 +57,7 @@ Swift Next func play(catToy: Toy) } - let fn = Cat.play + let fn = Cat.play(catToy:) fn(myCat)(myToy) ``` diff --git a/lib/SILGen/SILGen.h b/lib/SILGen/SILGen.h index 7353e704c4633..7ae7125c25ef6 100644 --- a/lib/SILGen/SILGen.h +++ b/lib/SILGen/SILGen.h @@ -245,9 +245,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor { /// Emits default argument generators for the given parameter list. void emitDefaultArgGenerators(SILDeclRef::Loc decl, ParameterList *paramList); - - /// Emits the curry thunk between two uncurry levels of a function. - void emitCurryThunk(SILDeclRef thunk); /// Emits a thunk from a foreign function to the native Swift convention. void emitForeignToNativeThunk(SILDeclRef thunk); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 08f41aa73f016..d4d64d8ba9711 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -556,43 +556,12 @@ class Callee { return result; } - SILDeclRef getCurriedConstant(bool isCurried) const { - if (isCurried) { - auto constant = Constant.asCurried(); - - // If we're currying a direct reference to a class-dispatched method, - // make sure we emit the right set of thunks. - if (kind == Kind::StandaloneFunction) { - if (auto func = Constant.getAbstractFunctionDecl()) { - if (getMethodDispatch(func) == MethodDispatch::Class) { - return constant.asDirectReference(true); - } - } - } - - return constant; - } - - return Constant; - } - - ManagedValue getFnValue(SILGenFunction &SGF, bool isCurried, + ManagedValue getFnValue(SILGenFunction &SGF, Optional borrowedSelf) const & { Optional constant = None; - if (!Constant) { - assert(!isCurried && "can't curry indirect function"); - } else { - constant = getCurriedConstant(isCurried); - - // If the call is curried, emit a direct call to the curry thunk. - if (constant->isCurried) { - auto constantInfo = - SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); - SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); - return ManagedValue::forUnmanaged(ref); - } - } + if (Constant) + constant = Constant; switch (kind) { case Kind::IndirectValue: @@ -692,21 +661,11 @@ class Callee { llvm_unreachable("unhandled kind"); } - CalleeTypeInfo getTypeInfo(SILGenFunction &SGF, bool isCurried) const & { + CalleeTypeInfo getTypeInfo(SILGenFunction &SGF) const & { Optional constant = None; - if (!Constant) { - assert(!isCurried && "can't curry indirect function"); - } else { - constant = getCurriedConstant(isCurried); - - // If the call is curried, emit a direct call to the curry thunk. - if (constant->isCurried) { - auto constantInfo = - SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); - return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); - } - } + if (Constant) + constant = Constant; switch (kind) { case Kind::IndirectValue: @@ -845,10 +804,8 @@ class SILGenApply : public Lowering::ExprVisitor { /// The lvalue or rvalue representing the argument source of self. ArgumentSource selfParam; - /// The method type with self stripped off (NOT the type of the self value). - Type selfType; - - std::vector callSites; + ApplyExpr *selfApply = nullptr; + ApplyExpr *callSite = nullptr; Expr *sideEffect = nullptr; SILGenApply(SILGenFunction &SGF) @@ -865,14 +822,42 @@ class SILGenApply : public Lowering::ExprVisitor { sideEffect = sideEffectExpr; } - void setSelfParam(ArgumentSource &&theSelfParam, Expr *theSelfApplyExpr) { + void setSelfParam(ArgumentSource &&theSelfParam) { assert(!selfParam && "already set this!"); selfParam = std::move(theSelfParam); - selfType = theSelfApplyExpr->getType(); } - void decompose(Expr *e) { - visit(e); + bool isSelfApplyOfMethod(ApplyExpr *e) { + if (auto *selfApply = dyn_cast(e->getFn())) { + if (auto *declRefExpr = dyn_cast(selfApply->getFn())) + return declRefExpr->getDecl()->getNumCurryLevels() == 2; + + if (isa(selfApply->getFn())) + return true; + } + + return false; + } + + void decompose(ApplyExpr *e) { + callSite = e; + + if (isSelfApplyOfMethod(e)) { + selfApply = cast(e->getFn()); + + if (selfApply->isSuper()) { + applySuper(selfApply); + return; + } + + if (applyInitDelegation(selfApply)) + return; + + visit(selfApply->getFn()); + return; + } + + visit(e->getFn()); } /// Fall back to an unknown, indirect callee. @@ -889,20 +874,6 @@ class SILGenApply : public Lowering::ExprVisitor { setCallee(Callee::forIndirect(fn, origType, substType, e)); } - /// Add a call site to the curry. - void visitApplyExpr(ApplyExpr *e) { - if (e->isSuper()) { - applySuper(e); - return; - } - - if (applyInitDelegation(e)) - return; - - callSites.push_back(e); - visit(e->getFn()); - } - static constexpr unsigned metatypeRepPair(MetatypeRepresentation a, MetatypeRepresentation b) { return assert(unsigned(a) < 256 && unsigned(b) < 256 @@ -984,18 +955,14 @@ class SILGenApply : public Lowering::ExprVisitor { void processProtocolMethod(DeclRefExpr *e, AbstractFunctionDecl *afd, ProtocolDecl *proto) { - assert(!callSites.empty()); - ApplyExpr *thisCallSite = callSites.back(); - callSites.pop_back(); - - ArgumentSource selfValue = thisCallSite->getArg(); + ArgumentSource selfValue = selfApply->getArg(); auto subs = e->getDeclRef().getSubstitutions(); SILDeclRef::Kind kind = SILDeclRef::Kind::Func; if (isa(afd)) { if (proto->isObjC()) { - SILLocation loc = thisCallSite->getArg(); + SILLocation loc = selfApply->getArg(); // For Objective-C initializers, we only have an initializing // initializer. We need to allocate the object ourselves. @@ -1021,7 +988,7 @@ class SILGenApply : public Lowering::ExprVisitor { SGF, selfValue.getSubstRValueType(), constant, subs, e); - setSelfParam(std::move(selfValue), thisCallSite); + setSelfParam(std::move(selfValue)); setCallee(std::move(theCallee)); } @@ -1045,9 +1012,8 @@ class SILGenApply : public Lowering::ExprVisitor { // Required constructors are statically dispatched when the 'self' // value is statically derived. - ApplyExpr *thisCallSite = callSites.back(); - assert(thisCallSite->getArg()->getType()->is()); - if (thisCallSite->getArg()->isStaticallyDerivedMetatype()) + assert(selfApply->getArg()->getType()->is()); + if (selfApply->getArg()->isStaticallyDerivedMetatype()) return false; } @@ -1056,11 +1022,8 @@ class SILGenApply : public Lowering::ExprVisitor { } void processClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) { - ApplyExpr *thisCallSite = callSites.back(); - callSites.pop_back(); - - ArgumentSource selfArgSource(thisCallSite->getArg()); - setSelfParam(std::move(selfArgSource), thisCallSite); + ArgumentSource selfArgSource(selfApply->getArg()); + setSelfParam(std::move(selfArgSource)); // Directly dispatch to calls of the replaced function inside of // '@_dynamicReplacement(for:)' methods. @@ -1068,7 +1031,7 @@ class SILGenApply : public Lowering::ExprVisitor { if (SGF.getOptions() .EnableDynamicReplacementCanCallPreviousImplementation && isCallToReplacedInDynamicReplacement(SGF, afd, isObjCReplacementCall) && - thisCallSite->getArg()->isSelfExprOf( + selfApply->getArg()->isSelfExprOf( cast(SGF.FunctionDC->getAsDecl()), false)) { auto constant = SILDeclRef(afd).asForeign( !isObjCReplacementCall && requiresForeignEntryPoint(e->getDecl())); @@ -1104,6 +1067,11 @@ class SILGenApply : public Lowering::ExprVisitor { // Enum case constructor references are open-coded. if (auto *eed = dyn_cast(e->getDecl())) { + if (selfApply) { + ArgumentSource selfArgSource(selfApply->getArg()); + setSelfParam(std::move(selfArgSource)); + } + setCallee(Callee::forEnumElement(SGF, SILDeclRef(eed), subs, e)); return; } @@ -1135,7 +1103,7 @@ class SILGenApply : public Lowering::ExprVisitor { // Check whether we have to dispatch to the original implementation of a // dynamically_replaceable inside of a dynamic_replacement(for:) function. - ApplyExpr *thisCallSite = callSites.back(); + ApplyExpr *thisCallSite = (selfApply ? selfApply : callSite); bool isObjCReplacementSelfCall = false; bool isSelfCallToReplacedInDynamicReplacement = SGF.getOptions() @@ -1156,6 +1124,12 @@ class SILGenApply : public Lowering::ExprVisitor { else setCallee(Callee::forDirect(SGF, constant, subs, e)); + if (selfApply) { + // This is a statically-dispatched method with a 'self' parameter. + ArgumentSource selfArgSource(selfApply->getArg()); + setSelfParam(std::move(selfArgSource)); + } + // If the decl ref requires captures, emit the capture params. if (!captureInfo.getCaptures().empty()) { SmallVector captures; @@ -1303,7 +1277,7 @@ class SILGenApply : public Lowering::ExprVisitor { setCallee(Callee::forDirect(SGF, constant, substitutions, fn)); } - setSelfParam(std::move(superArgSource), apply); + setSelfParam(std::move(superArgSource)); } /// Walk the given \c selfArg expression that produces the appropriate @@ -1523,7 +1497,7 @@ class SILGenApply : public Lowering::ExprVisitor { subs, fn, true)); } - setSelfParam(std::move(selfArgSource), expr); + setSelfParam(std::move(selfArgSource)); return true; } @@ -1589,7 +1563,7 @@ class SILGenApply : public Lowering::ExprVisitor { // Since we'll be collapsing this call site, make sure there's another // call site that will actually perform the invocation. - if (callSites.empty()) + if (callSite == nullptr) return false; // Only @objc methods can be forced. @@ -1621,7 +1595,7 @@ class SILGenApply : public Lowering::ExprVisitor { setCallee(Callee::forDynamic(SGF, member, memberRef.getSubstitutions(), substFormalType, {}, e)); - setSelfParam(std::move(baseArgSource), dynamicMemberRef); + setSelfParam(std::move(baseArgSource)); }; // When we have an open existential, open it and then emit the @@ -1860,10 +1834,6 @@ static unsigned getFlattenedValueCount(AbstractionPattern origType, return getFlattenedValueCount(origType, substType); } -static void claimNextParamClause(CanAnyFunctionType &type) { - type = dyn_cast(type.getResult()); -} - namespace { /// The original argument expression for some sort of complex @@ -3460,16 +3430,14 @@ namespace { class CallSite { public: SILLocation Loc; - CanType SubstResultType; private: PreparedArguments Args; bool Throws; public: - CallSite(SILLocation loc, PreparedArguments &&args, CanType resultType, - bool throws) - : Loc(loc), SubstResultType(resultType), Args(std::move(args)), + CallSite(SILLocation loc, PreparedArguments &&args, bool throws) + : Loc(loc), Args(std::move(args)), Throws(throws) { assert(Args.isValid()); } @@ -3477,10 +3445,6 @@ class CallSite { /// Return the substituted, unlowered AST parameter types of the argument. ArrayRef getParams() const { return Args.getParams(); } - /// Return the substituted, unlowered AST type of the result of - /// this application. - CanType getSubstResultType() const { return SubstResultType; } - bool throws() const { return Throws; } /// Evaluate arguments and begin any inout formal accesses. @@ -3529,7 +3493,6 @@ class CallEmission { SILGenFunction &SGF; std::vector uncurriedSites; - std::vector extraSites; Callee callee; FormalEvaluationScope initialWritebackScope; unsigned expectedSiteCount; @@ -3550,13 +3513,8 @@ class CallEmission { /// unevaluated arguments and their formal type. void addCallSite(CallSite &&site) { // Append to the main argument list if we have uncurry levels remaining. - if (uncurriedSites.size() < expectedSiteCount) { - uncurriedSites.push_back(std::move(site)); - return; - } - - // Otherwise, apply these arguments to the result of the previous call. - extraSites.push_back(std::move(site)); + assert(uncurriedSites.size() < expectedSiteCount); + uncurriedSites.push_back(std::move(site)); } /// Add a level of function application by passing in its possibly @@ -3568,25 +3526,16 @@ class CallEmission { void addSelfParam(SILLocation loc, ArgumentSource &&selfArg, - AnyFunctionType::Param selfParam, - CanType methodType) { + AnyFunctionType::Param selfParam) { PreparedArguments preparedSelf(llvm::ArrayRef{selfParam}); preparedSelf.addArbitrary(std::move(selfArg)); - addCallSite(loc, std::move(preparedSelf), methodType, - /*throws*/ false); + addCallSite(loc, std::move(preparedSelf), /*throws*/ false); } /// Is this a fully-applied enum element constructor call? bool isEnumElementConstructor() { - return (callee.kind == Callee::Kind::EnumElement && - uncurriedSites.size() == expectedSiteCount); - } - - /// True if this is a completely unapplied super method call - bool isPartiallyAppliedSuperMethod() { - return (callee.kind == Callee::Kind::SuperMethod && - uncurriedSites.size() == 1); + return (callee.kind == Callee::Kind::EnumElement); } CleanupHandle applyCoroutine(SmallVectorImpl &yields); @@ -3595,32 +3544,14 @@ class CallEmission { initialWritebackScope.verify(); // Emit the first level of call. - auto firstLevelResult = applyFirstLevelCallee(C); + auto value = applyFirstLevelCallee(C); // End of the initial writeback scope. + // FIXME: Unnecessary? initialWritebackScope.verify(); initialWritebackScope.pop(); - // If we do not have any more call sites, bail early and just return the - // value. - if (extraSites.empty()) { - return std::move(firstLevelResult.value); - } - - // At this point, firstLevelResult should have a formal type for the - // remaining call sites. Do a quick assert to make sure that we have our - // rvalue and the relevant foreign type. - assert(firstLevelResult.isComplete()); - - AbstractionPattern origFormalType = - getIndirectApplyAbstractionPattern(SGF, firstLevelResult.formalType); - bool formalTypeThrows = - !cast(firstLevelResult.formalType)->getExtInfo().throws(); - - // Then handle the remaining call sites. - return applyRemainingCallSites(std::move(firstLevelResult.value), - origFormalType, firstLevelResult.foreignSelf, - C, formalTypeThrows); + return value; } // Movable, but not copyable. @@ -3643,76 +3574,24 @@ class CallEmission { /// This returns whether or not any arguments were able to throw in /// ApplyOptions. ApplyOptions emitArgumentsForNormalApply( - CanFunctionType &formalType, AbstractionPattern &origFormalType, - CanSILFunctionType substFnType, + AbstractionPattern origFormalType, CanSILFunctionType substFnType, const Optional &foreignError, ImportAsMemberStatus foreignSelf, SmallVectorImpl &uncurriedArgs, - Optional &uncurriedLoc, CanFunctionType &formalApplyType); - - struct FirstLevelApplicationResult { - RValue value; - CanFunctionType formalType; - ImportAsMemberStatus foreignSelf; - - FirstLevelApplicationResult() = default; - - // Delete copy constructor/operator, - FirstLevelApplicationResult(const FirstLevelApplicationResult &) = delete; - FirstLevelApplicationResult & - operator=(const FirstLevelApplicationResult &) = delete; - - // This is a move only type. - FirstLevelApplicationResult(FirstLevelApplicationResult &&other) - : value(std::move(other.value)), formalType(other.formalType), - foreignSelf(other.foreignSelf) {} - FirstLevelApplicationResult & - operator=(FirstLevelApplicationResult &&other) { - value = std::move(other.value); - formalType = other.formalType; - foreignSelf = other.foreignSelf; - return *this; - } - - /// Verify some variants around a complete FirstLevelApplicationResult. - /// - /// The specific invariants is that value is complete and that we have a - /// formal type. - bool isComplete() const { return value.isComplete() && bool(formalType); } - }; + Optional &uncurriedLoc); - FirstLevelApplicationResult + RValue applySpecializedEmitter(SpecializedEmitter &specializedEmitter, SGFContext C); - FirstLevelApplicationResult applyPartiallyAppliedSuperMethod(SGFContext C); - - FirstLevelApplicationResult applyEnumElementConstructor(SGFContext C); + RValue applyEnumElementConstructor(SGFContext C); - FirstLevelApplicationResult applyNormalCall(SGFContext C); + RValue applyNormalCall(SGFContext C); - FirstLevelApplicationResult applyFirstLevelCallee(SGFContext C); - - RValue applyRemainingCallSites(RValue &&result, - AbstractionPattern origFormalType, - ImportAsMemberStatus foreignSelf, SGFContext C, - bool formalTypeThrows); + RValue applyFirstLevelCallee(SGFContext C); }; } // end anonymous namespace -/// This function claims param clauses from the passed in formal type until the -/// type is completely uncurried. This will be the final result type for a -/// normal call. -static AbstractionPattern -getUncurriedOrigFormalResultType(AbstractionPattern origFormalType, - unsigned numUncurriedSites) { - for (unsigned i = 0, e = numUncurriedSites; i < e; ++i) { - origFormalType = origFormalType.getFunctionResultType(); - } - - return origFormalType; -} - namespace { /// Cleanup to end a coroutine application. class EndCoroutineApply : public Cleanup { @@ -3741,22 +3620,18 @@ class EndCoroutineApply : public Cleanup { CleanupHandle CallEmission::applyCoroutine(SmallVectorImpl &yields) { auto origFormalType = callee.getOrigFormalType(); - CanFunctionType formalType = callee.getSubstFormalType(); - - const bool isCurried = false; // Get the callee type information. - auto calleeTypeInfo = callee.getTypeInfo(SGF, isCurried); + auto calleeTypeInfo = callee.getTypeInfo(SGF); SmallVector uncurriedArgs; Optional uncurriedLoc; - CanFunctionType formalApplyType; // Evaluate the arguments. ApplyOptions options = emitArgumentsForNormalApply( - formalType, origFormalType, calleeTypeInfo.substFnType, + origFormalType, calleeTypeInfo.substFnType, calleeTypeInfo.foreignError, calleeTypeInfo.foreignSelf, uncurriedArgs, - uncurriedLoc, formalApplyType); + uncurriedLoc); // Now evaluate the callee. Optional borrowedSelf; @@ -3764,7 +3639,7 @@ CallEmission::applyCoroutine(SmallVectorImpl &yields) { borrowedSelf = uncurriedArgs.back(); } - auto fnValue = callee.getFnValue(SGF, isCurried, borrowedSelf); + auto fnValue = callee.getFnValue(SGF, borrowedSelf); return SGF.emitBeginApply(uncurriedLoc.getValue(), fnValue, callee.getSubstitutions(), uncurriedArgs, @@ -3811,17 +3686,12 @@ SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn, return endApplyHandle; } -CallEmission::FirstLevelApplicationResult -CallEmission::applyFirstLevelCallee(SGFContext C) { - // Check for a specialized emitter. - if (uncurriedSites.size() == expectedSiteCount) { - if (auto emitter = callee.getSpecializedEmitter(SGF.SGM)) { - return applySpecializedEmitter(emitter.getValue(), C); - } - } +RValue CallEmission::applyFirstLevelCallee(SGFContext C) { + assert(uncurriedSites.size() == expectedSiteCount); - if (isPartiallyAppliedSuperMethod()) { - return applyPartiallyAppliedSuperMethod(C); + // Check for a specialized emitter. + if (auto emitter = callee.getSpecializedEmitter(SGF.SGM)) { + return applySpecializedEmitter(emitter.getValue(), C); } if (isEnumElementConstructor()) { @@ -3831,21 +3701,19 @@ CallEmission::applyFirstLevelCallee(SGFContext C) { return applyNormalCall(C); } -CallEmission::FirstLevelApplicationResult -CallEmission::applyNormalCall(SGFContext C) { - FirstLevelApplicationResult firstLevelResult; - +RValue CallEmission::applyNormalCall(SGFContext C) { // We use the context emit-into initialization only for the // outermost call. - SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); + SGFContext uncurriedContext = C; - firstLevelResult.formalType = callee.getSubstFormalType(); + auto formalType = callee.getSubstFormalType(); auto origFormalType = callee.getOrigFormalType(); bool isCurried = (uncurriedSites.size() < callee.getParameterListCount()); + assert(!isCurried); // Get the callee type information. - auto calleeTypeInfo = callee.getTypeInfo(SGF, isCurried); + auto calleeTypeInfo = callee.getTypeInfo(SGF); // In C language modes, substitute the type of the AbstractionPattern // so that we won't see type parameters down when we try to form bridging @@ -3860,9 +3728,15 @@ CallEmission::applyNormalCall(SGFContext C) { } // Initialize the rest of the call info. - calleeTypeInfo.origResultType = - getUncurriedOrigFormalResultType(origFormalType, uncurriedSites.size()); - calleeTypeInfo.substResultType = uncurriedSites.back().getSubstResultType(); + calleeTypeInfo.origResultType = origFormalType.getFunctionResultType(); + calleeTypeInfo.substResultType = formalType.getResult(); + + if (uncurriedSites.size() == 2) { + calleeTypeInfo.origResultType = + calleeTypeInfo.origResultType->getFunctionResultType(); + calleeTypeInfo.substResultType = + cast(calleeTypeInfo.substResultType).getResult(); + } ResultPlanPtr resultPlan = ResultPlanBuilder::computeResultPlan( SGF, calleeTypeInfo, uncurriedSites.back().Loc, uncurriedContext); @@ -3877,9 +3751,9 @@ CallEmission::applyNormalCall(SGFContext C) { // *NOTE* We pass in initial options as a reference so that we can pass to // emitApply if any of the arguments could have thrown. ApplyOptions options = emitArgumentsForNormalApply( - firstLevelResult.formalType, origFormalType, calleeTypeInfo.substFnType, + origFormalType, calleeTypeInfo.substFnType, calleeTypeInfo.foreignError, calleeTypeInfo.foreignSelf, uncurriedArgs, - uncurriedLoc, formalApplyType); + uncurriedLoc); // Now evaluate the callee. Optional borrowedSelf; @@ -3887,15 +3761,13 @@ CallEmission::applyNormalCall(SGFContext C) { borrowedSelf = uncurriedArgs.back(); } - auto mv = callee.getFnValue(SGF, isCurried, borrowedSelf); + auto mv = callee.getFnValue(SGF, borrowedSelf); // Emit the uncurried call. - firstLevelResult.value = SGF.emitApply( + return SGF.emitApply( std::move(resultPlan), std::move(argScope), uncurriedLoc.getValue(), mv, callee.getSubstitutions(), uncurriedArgs, calleeTypeInfo, options, uncurriedContext); - firstLevelResult.foreignSelf = calleeTypeInfo.foreignSelf; - return firstLevelResult; } static void emitPseudoFunctionArguments(SILGenFunction &SGF, @@ -3904,10 +3776,8 @@ static void emitPseudoFunctionArguments(SILGenFunction &SGF, SmallVectorImpl &outVals, PreparedArguments &&args); -CallEmission::FirstLevelApplicationResult -CallEmission::applyEnumElementConstructor(SGFContext C) { - FirstLevelApplicationResult firstLevelResult; - SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); +RValue CallEmission::applyEnumElementConstructor(SGFContext C) { + SGFContext uncurriedContext = C; // Get the callee type information. // @@ -3916,7 +3786,7 @@ CallEmission::applyEnumElementConstructor(SGFContext C) { // emitters above, enum constructors use the AST-level abstraction // pattern, to ensure that function types in payloads are re-abstracted // correctly. - firstLevelResult.formalType = callee.getSubstFormalType(); + auto formalType = callee.getSubstFormalType(); auto origFormalType = callee.getOrigFormalType(); // We have a fully-applied enum element constructor: open-code the @@ -3925,18 +3795,17 @@ CallEmission::applyEnumElementConstructor(SGFContext C) { SILLocation uncurriedLoc = uncurriedSites[0].Loc; - CanType formalResultType = firstLevelResult.formalType.getResult(); + origFormalType = origFormalType.getFunctionResultType(); + CanType formalResultType = formalType.getResult(); // Ignore metatype argument SmallVector metatypeVal; emitPseudoFunctionArguments(SGF, - AbstractionPattern(firstLevelResult.formalType), - firstLevelResult.formalType, metatypeVal, + AbstractionPattern(formalType), + formalType, metatypeVal, std::move(uncurriedSites[0]).forward()); assert(metatypeVal.size() == 1); - origFormalType = origFormalType.getFunctionResultType(); - claimNextParamClause(firstLevelResult.formalType); // Get the payload argument. ArgumentSource payload; @@ -3955,9 +3824,8 @@ CallEmission::applyEnumElementConstructor(SGFContext C) { /*canonicalVararg*/ true); auto arg = RValue(SGF, argVals, payloadTy->getCanonicalType()); payload = ArgumentSource(element, std::move(arg)); - formalResultType = firstLevelResult.formalType.getResult(); + formalResultType = cast(formalResultType).getResult(); origFormalType = origFormalType.getFunctionResultType(); - claimNextParamClause(firstLevelResult.formalType); } else { assert(uncurriedSites.size() == 1); } @@ -3966,90 +3834,27 @@ CallEmission::applyEnumElementConstructor(SGFContext C) { uncurriedLoc, std::move(payload), SGF.getLoweredType(formalResultType), element, uncurriedContext); - firstLevelResult.value = - RValue(SGF, uncurriedLoc, formalResultType, resultMV); - return firstLevelResult; -} - -CallEmission::FirstLevelApplicationResult -CallEmission::applyPartiallyAppliedSuperMethod(SGFContext C) { - FirstLevelApplicationResult firstLevelResult; - - // We want to emit the arguments as fully-substituted values - // because that's what the partially applied super method expects; - firstLevelResult.formalType = callee.getSubstFormalType(); - auto origFormalType = AbstractionPattern(firstLevelResult.formalType); - auto substFnType = SGF.getSILFunctionType( - SGF.getTypeExpansionContext(), origFormalType, firstLevelResult.formalType); - - // Emit the arguments. - SmallVector uncurriedArgs; - Optional uncurriedLoc; - CanFunctionType formalApplyType; - ApplyOptions options = emitArgumentsForNormalApply( - firstLevelResult.formalType, origFormalType, substFnType, - Optional(), firstLevelResult.foreignSelf, - uncurriedArgs, uncurriedLoc, formalApplyType); - (void)options; - - // Emit the uncurried call. - assert(uncurriedArgs.size() == 1 && "Can only partially apply the " - "self parameter of a super " - "method call"); - - auto constant = callee.getMethodName(); - auto loc = uncurriedLoc.getValue(); - auto subs = callee.getSubstitutions(); - auto upcastedSelf = uncurriedArgs.back(); - - // Make sure that upcasted self is at +1 since we are going to place it into a - // partial_apply. - upcastedSelf = upcastedSelf.ensurePlusOne(SGF, loc); - - auto constantInfo = - SGF.getConstantInfo(SGF.getTypeExpansionContext(), callee.getMethodName()); - auto functionTy = constantInfo.getSILType(); - ManagedValue superMethod; - { - ArgumentScope S(SGF, loc); - ManagedValue castValue = - borrowedCastToOriginalSelfType(SGF, loc, upcastedSelf); - if (!constant.isForeign) { - superMethod = SGF.B.createSuperMethod(loc, castValue, constant, - functionTy); - } else { - superMethod = SGF.B.createObjCSuperMethod(loc, castValue, constant, - functionTy); - } - S.pop(); - } - auto calleeConvention = ParameterConvention::Direct_Guaranteed; - - ManagedValue pa = SGF.B.createPartialApply(loc, superMethod, - subs, {upcastedSelf}, - calleeConvention); - firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), pa); - return firstLevelResult; + return RValue(SGF, uncurriedLoc, formalResultType, resultMV); } -CallEmission::FirstLevelApplicationResult +RValue CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, SGFContext C) { - FirstLevelApplicationResult firstLevelResult; - // We use the context emit-into initialization only for the // outermost call. - SGFContext uncurriedContext = (extraSites.empty() ? C : SGFContext()); + SGFContext uncurriedContext = C; ManagedValue mv; // Get the callee type information. We want to emit the arguments as // fully-substituted values because that's what the specialized emitters // expect. - firstLevelResult.formalType = callee.getSubstFormalType(); - auto origFormalType = AbstractionPattern(firstLevelResult.formalType); + auto formalType = callee.getSubstFormalType(); + auto origFormalType = AbstractionPattern(formalType); auto substFnType = SGF.getSILFunctionType( - SGF.getTypeExpansionContext(), origFormalType, firstLevelResult.formalType); + SGF.getTypeExpansionContext(), origFormalType, formalType); + + CanType formalResultType = formalType.getResult(); // If we have an early emitter, just let it take over for the // uncurried call site. @@ -4057,13 +3862,8 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, auto emitter = specializedEmitter.getEarlyEmitter(); assert(uncurriedSites.size() == 1); - CanFunctionType formalApplyType = - cast(firstLevelResult.formalType); - assert(!formalApplyType->getExtInfo().throws()); - CanType formalResultType = formalApplyType.getResult(); + assert(!formalType->getExtInfo().throws()); SILLocation uncurriedLoc = uncurriedSites[0].Loc; - origFormalType = origFormalType.getFunctionResultType(); - claimNextParamClause(firstLevelResult.formalType); // We should be able to enforce that these arguments are // always still expressions. @@ -4071,9 +3871,7 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, ManagedValue resultMV = emitter(SGF, uncurriedLoc, callee.getSubstitutions(), std::move(args), uncurriedContext); - firstLevelResult.value = - RValue(SGF, uncurriedLoc, formalResultType, resultMV); - return firstLevelResult; + return RValue(SGF, uncurriedLoc, formalResultType, resultMV); } Optional resultPlan; @@ -4086,7 +3884,7 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, // result plan/arg scope before we prepare arguments. if (!specializedEmitter.isLateEmitter() && substConv.hasIndirectSILResults()) { - calleeTypeInfo.emplace(callee.getTypeInfo(SGF, false /*isCurried*/)); + calleeTypeInfo.emplace(callee.getTypeInfo(SGF)); calleeTypeInfo->origResultType = origFormalType.getFunctionResultType(); calleeTypeInfo->substResultType = callee.getSubstFormalType().getResult(); @@ -4100,10 +3898,10 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, SmallVector uncurriedArgs; Optional uncurriedLoc; CanFunctionType formalApplyType; - emitArgumentsForNormalApply(firstLevelResult.formalType, origFormalType, - substFnType, Optional(), - firstLevelResult.foreignSelf, uncurriedArgs, - uncurriedLoc, formalApplyType); + ImportAsMemberStatus foreignSelf; + emitArgumentsForNormalApply(origFormalType, substFnType, + Optional(), foreignSelf, + uncurriedArgs, uncurriedLoc); // If we have a late emitter, now that we have emitted our arguments, call the // emitter. @@ -4111,8 +3909,7 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, auto emitter = specializedEmitter.getLateEmitter(); ManagedValue mv = emitter(SGF, loc, callee.getSubstitutions(), uncurriedArgs, uncurriedContext); - firstLevelResult.value = RValue(SGF, loc, formalApplyType.getResult(), mv); - return firstLevelResult; + return RValue(SGF, loc, formalResultType, mv); } // Otherwise, we must have a named builtin. @@ -4156,30 +3953,24 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, // Then finish our value. if (resultPlan.hasValue()) { - firstLevelResult.value = - std::move(*resultPlan) - ->finish(SGF, loc, formalApplyType.getResult(), directResultsFinal); + return std::move(*resultPlan) + ->finish(SGF, loc, formalResultType, directResultsFinal); } else { - firstLevelResult.value = RValue( - SGF, *uncurriedLoc, formalApplyType.getResult(), directResultsFinal[0]); + return RValue( + SGF, *uncurriedLoc, formalResultType, directResultsFinal[0]); } - return firstLevelResult; } ApplyOptions CallEmission::emitArgumentsForNormalApply( - CanFunctionType &formalType, AbstractionPattern &origFormalType, - CanSILFunctionType substFnType, + AbstractionPattern origFormalType, CanSILFunctionType substFnType, const Optional &foreignError, ImportAsMemberStatus foreignSelf, SmallVectorImpl &uncurriedArgs, - Optional &uncurriedLoc, CanFunctionType &formalApplyType) { + Optional &uncurriedLoc) { ApplyOptions options = ApplyOptions::None; SmallVector, 2> args; SmallVector delayedArgs; - auto expectedUncurriedOrigResultFormalType = - getUncurriedOrigFormalResultType(origFormalType, uncurriedSites.size()); - (void)expectedUncurriedOrigResultFormalType; args.reserve(uncurriedSites.size()); { @@ -4202,8 +3993,6 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply( // Collect the arguments to the uncurried call. for (auto &site : uncurriedSites) { - formalApplyType = cast(formalType); - claimNextParamClause(formalType); uncurriedLoc = site.Loc; args.push_back({}); @@ -4222,11 +4011,6 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply( } } assert(uncurriedLoc); - assert(formalApplyType); - assert(origFormalType.getType() == - expectedUncurriedOrigResultFormalType.getType() && - "expectedUncurriedOrigResultFormalType and emitArgumentsForNormalCall " - "are out of sync"); // Emit any delayed arguments: formal accesses to inout arguments, etc. if (!delayedArgs.empty()) { @@ -4249,63 +4033,6 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply( return options; } -RValue CallEmission::applyRemainingCallSites(RValue &&result, - AbstractionPattern origFormalType, - ImportAsMemberStatus foreignSelf, - SGFContext C, - bool formalTypeThrows) { - assert(!extraSites.empty() && - "We should only get here if we actually have extra callsites"); - - // Apply the remaining call sites to the result function. - // Each chained call gets its own writeback scope. - for (unsigned i = 0, size = extraSites.size(); i < size; ++i) { - FormalEvaluationScope writebackScope(SGF); - - SILLocation loc = extraSites[i].Loc; - - auto functionMV = std::move(result).getAsSingleValue(SGF, loc); - - auto substFnType = functionMV.getType().castTo(); - ParamLowering paramLowering(substFnType, SGF); - - SmallVector siteArgs; - SmallVector delayedArgs; - - // TODO: foreign errors for block or function pointer values? - assert(substFnType->hasErrorResult() || formalTypeThrows); - - SGFContext context = i == size - 1 ? C : SGFContext(); - - // Create the callee type info and initialize our indirect results. - CalleeTypeInfo calleeTypeInfo( - substFnType, - origFormalType.getFunctionResultType(), - extraSites[i].getSubstResultType(), - Optional(), - foreignSelf); - ResultPlanPtr resultPtr = - ResultPlanBuilder::computeResultPlan(SGF, calleeTypeInfo, loc, context); - ArgumentScope argScope(SGF, loc); - - std::move(extraSites[i]) - .emit(SGF, origFormalType, substFnType, paramLowering, siteArgs, - delayedArgs, calleeTypeInfo.foreignError, - calleeTypeInfo.foreignSelf); - if (!delayedArgs.empty()) { - emitDelayedArguments(SGF, delayedArgs, siteArgs); - } - - result = SGF.emitApply(std::move(resultPtr), std::move(argScope), loc, - functionMV, {}, siteArgs, calleeTypeInfo, - ApplyOptions::None, context); - - origFormalType = origFormalType.getFunctionResultType(); - } - - return std::move(result); -} - CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) { // Set up writebacks for the call(s). FormalEvaluationScope writebacks(SGF); @@ -4332,26 +4059,20 @@ CallEmission CallEmission::forApplyExpr(SILGenFunction &SGF, ApplyExpr *e) { apply.selfParam.isLValue() ? ParameterTypeFlags().withInOut(true) : ParameterTypeFlags()); - emission.addSelfParam(e, std::move(apply.selfParam), selfParam, - apply.selfType->getCanonicalType()); + emission.addSelfParam(e, std::move(apply.selfParam), selfParam); } - // Apply arguments from call sites, innermost to outermost. - for (auto site = apply.callSites.rbegin(), end = apply.callSites.rend(); - site != end; - ++site) { - ApplyExpr *apply = *site; - - Expr *arg = apply->getArg(); + // Apply arguments from the actual call site. + if (apply.callSite) { + Expr *arg = apply.callSite->getArg(); SmallVector params; AnyFunctionType::decomposeInput(arg->getType(), params); PreparedArguments preparedArgs(params, arg); - emission.addCallSite(apply, std::move(preparedArgs), - apply->getType()->getCanonicalType(), - apply->throws()); + emission.addCallSite(apply.callSite, std::move(preparedArgs), + apply.callSite->throws()); } return emission; @@ -4849,13 +4570,12 @@ SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, auto origFormalType = callee.getOrigFormalType(); auto substFormalType = callee.getSubstFormalType(); - auto calleeTypeInfo = callee.getTypeInfo(*this, /*isCurried=*/false); + auto calleeTypeInfo = callee.getTypeInfo(*this); Optional borrowedSelf; if (callee.requiresSelfValueForDispatch()) borrowedSelf = args.back(); - auto mv = callee.getFnValue(*this, /*isCurried=*/false, - borrowedSelf); + auto mv = callee.getFnValue(*this, borrowedSelf); assert(!calleeTypeInfo.foreignError); assert(!calleeTypeInfo.foreignSelf.isImportAsMember()); @@ -4966,13 +4686,11 @@ RValue SILGenFunction::emitApplyAllocatingInitializer(SILLocation loc, } auto substFormalType = callee->getSubstFormalType(); + auto resultType = cast(substFormalType.getResult()).getResult(); // Form the call emission. CallEmission emission(*this, std::move(*callee), std::move(writebackScope)); - auto methodType = cast(substFormalType.getResult()); - auto resultType = methodType.getResult(); - // Self metatype. emission.addSelfParam(loc, ArgumentSource(loc, @@ -4980,11 +4698,10 @@ RValue SILGenFunction::emitApplyAllocatingInitializer(SILLocation loc, selfMetaVal.getType() .getASTType(), std::move(selfMetaVal))), - substFormalType.getParams()[0], - methodType); + substFormalType.getParams()[0]); // Arguments. - emission.addCallSite(loc, std::move(args), resultType, /*throws*/ false); + emission.addCallSite(loc, std::move(args), /*throws*/ false); // For an inheritable initializer, determine whether we'll need to adjust the // result type. @@ -5052,15 +4769,8 @@ RValue SILGenFunction::emitApplyMethod(SILLocation loc, ConcreteDeclRef declRef, // Form the call emission. CallEmission emission(*this, std::move(*callee), std::move(writebackScope)); - - auto methodType = cast(substFormalType.getResult()); - auto resultType = methodType.getResult(); - - emission.addSelfParam(loc, std::move(self), substFormalType.getParams()[0], - methodType); - - // Arguments. - emission.addCallSite(loc, std::move(args), resultType, /*throws*/ false); + emission.addSelfParam(loc, std::move(self), substFormalType.getParams()[0]); + emission.addCallSite(loc, std::move(args), /*throws*/ false); return emission.apply(C); } @@ -5082,9 +4792,7 @@ RValue SILGenFunction::emitApplyOfPropertyWrapperBackingInitializer( PreparedArguments args(substFnType->getAs()->getParams()); args.add(loc, std::move(originalValue)); - emission.addCallSite(loc, std::move(args), - substFnType->getResult()->getCanonicalType(), - /*throws=*/false); + emission.addCallSite(loc, std::move(args), /*throws=*/false); return emission.apply(C); } @@ -5698,8 +5406,7 @@ RValue SILGenFunction::emitGetAccessor(SILLocation loc, SILDeclRef get, // Self -> if (hasSelf) { emission.addSelfParam(loc, std::move(selfValue), - accessType.getParams()[0], - accessType.getResult()); + accessType.getParams()[0]); accessType = cast(accessType.getResult()); } // Index or () if none. @@ -5707,7 +5414,6 @@ RValue SILGenFunction::emitGetAccessor(SILLocation loc, SILDeclRef get, subscriptIndices.emplace({}); emission.addCallSite(loc, std::move(subscriptIndices), - accessType.getResult(), accessType->throws()); // T @@ -5734,8 +5440,7 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set, // Self -> if (hasSelf) { emission.addSelfParam(loc, std::move(selfValue), - accessType.getParams()[0], - accessType.getResult()); + accessType.getParams()[0]); accessType = cast(accessType.getResult()); } @@ -5752,7 +5457,6 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set, } assert(values.isValid()); emission.addCallSite(loc, std::move(values), - accessType.getResult(), accessType->throws()); // () emission.apply(); @@ -5779,8 +5483,7 @@ ManagedValue SILGenFunction::emitAddressorAccessor( // Self -> if (hasSelf) { emission.addSelfParam(loc, std::move(selfValue), - accessType.getParams()[0], - accessType.getResult()); + accessType.getParams()[0]); accessType = cast(accessType.getResult()); } // Index or () if none. @@ -5788,7 +5491,6 @@ ManagedValue SILGenFunction::emitAddressorAccessor( subscriptIndices.emplace({}); emission.addCallSite(loc, std::move(subscriptIndices), - accessType.getResult(), accessType->throws()); // Unsafe{Mutable}Pointer or @@ -5843,8 +5545,7 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor, // Self -> if (hasSelf) { emission.addSelfParam(loc, std::move(selfValue), - accessType.getParams()[0], - accessType.getResult()); + accessType.getParams()[0]); accessType = cast(accessType.getResult()); } // Index or () if none. @@ -5852,7 +5553,6 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor, subscriptIndices.emplace({}); emission.addCallSite(loc, std::move(subscriptIndices), - accessType.getResult(), accessType->throws()); auto endApplyHandle = emission.applyCoroutine(yields); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index c43126ea39395..0f7f436a816b1 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -907,12 +907,7 @@ emitRValueForDecl(SILLocation loc, ConcreteDeclRef declRef, Type ncRefType, // If the referenced decl isn't a VarDecl, it should be a constant of some // sort. SILDeclRef silDeclRef(decl); - if (silDeclRef.getParameterListCount() == 2) { - // Unqualified reference to an instance method from a static context, - // without applying 'self'. - silDeclRef = silDeclRef.asCurried(); - } - + assert(silDeclRef.getParameterListCount() == 1); ManagedValue result = emitClosureValue(loc, silDeclRef, refType, declRef.getSubstitutions()); return RValue(*this, loc, refType, result); diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 0e6fef4e8be69..d838b9245e1f3 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -652,9 +652,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction void emitClassMemberDestruction(ManagedValue selfValue, ClassDecl *cd, CleanupLocation cleanupLoc); - /// Generates code for a curry thunk from one uncurry level - /// of a function to another. - void emitCurryThunk(SILDeclRef thunk); /// Generates a thunk from a foreign function to the native Swift convention. void emitForeignToNativeThunk(SILDeclRef thunk); /// Generates a thunk from a native function to the conventions. diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index cf937dbe5ddcc..0ae74316397e3 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -88,153 +88,6 @@ SILGenFunction::emitDynamicMethodRef(SILLocation loc, SILDeclRef constant, return ManagedValue::forUnmanaged(B.createFunctionRefFor(loc, F)); } -static std::pair -getNextUncurryLevelRef(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, - ManagedValue selfArg, SubstitutionMap curriedSubs) { - auto *vd = thunk.getDecl(); - - // Reference the next uncurrying level of the function. - SILDeclRef next = SILDeclRef(vd, thunk.kind); - assert(!next.isCurried); - - auto constantInfo = - SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), next); - - // If the function is natively foreign, reference its foreign entry point. - if (requiresForeignToNativeThunk(vd)) - return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), - next}; - - // If the thunk is a curry thunk for a direct method reference, we are - // doing a direct dispatch (eg, a fragile 'super.foo()' call). - if (thunk.isDirectReference) - return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), - next}; - - if (auto *func = dyn_cast(vd)) { - if (getMethodDispatch(func) == MethodDispatch::Class) { - // Use the dynamic thunk if dynamic. - if (vd->isObjCDynamic()) { - return {SGF.emitDynamicMethodRef(loc, next, constantInfo.SILFnType), - next}; - } - - auto methodTy = SGF.SGM.Types.getConstantOverrideType( - SGF.getTypeExpansionContext(), next); - SILValue result = - SGF.emitClassMethodRef(loc, selfArg.getValue(), next, methodTy); - return {ManagedValue::forUnmanaged(result), - next.getOverriddenVTableEntry()}; - } - - // If the fully-uncurried reference is to a generic method, look up the - // witness. - if (constantInfo.SILFnType->getRepresentation() - == SILFunctionTypeRepresentation::WitnessMethod) { - auto protocol = func->getDeclContext()->getSelfProtocolDecl(); - auto origSelfType = protocol->getSelfInterfaceType()->getCanonicalType(); - auto substSelfType = origSelfType.subst(curriedSubs)->getCanonicalType(); - auto conformance = curriedSubs.lookupConformance(origSelfType, protocol); - auto result = SGF.B.createWitnessMethod(loc, substSelfType, conformance, - next, constantInfo.getSILType()); - return {ManagedValue::forUnmanaged(result), next}; - } - } - - // Otherwise, emit a direct call. - return {ManagedValue::forUnmanaged(SGF.emitGlobalFunctionRef(loc, next)), - next}; -} - -void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { - assert(thunk.isCurried); - - auto *vd = thunk.getDecl(); - - if (auto *fd = dyn_cast(vd)) { - assert(!SGM.M.Types.hasLoweredLocalCaptures(SILDeclRef(fd)) && - "methods cannot have captures"); - (void) fd; - } - - SILLocation loc(vd); - Scope S(*this, vd); - - auto thunkInfo = SGM.Types.getConstantInfo(getTypeExpansionContext(), thunk); - auto thunkFnTy = thunkInfo.SILFnType; - SILFunctionConventions fromConv(thunkFnTy, SGM.M); - - auto selfTy = fromConv.getSILType(thunkFnTy->getSelfParameter()); - selfTy = F.mapTypeIntoContext(selfTy); - ManagedValue selfArg = B.createInputFunctionArgument(selfTy, loc); - - // Forward substitutions. - auto subs = F.getForwardingSubstitutionMap(); - - auto toFnAndRef = getNextUncurryLevelRef(*this, loc, thunk, selfArg, subs); - ManagedValue toFn = toFnAndRef.first; - SILDeclRef calleeRef = toFnAndRef.second; - - SILType resultTy = fromConv.getSingleSILResultType(); - resultTy = F.mapTypeIntoContext(resultTy); - - // Partially apply the next uncurry level and return the result closure. - selfArg = selfArg.ensurePlusOne(*this, loc); - auto calleeConvention = ParameterConvention::Direct_Guaranteed; - ManagedValue toClosure = - B.createPartialApply(loc, toFn, subs, {selfArg}, - calleeConvention); - if (resultTy != toClosure.getType()) { - CanSILFunctionType resultFnTy = resultTy.castTo(); - CanSILFunctionType closureFnTy = toClosure.getType().castTo(); - if (resultFnTy->isABICompatibleWith(closureFnTy, F).isCompatible()) { - toClosure = B.createConvertFunction(loc, toClosure, resultTy); - } else { - // Compute the partially-applied abstraction pattern for the callee: - // just grab the pattern for the curried fn ref and "call" it. - assert(!calleeRef.isCurried); - calleeRef.isCurried = true; - auto appliedFnPattern = - SGM.Types.getConstantInfo(getTypeExpansionContext(), calleeRef) - .FormalPattern.getFunctionResultType(); - - auto appliedThunkPattern = - thunkInfo.FormalPattern.getFunctionResultType(); - - // The formal type should be the same for the callee and the thunk. - auto formalType = thunkInfo.FormalType; - if (auto genericSubstType = dyn_cast(formalType)) { - formalType = genericSubstType.substGenericArgs(subs); - } - formalType = cast(formalType.getResult()); - - toClosure = - emitTransformedValue(loc, toClosure, - appliedFnPattern, formalType, - appliedThunkPattern, formalType, - resultTy); - } - } - toClosure = S.popPreservingValue(toClosure); - B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(loc), toClosure); -} - -void SILGenModule::emitCurryThunk(SILDeclRef constant) { - assert(constant.isCurried); - - // Thunks are always emitted by need, so don't need delayed emission. - SILFunction *f = getFunction(constant, ForDefinition); - f->setThunk(IsThunk); - f->setBare(IsBare); - - auto *fd = constant.getDecl(); - preEmitFunction(constant, fd, f, fd); - PrettyStackTraceSILFunction X("silgen emitCurryThunk", f); - - SILGenFunction(*this, *f, SwiftModule).emitCurryThunk(constant); - postEmitFunction(constant, f); -} - void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. assert(!thunk.isForeign && "foreign-to-native thunks only"); @@ -282,7 +135,7 @@ SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, // If the constant is a thunk we haven't emitted yet, emit it. if (!SGM.hasFunction(constant)) { if (constant.isCurried) { - SGM.emitCurryThunk(constant); + llvm_unreachable("Curry thunks should have been built in CSApply"); } else if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0a5809a9ba924..ada24a8461e85 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -483,6 +483,10 @@ namespace { // Handle operator requirements found in protocols. if (auto proto = dyn_cast(decl->getDeclContext())) { + bool isCurried = shouldBuildCurryThunk(choice, + /*baseIsInstance=*/false, + /*extraUncurryLevel=*/false); + // If we have a concrete conformance, build a call to the witness. // // FIXME: This is awful. We should be able to handle this as a call to @@ -494,49 +498,53 @@ namespace { ConformanceCheckFlags::InExpression); if (conformance.isConcrete()) { if (auto witness = conformance.getConcrete()->getWitnessDecl(decl)) { - // The fullType was computed by substituting the protocol - // requirement so it always has a (Self) -> ... curried - // application. Strip it off if the witness was a top-level - // function. - Type refType; - if (witness->getDeclContext()->isTypeContext()) - refType = fullType; - else - refType = fullType->castTo()->getResult(); - - // Build the AST for the call to the witness. - auto subMap = getOperatorSubstitutions(witness, refType); - if (subMap) { - ConcreteDeclRef witnessRef(witness, *subMap); - auto declRefExpr = new (ctx) DeclRefExpr(witnessRef, loc, - /*Implicit=*/false); - declRefExpr->setFunctionRefKind(choice.getFunctionRefKind()); - cs.setType(declRefExpr, refType); - - Expr *refExpr; - if (witness->getDeclContext()->isTypeContext()) { - // If the operator is a type member, add the implicit - // (Self) -> ... call. - Expr *base = - TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, - ctx); - cs.setType(base, MetatypeType::get(baseTy)); - - refExpr = new (ctx) DotSyntaxCallExpr(declRefExpr, - SourceLoc(), base); - auto refType = fullType->castTo()->getResult(); - cs.setType(refExpr, refType); - } else { - refExpr = declRefExpr; + bool isMemberOperator = witness->getDeclContext()->isTypeContext(); + + if (!isMemberOperator || !isCurried) { + // The fullType was computed by substituting the protocol + // requirement so it always has a (Self) -> ... curried + // application. Strip it off if the witness was a top-level + // function. + Type refType; + if (isMemberOperator) + refType = fullType; + else + refType = fullType->castTo()->getResult(); + + // Build the AST for the call to the witness. + auto subMap = getOperatorSubstitutions(witness, refType); + if (subMap) { + ConcreteDeclRef witnessRef(witness, *subMap); + auto declRefExpr = new (ctx) DeclRefExpr(witnessRef, loc, + /*Implicit=*/false); + declRefExpr->setFunctionRefKind(choice.getFunctionRefKind()); + cs.setType(declRefExpr, refType); + + Expr *refExpr; + if (isMemberOperator) { + // If the operator is a type member, add the implicit + // (Self) -> ... call. + Expr *base = + TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, + ctx); + cs.setType(base, MetatypeType::get(baseTy)); + + refExpr = new (ctx) DotSyntaxCallExpr(declRefExpr, + SourceLoc(), base); + auto refType = fullType->castTo()->getResult(); + cs.setType(refExpr, refType); + } else { + refExpr = declRefExpr; + } + + return forceUnwrapIfExpected(refExpr, choice, locator); } - - return forceUnwrapIfExpected(refExpr, choice, locator); } } } } - // Build a reference to the protocol requirement. + // Build a reference to the member. Expr *base = TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, ctx); cs.cacheExprTypes(base); diff --git a/test/SILGen/partial_apply_operator.swift b/test/SILGen/partial_apply_operator.swift new file mode 100644 index 0000000000000..df4c505083c83 --- /dev/null +++ b/test/SILGen/partial_apply_operator.swift @@ -0,0 +1,33 @@ + +// RUN: %target-swift-emit-silgen -module-name partial_apply_protocol -primary-file %s | %FileCheck %s +// RUN: %target-swift-emit-ir -module-name partial_apply_protocol -primary-file %s + +protocol Group { + static func +(_: Self, _: Self) -> Self + static prefix func -(_: Self) -> Self +} + +extension Int : Group {} + +func takesBinaryOp(_: (Int, Int) -> Int) {} +func takesUnaryOp(_: (Int) -> Int) {} + +func takesGenericBinaryOp(_: (T, T) -> T) {} +func takesGenericUnaryOp(_: (T) -> T) {} + +func passOp() { + takesBinaryOp(+) + takesUnaryOp(-) +} + +func passGenericOp(_: T) { + takesGenericBinaryOp(+) + + // FIXME: Rejected by the type checker? rdar://problem/60607396 + // takesGenericUnaryOp(-) +} + +// CHECK-LABEL: sil private [ossa] @$s22partial_apply_protocol6passOpyyFS2i_SitcSimcfu_S2i_Sitcfu0_ : $@convention(thin) (Int, Int, @thin Int.Type) -> Int +// CHECK-LABEL: sil private [ossa] @$s22partial_apply_protocol6passOpyyFS2icSimcfu1_S2icfu2_ : $@convention(thin) (Int, @thin Int.Type) -> Int + +// CHECK-LABEL: sil private [ossa] @$s22partial_apply_protocol13passGenericOpyyxAA5GroupRzlFS2i_SitcSimcfu_S2i_Sitcfu0_ : $@convention(thin) (Int, Int, @thin Int.Type) -> Int \ No newline at end of file