diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8839727a8da..ebcf6657a51 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1548,9 +1548,11 @@ ERROR(ambiguous_decl_ref,tce_sema,none, ERROR(ambiguous_operator_ref,tce_sema,none, "ambiguous use of operator %0", (Identifier)) -ERROR(partial_application_of_method_invalid,tce_sema,none, - "partial application of 'mutating' %select{struct method|enum method|" - "generic method|protocol method}0 is not allowed", +// Cannot capture inout-ness of a parameter +// Partial application of foreign functions not supported +ERROR(partial_application_of_function_invalid,tce_sema,none, + "partial application of %select{function with 'inout' parameters|" + "'mutating' method|method in @objc protocol}0 is not allowed", (unsigned)) ERROR(self_assignment_var,tce_sema,none, diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index ad51e4e6e77..30eaacaf462 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -708,7 +708,7 @@ namespace { static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc, SILDeclRef constant, ArgumentSource &selfValue, - CanAnyFunctionType substAccessorType, + CanAnyFunctionType substFnType, ArrayRef &substitutions) { auto fd = cast(constant.getDecl()); auto protocol = cast(fd->getDeclContext()); @@ -798,8 +798,11 @@ static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc, materializeSelfIfNecessary(); + // The protocol self is implicitly decurried. + substFnType = cast(substFnType.getResult()); + return Callee::forArchetype(gen, openingSite, selfTy, - constant, substAccessorType, loc); + constant, substFnType, loc); } /// An ASTVisitor for building SIL function calls. @@ -915,7 +918,8 @@ public: for (auto callSite : CallSites) { addSite(callSite, false); } - // The self application might be a MemberRefExpr if "self" is an archetype. + + // The self application might be a DynamicMemberRefExpr. if (auto selfApply = dyn_cast_or_null(SelfApplyExpr)) { addSite(selfApply, otherCtorRefUsesAllocating); } @@ -1022,6 +1026,68 @@ public: bool requiresAllocRefDynamic = false; // Determine whether the method is dynamically dispatched. + if (auto *proto = dyn_cast(afd->getDeclContext())) { + // 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 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 just pass in the address since + // archetypes are address-only. + + CanAnyFunctionType substFnType = getSubstFnType(); + assert(!CallSites.empty()); + ApplyExpr *thisCallSite = CallSites.back(); + CallSites.pop_back(); + + ArgumentSource selfValue = thisCallSite->getArg(); + + ArrayRef subs = e->getDeclRef().getSubstitutions(); + + SILDeclRef::Kind kind = SILDeclRef::Kind::Func; + if (isa(afd)) { + if (proto->isObjC()) { + SILLocation loc = thisCallSite->getArg(); + + // For Objective-C initializers, we only have an initializing + // initializer. We need to allocate the object ourselves. + kind = SILDeclRef::Kind::Initializer; + + auto metatype = std::move(selfValue).getAsSingleValue(SGF); + auto allocated = allocateObjCObject(metatype, loc); + auto allocatedType = allocated.getType().getSwiftRValueType(); + selfValue = ArgumentSource(loc, RValue(allocated, allocatedType)); + } else { + // For non-Objective-C initializers, we have an allocating + // initializer to call. + kind = SILDeclRef::Kind::Allocator; + } + } + + SILDeclRef constant = SILDeclRef(afd, kind); + + // Prepare the callee. This can modify both selfValue and subs. + Callee theCallee = prepareArchetypeCallee(SGF, e, constant, selfValue, + substFnType, subs); + + setSelfParam(std::move(selfValue), thisCallSite); + setCallee(std::move(theCallee)); + + // If there are substitutions, add them now. + if (!subs.empty()) { + ApplyCallee->setSubstitutions(SGF, e, subs, CallDepth); + } + + return; + } + if (e->getAccessSemantics() != AccessSemantics::Ordinary) { isDynamicallyDispatched = false; } else { @@ -1222,78 +1288,6 @@ public: 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 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 just pass in the address since - // archetypes are address-only. - - ArgumentSource selfValue = e->getBase(); - - auto *proto = cast(fd->getDeclContext()); - ArrayRef subs = e->getMember().getSubstitutions(); - - // 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; - - auto metatype = std::move(selfValue).getAsSingleValue(SGF); - auto allocated = allocateObjCObject(metatype, e->getBase()); - auto allocatedType = allocated.getType().getSwiftRValueType(); - selfValue = ArgumentSource(e->getBase(), - RValue(allocated, allocatedType)); - - } else { - // For non-Objective-C initializers, we have an allocating - // initializer to call. - kind = SILDeclRef::Kind::Allocator; - } - } - SILDeclRef constant = SILDeclRef(fd, kind); - - // Gross. We won't have any call sites if this is a curried generic method - // application, because it doesn't look like a call site in the AST, but a - // member ref. - CanFunctionType substFnType; - if (!CallSites.empty() || dyn_cast_or_null(SelfApplyExpr)) - substFnType = getSubstFnType(); - else - substFnType = cast(e->getType()->getCanonicalType()); - - // Prepare the callee. This can modify both selfValue and subs. - Callee theCallee = prepareArchetypeCallee(SGF, e, constant, selfValue, - substFnType, subs); - - setSelfParam(std::move(selfValue), e); - setCallee(std::move(theCallee)); - - // If there are substitutions, add them now. - if (!subs.empty()) { - ApplyCallee->setSubstitutions(SGF, e, subs, CallDepth); - } - } - void visitFunctionConversionExpr(FunctionConversionExpr *e) { // FIXME: Check whether this function conversion requires us to build a // thunk. @@ -3451,9 +3445,6 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &gen, assert(!isDirectUse && "direct use of protocol accessor?"); assert(!isSuper && "super call to protocol method?"); - // The protocol self is implicitly decurried. - substAccessorType = cast(substAccessorType.getResult()); - return prepareArchetypeCallee(gen, loc, constant, selfValue, substAccessorType, substitutions); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 565e219a3bb..9692f3abeee 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1803,13 +1803,6 @@ RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *E, SGFContext C) { SGF.B.createMetatype(E, SGF.getLoweredLoadableType(E->getType())); return RValue(SGF, E, ManagedValue::forUnmanaged(MT)); } - - if (isa(E->getMember().getDecl())) { - // Method references into generics are represented as member refs instead - // of apply exprs for some reason. Send this down the correct path to be - // treated as a curried method application. - return SGF.emitApplyExpr(E, C); - } // If we have a nominal type decl as our base, try to use special logic to // emit the base rvalue's member using special logic that will let us avoid diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index b17ff53ace2..2e4557e38ca 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -472,7 +472,7 @@ namespace { locator, locator, implicit, semantics, /*isDynamic=*/false); if (!result) - return nullptr;; + return nullptr; return result; } @@ -967,11 +967,11 @@ namespace { return ref; } - // For types, properties, and members of archetypes, build - // member references. - if (isDependentConformingRef || isa(member) || - isa(member)) { + // For types and properties, build member references. + if (isa(member) || isa(member)) { assert(!dynamicSelfFnType && "Converted type doesn't make sense here"); + assert(baseIsInstance || !member->isInstanceMember()); + auto memberRefExpr = new (context) MemberRefExpr(base, dotLoc, memberRef, memberLoc, Implicit, semantics); @@ -2226,7 +2226,9 @@ namespace { newRef = convertUnavailableToOptional(newRef,decl, expr->getLoc(), choice.getReasonUnavailable(cs)); } - + + recordUnsupportedPartialApply(expr, newRef); + return newRef; } @@ -2360,7 +2362,10 @@ namespace { locator, expr->isSpecialized(), expr->isImplicit(), AccessSemantics::Ordinary); - + + if (auto newDeclRef = dyn_cast(newRef)) + recordUnsupportedPartialApply(newDeclRef, newDeclRef); + if (choice.isPotentiallyUnavailable()) { newRef = convertUnavailableToOptional(newRef, decl, expr->getLoc(), choice.getReasonUnavailable(cs)); @@ -2488,23 +2493,22 @@ namespace { } private: - struct MemberPartialApplication { + // Selector for the partial_application_of_function_invalid diagnostic + // message. + struct PartialApplication { unsigned level : 29; - // Selector for the partial_application_of_method_invalid diagnostic - // message. enum : unsigned { - Struct, - Enum, - Archetype, - Protocol + Function, + MutatingMethod, + ObjCProtocolMethod }; unsigned kind : 3; }; - - // A map used to track partial applications of methods to require that they - // be fully applied. Partial applications of value types would capture - // 'self' as an inout and hide any mutation of 'self', which is surprising. - llvm::SmallDenseMap + + // Partial applications of functions with inout parameters is not permitted, + // so we track them to ensure they are fully applied. The map value is the + // number of remaining applications. + llvm::SmallDenseMap InvalidPartialApplications; /// A list of "suspicious" optional injections that come from @@ -2575,49 +2579,10 @@ namespace { AccessSemantics::Ordinary, isDynamic, reason); - - // If this is an application of a mutating method, - // arrange for us to check that it gets fully applied. - FuncDecl *fn = nullptr; - Optional kind; - if (auto apply = dyn_cast(member)) { - auto selfInoutTy = apply->getArg()->getType()->getAs(); - if (!selfInoutTy) - goto not_mutating_member; - auto selfTy = selfInoutTy->getObjectType(); - auto fnDeclRef = dyn_cast(apply->getFn()); - if (!fnDeclRef) - goto not_mutating_member; - fn = dyn_cast(fnDeclRef->getDecl()); - if (selfTy->getStructOrBoundGenericStruct()) - kind = MemberPartialApplication::Struct; - else if (selfTy->getEnumOrBoundGenericEnum()) - kind = MemberPartialApplication::Enum; - else - goto not_mutating_member; - } else if (auto pmRef = dyn_cast(member)) { - auto baseInoutTy = pmRef->getBase()->getType()->getAs(); - if (!baseInoutTy) - goto not_mutating_member; - auto baseTy = baseInoutTy->getObjectType(); - if (baseTy->getRValueType()->isOpenedExistential()) { - kind = MemberPartialApplication::Protocol; - } else if (baseTy->hasReferenceSemantics()) { - goto not_mutating_member; - } else if (isa(pmRef->getMember().getDecl())) - kind = MemberPartialApplication::Archetype; - else - goto not_mutating_member; - fn = dyn_cast(pmRef->getMember().getDecl()); - } - - if (fn && fn->isInstanceMember()) - InvalidPartialApplications.insert({ - member, - // We need to apply all of the non-self argument clauses. - {fn->getNaturalArgumentCount() - 1, kind.getValue() }, - }); - not_mutating_member: + + if (auto applyExpr = dyn_cast(member)) + advancePartialApplyExpr(applyExpr, applyExpr); + return member; } @@ -2884,29 +2849,107 @@ namespace { llvm_unreachable("Already type-checked"); } + /// If this is an application of a function that cannot be partially + /// applied, arrange for us to check that it gets fully applied. + void recordUnsupportedPartialApply(DeclRefExpr *expr, Expr *fnExpr) { + bool requiresFullApply = false; + unsigned kind; + + auto fn = dyn_cast(expr->getDecl()); + if (!fn) + return; + + // @objc protocol methods cannot be partially applied. + if (auto proto = fn->getDeclContext()->isProtocolOrProtocolExtensionContext()) { + if (proto->isObjC()) { + requiresFullApply = true; + kind = PartialApplication::ObjCProtocolMethod; + } + } + + if (requiresFullApply) { + // We need to apply all argument clauses. + InvalidPartialApplications.insert({ + fnExpr, {fn->getNaturalArgumentCount(), kind} + }); + } + } + + /// If this is an application of a function that cannot be partially + /// applied, arrange for us to check that it gets fully applied. + void recordUnsupportedPartialApply(ApplyExpr *expr, Expr *fnExpr) { + bool requiresFullApply = false; + unsigned kind; + + auto fnDeclRef = dyn_cast(fnExpr); + if (!fnDeclRef) + return; + + recordUnsupportedPartialApply(fnDeclRef, fnExpr); + + auto fn = dyn_cast(fnDeclRef->getDecl()); + if (!fn) + return; + + if (fn->isInstanceMember()) + kind = PartialApplication::MutatingMethod; + else + kind = PartialApplication::Function; + + // Functions with inout parameters cannot be partially applied. + auto argTy = expr->getArg()->getType(); + if (auto tupleTy = argTy->getAs()) { + for (auto eltTy : tupleTy->getElementTypes()) { + if (eltTy->getAs()) { + requiresFullApply = true; + break; + } + } + } else if (argTy->getAs()) { + requiresFullApply = true; + } + + if (requiresFullApply) { + // We need to apply all argument clauses. + InvalidPartialApplications.insert({ + fnExpr, {fn->getNaturalArgumentCount(), kind} + }); + } + } + + /// See if this application advanced a partial value type application. + void advancePartialApplyExpr(ApplyExpr *expr, Expr *result) { + Expr *fnExpr = expr->getFn()->getSemanticsProvidingExpr(); + if (auto forceExpr = dyn_cast(fnExpr)) + fnExpr = forceExpr->getSubExpr()->getSemanticsProvidingExpr(); + if (auto dotSyntaxExpr = dyn_cast(fnExpr)) + fnExpr = dotSyntaxExpr->getRHS(); + + recordUnsupportedPartialApply(expr, fnExpr); + + auto foundApplication = InvalidPartialApplications.find(fnExpr); + if (foundApplication == InvalidPartialApplications.end()) + return; + + unsigned level = foundApplication->second.level; + assert(level > 0); + InvalidPartialApplications.erase(foundApplication); + if (level > 1) { + // We have remaining argument clauses. + InvalidPartialApplications.insert({ + result, {level - 1, foundApplication->second.kind} + }); + } + } + Expr *visitApplyExpr(ApplyExpr *expr) { auto result = finishApply(expr, expr->getType(), ConstraintLocatorBuilder( cs.getConstraintLocator(expr))); - // See if this application advanced a partial value type application. - Expr *fn = expr->getFn()->getSemanticsProvidingExpr(); - if (auto force = dyn_cast(fn)) - fn = force->getSubExpr()->getSemanticsProvidingExpr(); - auto foundApplication = InvalidPartialApplications.find(fn); - if (foundApplication != InvalidPartialApplications.end()) { - unsigned level = foundApplication->second.level; - assert(level > 0); - InvalidPartialApplications.erase(foundApplication); - if (level > 1) - InvalidPartialApplications.insert({ - result, { - level - 1, - foundApplication->second.kind - } - }); - } - + // Record a partial value type application, if necessary. + advancePartialApplyExpr(expr, result); + return result; } @@ -3412,7 +3455,7 @@ namespace { for (auto &unapplied : InvalidPartialApplications) { unsigned kind = unapplied.second.kind; tc.diagnose(unapplied.first->getLoc(), - diag::partial_application_of_method_invalid, + diag::partial_application_of_function_invalid, kind); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 3a61d0666ae..67150cae1d5 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1010,14 +1010,7 @@ void ConstraintSystem::openGeneric( /// declared. static void addSelfConstraint(ConstraintSystem &cs, Type objectTy, Type selfTy, ConstraintLocatorBuilder locator){ - // When referencing a protocol member, we need the object type to be usable - // as the Self type of the protocol, which covers anything that conforms to - // the protocol as well as existentials that include that protocol. - if (selfTy->is()) { - cs.addConstraint(ConstraintKind::SelfObjectOfProtocol, objectTy, selfTy, - cs.getConstraintLocator(locator)); - return; - } + assert(!selfTy->is()); // Otherwise, use a subtype constraint for classes to cope with inheritance. if (selfTy->getClassOrBoundGenericClass()) { diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 9ace6203f18..d400ef2677d 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -126,23 +126,16 @@ protocol P { mutating func mut(x: Int) } -@objc -protocol P2 { - func bar(x: Int) -} - - func generic(var t: T) { _ = t.bar - _ = t.mut // expected-error{{partial application of 'mutating' generic method is not allowed}} + _ = t.mut // expected-error{{partial application of 'mutating' method is not allowed}} var _ : () = t.bar(0) } -func existential(var p: P, p2 : P2) { +func existential(var p: P) { p.mut(1) _ = p.bar - _ = p.mut // expected-error{{partial application of 'mutating' protocol method is not allowed}} - _ = p2.bar + _ = p.mut // expected-error{{partial application of 'mutating' method is not allowed}} var _ : () = p.bar(0) } diff --git a/test/Constraints/members_objc.swift b/test/Constraints/members_objc.swift new file mode 100644 index 00000000000..be724c61f91 --- /dev/null +++ b/test/Constraints/members_objc.swift @@ -0,0 +1,20 @@ +// RUN: %target-parse-verify-swift + +import Swift + +@objc +protocol P2 { + func bar(x: Int) +} + +func existential(p2 : P2) { + _ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}} +} + +func archetype(p2 : T) { + _ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}} +} + +func archetypeMeta(p2 : T) { + _ = T.bar // FIXME: not yet diagnosed +} diff --git a/test/Interpreter/currying_protocols.swift b/test/Interpreter/currying_protocols.swift index 82f5ea7ad26..c6a3e0c3cb6 100644 --- a/test/Interpreter/currying_protocols.swift +++ b/test/Interpreter/currying_protocols.swift @@ -22,3 +22,46 @@ foo(S(offset: 4)) let p : P = S(offset: 4) print("\(p.scale(5)(y: 7))\n", appendNewline: false) // CHECK: 39 + +func culDeSac(t: T) {} +func roundabout(t: T, _ u: T -> ()) { u(t) } + +protocol Proto { + typealias Category + func f(t: Self)(i: Category, j: Category) + static func ff()(i: Category, j: Category) +} + +class Q : Proto { + typealias Category = Int + var q: Int + init(q: Int) { self.q = q } + func f(t: Q)(i: Int, j: Int) { print(q * t.q + i * j) } + static func ff()(i: Int, j: Int) { print(i * j) } +} + +func suburbanJungle(t: T) { + roundabout(T.ff) { $0()(i: 2, j: 10) } + roundabout(T.ff()) { $0(i: 4, j: 10) } + culDeSac(T.ff()(i: 6, j: 10)) + roundabout(T.f) { $0(t)(t)(i: 1, j: 2) } + roundabout(T.f(t)) { $0(t)(i: 3, j: 4) } + roundabout(T.f(t)(t)) { $0(i: 5, j: 6) } + culDeSac(T.f(t)(t)(i: 7, j: 8)) + roundabout(t.f) { $0(t)(i: 9, j: 10) } + roundabout(t.f(t)) { $0(i: 11, j: 12) } + culDeSac(t.f(t)(i: 13, j: 14)) +} + +suburbanJungle(Q(q: 3)) + +// CHECK: 20 +// CHECK: 40 +// CHECK: 60 +// CHECK: 11 +// CHECK: 21 +// CHECK: 39 +// CHECK: 65 +// CHECK: 99 +// CHECK: 141 +// CHECK: 191 diff --git a/test/SILGen/partial_apply_generic.swift b/test/SILGen/partial_apply_generic.swift index 3990a3da11a..ab964c1bc6c 100644 --- a/test/SILGen/partial_apply_generic.swift +++ b/test/SILGen/partial_apply_generic.swift @@ -1,15 +1,64 @@ +// RUN: %target-swift-frontend -emit-silgen %s > /tmp/x.sil // RUN: %target-swift-frontend -emit-silgen %s | FileCheck %s protocol Foo { - static func foo() + static func staticFunc() + func instanceFunc() } -func getFoo(t: T.Type) -> () -> () { - return t.foo +// CHECK-LABEL: sil hidden @_TF21partial_apply_generic14getStaticFunc1uRq_S_3Foo_FMq_FT_T_ +func getStaticFunc1(t: T.Type) -> () -> () { +// CHECK: [[REF:%.*]] = function_ref @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_ +// CHECK-NEXT: apply [[REF]](%0) + return t.staticFunc +// CHECK-NEXT: return } -// CHECK-LABEL: sil hidden @_TF21partial_apply_generic6getFoouRq_S_3Foo_FMq_FT_T_ -// CHECK: function_ref @_TZFP21partial_apply_generic3Foo3foouRq_S0__FMq_FT_T_ +// CHECK-LABEL: sil shared @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_ +// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.staticFunc!1 +// CHECK-NEXT: partial_apply [[REF]](%0) +// CHECK-NEXT: return + +// CHECK-LABEL: sil hidden @_TF21partial_apply_generic14getStaticFunc2uRq_S_3Foo_Fq_FT_T_ +func getStaticFunc2(t: T) -> () -> () { +// CHECK: [[REF:%.*]] = function_ref @_TZFP21partial_apply_generic3Foo10staticFuncuRq_S0__FMq_FT_T_ +// CHECK: apply [[REF]] + return T.staticFunc +// CHECK-NEXT: destroy_addr %0 : $*T +// CHECK-NEXT: return +} + +// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc1uRq_S_3Foo_Fq_FT_T_ +func getInstanceFunc1(t: T) -> () -> () { +// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_ +// CHECK-NEXT: alloc_stack $T +// CHECK-NEXT: copy_addr %0 to [initialization] +// CHECK-NEXT: apply [[REF]] + return t.instanceFunc +// CHECK-NEXT: dealloc_stack +// CHECK-NEXT: destroy_addr %0 : $*T +// CHECK-NEXT: return +} + +// CHECK-LABEL: sil shared @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_ +// CHECK: [[REF:%.*]] = witness_method $Self, #Foo.instanceFunc!1 +// CHECK-NEXT: partial_apply [[REF]](%0) +// CHECK-NEXT: return + +// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc2uRq_S_3Foo_Fq_Fq_FT_T_ +func getInstanceFunc2(t: T) -> (T) -> () -> () { +// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_ +// CHECK-NEXT: partial_apply [[REF]]( + return T.instanceFunc +// CHECK-NEXT: destroy_addr %0 : $* +// CHECK-NEXT: return +} + +// CHECK-LABEL: sil hidden @_TF21partial_apply_generic16getInstanceFunc3uRq_S_3Foo_FMq_Fq_FT_T_ +func getInstanceFunc3(t: T.Type) -> (T) -> () -> () { +// CHECK: [[REF:%.*]] = function_ref @_TFP21partial_apply_generic3Foo12instanceFuncuRq_S0__Fq_FT_T_ +// CHECK-NEXT: partial_apply [[REF]]( + return t.instanceFunc +// CHECK-NEXT: return +} -// CHECK-LABEL: sil shared @_TZFP21partial_apply_generic3Foo3foouRq_S0__FMq_FT_T_ -// CHECK: witness_method $Self, #Foo.foo!1 diff --git a/test/expr/capture/inout.swift b/test/expr/capture/inout.swift index 36ab642fb0e..9fce019a18d 100644 --- a/test/expr/capture/inout.swift +++ b/test/expr/capture/inout.swift @@ -6,3 +6,12 @@ func foo(inout x: Int) { return x } } + +// But not partially applied. +func curriedFoo(inout x: Int)(y: Int) -> Int { + return x + y +} + +var score: Int = 0 + +_ = curriedFoo(&score) // expected-error {{partial application of function with 'inout' parameters is not allowed}}