Skip to content

Commit 478e1c7

Browse files
committed
Partial application of @objc protocol methods
1 parent 840c34f commit 478e1c7

File tree

7 files changed

+113
-52
lines changed

7 files changed

+113
-52
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1849,7 +1849,6 @@ ERROR(partial_application_of_function_invalid,tce_sema,none,
18491849
"partial application of %select{"
18501850
"function with 'inout' parameters|"
18511851
"'mutating' method|"
1852-
"method in @objc protocol|"
18531852
"'super.init' initializer chain|"
18541853
"'self.init' initializer delegation"
18551854
"}0 is not allowed",

lib/SIL/SILDeclRef.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,11 @@ bool SILDeclRef::isForeignToNativeThunk() const {
336336
// Otherwise, match whether we have a clang node with whether we're foreign.
337337
if (isa<FuncDecl>(getDecl()) && getDecl()->hasClangNode())
338338
return !isForeign;
339+
// Objective-C protocol methods also require a foreign to native thunk.
340+
auto dc = getDecl()->getDeclContext();
341+
if (auto proto = dyn_cast<ProtocolDecl>(dc))
342+
if (proto->isObjC())
343+
return !isForeign;
339344
// ObjC initializing constructors and factories are foreign.
340345
// We emit a special native allocating constructor though.
341346
if (isa<ConstructorDecl>(getDecl())

lib/SILGen/SILGenBridging.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -968,14 +968,30 @@ getThunkedForeignFunctionRef(SILGenFunction &gen,
968968
SILLocation loc,
969969
SILDeclRef foreign,
970970
ArrayRef<ManagedValue> args,
971+
ArrayRef<Substitution> subs,
971972
const SILConstantInfo &foreignCI) {
972973
assert(!foreign.isCurried
973974
&& "should not thunk calling convention when curried");
974975

975-
// Produce a class_method when thunking ObjC methods.
976-
auto foreignTy = foreignCI.SILFnType;
977-
if (foreignTy->getRepresentation()
976+
// Produce a witness_method when thunking ObjC protocol methods.
977+
auto dc = foreign.getDecl()->getDeclContext();
978+
if (isa<ProtocolDecl>(dc) && cast<ProtocolDecl>(dc)->isObjC()) {
979+
assert(subs.size() == 1);
980+
auto thisType = subs[0].getReplacement()->getCanonicalType();
981+
assert(isa<ArchetypeType>(thisType) && "no archetype for witness?!");
982+
SILValue thisArg = args.back().getValue();
983+
984+
SILValue OpenedExistential;
985+
if (!cast<ArchetypeType>(thisType)->getOpenedExistentialType().isNull())
986+
OpenedExistential = thisArg;
987+
return gen.B.createWitnessMethod(loc, thisType, nullptr, foreign,
988+
foreignCI.getSILType(),
989+
OpenedExistential);
990+
991+
// Produce a class_method when thunking imported ObjC methods.
992+
} else if (foreignCI.SILFnType->getRepresentation()
978993
== SILFunctionTypeRepresentation::ObjCMethod) {
994+
assert(subs.empty());
979995
SILValue thisArg = args.back().getValue();
980996

981997
return gen.B.createClassMethod(loc, thisArg, foreign,
@@ -1101,12 +1117,19 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
11011117
maybeAddForeignErrorArg();
11021118

11031119
// Call the original.
1104-
auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args,
1120+
auto subs = getForwardingSubstitutions();
1121+
auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, subs,
11051122
foreignCI);
1106-
result = emitMonomorphicApply(fd, ManagedValue::forUnmanaged(fn),
1107-
args,
1108-
nativeFormalResultTy,
1109-
ApplyOptions::None, None, foreignError)
1123+
1124+
auto fnType = fn.getType().castTo<SILFunctionType>();
1125+
fnType = fnType->substGenericArgs(SGM.M, SGM.SwiftModule, subs);
1126+
1127+
result = emitApply(fd, ManagedValue::forUnmanaged(fn),
1128+
subs, args, fnType,
1129+
AbstractionPattern(nativeFormalResultTy),
1130+
nativeFormalResultTy,
1131+
ApplyOptions::None, None, foreignError,
1132+
SGFContext())
11101133
.forward(*this);
11111134
}
11121135
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(fd), result);

lib/SILGen/SILGenFunction.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,16 @@ SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc,
146146
constant.uncurryLevel + 1);
147147
// If the function is fully uncurried and natively foreign, reference its
148148
// foreign entry point.
149-
if (!next.isCurried && vd->hasClangNode())
150-
next = next.asForeign();
149+
if (!next.isCurried) {
150+
if (vd->hasClangNode())
151+
next = next.asForeign();
152+
153+
// Objective-C protocol methods also require a foreign to native thunk.
154+
auto dc = vd->getDeclContext();
155+
if (auto proto = dyn_cast<ProtocolDecl>(dc))
156+
if (proto->isObjC())
157+
next = next.asForeign();
158+
}
151159

152160
// Preserve whether the curry thunks lead to a direct reference to the
153161
// method implementation.

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
115115
enum : unsigned {
116116
Function,
117117
MutatingMethod,
118-
ObjCProtocolMethod,
119118
SuperInit,
120119
SelfInit,
121120
};
@@ -136,32 +135,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
136135
}
137136
}
138137

139-
/// If this is an application of a function that cannot be partially
140-
/// applied, arrange for us to check that it gets fully applied.
141-
void recordUnsupportedPartialApply(DeclRefExpr *expr) {
142-
bool requiresFullApply = false;
143-
unsigned kind;
144-
145-
auto fn = dyn_cast<FuncDecl>(expr->getDecl());
146-
if (!fn)
147-
return;
148-
149-
// @objc protocol methods cannot be partially applied.
150-
if (auto proto = fn->getDeclContext()->isProtocolOrProtocolExtensionContext()) {
151-
if (proto->isObjC()) {
152-
requiresFullApply = true;
153-
kind = PartialApplication::ObjCProtocolMethod;
154-
}
155-
}
156-
157-
if (requiresFullApply) {
158-
// We need to apply all argument clauses.
159-
InvalidPartialApplications.insert({
160-
expr, {fn->getNaturalArgumentCount(), kind}
161-
});
162-
}
163-
}
164-
165138
/// If this is an application of a function that cannot be partially
166139
/// applied, arrange for us to check that it gets fully applied.
167140
void recordUnsupportedPartialApply(ApplyExpr *expr, Expr *fnExpr) {
@@ -181,8 +154,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
181154
if (!fnDeclRef)
182155
return;
183156

184-
recordUnsupportedPartialApply(fnDeclRef);
185-
186157
auto fn = dyn_cast<FuncDecl>(fnDeclRef->getDecl());
187158
if (!fn)
188159
return;
@@ -203,11 +174,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
203174
/// This method is called in post-order over the AST to validate that
204175
/// methods are fully applied when they can't support partial application.
205176
void checkInvalidPartialApplication(Expr *E) {
206-
if (auto DRE = dyn_cast<DeclRefExpr>(E)) {
207-
recordUnsupportedPartialApply(DRE);
208-
return;
209-
}
210-
211177
if (auto AE = dyn_cast<ApplyExpr>(E)) {
212178
Expr *fnExpr = AE->getFn()->getSemanticsProvidingExpr();
213179
if (auto forceExpr = dyn_cast<ForceValueExpr>(fnExpr))

test/Constraints/members_objc.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import Swift
55
@objc
66
protocol P2 {
77
func bar(x: Int)
8+
static func pub(x: Int)
89
}
910

1011
func existential(p2 : P2) {
11-
_ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}}
12+
_ = p2.bar
13+
_ = P2.bar
1214
}
1315

1416
func archetype<T: P2>(p2 : T) {
15-
_ = p2.bar // expected-error{{partial application of method in @objc protocol is not allowed}}
16-
}
17-
18-
func archetypeMeta<T: P2>(p2 : T) {
19-
_ = T.bar // expected-error {{partial application of method in @objc protocol is not allowed}}
17+
_ = p2.bar
18+
_ = T.bar
19+
_ = T.pub
2020
}
2121

2222
// rdar://problem/22012606 - test applications of subscript members of class-constrained protocols
@@ -31,4 +31,4 @@ func archetypeMeta<T: P2>(p2 : T) {
3131
func test_subject_ClassConstrainedSubscript() {
3232
let list: subject_ClassConstrainedSubscript! = test_HasSubscript()
3333
list[0]
34-
}
34+
}

test/SILGen/objc_protocols.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import objc_protocols_Bas
1010
func copyRuncing() -> NSObject
1111

1212
func foo()
13+
14+
static func mince() -> NSObject
1315
}
1416

1517
@objc protocol NSFunging {
@@ -37,6 +39,47 @@ func objc_generic<T : NSRuncing>(x: T) -> (NSObject, NSObject) {
3739
// CHECK: release [[THIS2]]
3840
}
3941

42+
func objc_generic_partial_apply<T : NSRuncing>(x: T) {
43+
// CHECK: [[FN:%.*]] = function_ref @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
44+
// CHECK-NEXT: strong_retain %0
45+
// CHECK-NEXT: [[METHOD:%.*]] = apply [[FN]]<T>(%0)
46+
// CHECK-NEXT: strong_release [[METHOD]]
47+
_ = x.runce
48+
49+
// CHECK: [[FN:%.*]] = function_ref @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
50+
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]]<T>()
51+
// CHECK-NEXT: strong_release [[METHOD]]
52+
_ = T.runce
53+
54+
// CHECK: [[FN:%.*]] = function_ref @_TTOZFP14objc_protocols9NSRuncing5minceFT_CSo8NSObject
55+
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick T.Type
56+
// CHECK-NEXT: [[METHOD:%.*]] = apply [[FN]]<T>([[METATYPE]])
57+
// CHECK-NEXT: strong_release [[METHOD:%.*]]
58+
_ = T.mince
59+
}
60+
61+
// CHECK-LABEL: sil shared @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
62+
// CHECK: [[FN:%.*]] = function_ref @_TTOFP14objc_protocols9NSRuncing5runcefT_CSo8NSObject
63+
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]]<Self>(%0)
64+
// CHECK-NEXT: return [[METHOD]]
65+
66+
// CHECK-LABEL: sil shared @_TTOFP14objc_protocols9NSRuncing5runcefT_CSo8NSObject
67+
// CHECK: strong_retain %0
68+
// CHECK-NEXT: [[FN:%.*]] = witness_method $Self, #NSRuncing.runce!1.foreign
69+
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Self>(%0)
70+
// CHECK-NEXT: strong_release %0
71+
// CHECK-NEXT: return [[RESULT]]
72+
73+
// CHECK-LABEL: sil shared @_TTOZFP14objc_protocols9NSRuncing5minceFT_CSo8NSObject
74+
// CHECK: [[FN:%.*]] = function_ref @_TTOZFP14objc_protocols9NSRuncing5mincefT_CSo8NSObject
75+
// CHECK-NEXT: [[METHOD:%.*]] = partial_apply [[FN]]<Self>(%0)
76+
// CHECK-NEXT: return [[METHOD]]
77+
78+
// CHECK-LABEL: sil shared @_TTOZFP14objc_protocols9NSRuncing5mincefT_CSo8NSObject
79+
// CHECK: [[FN:%.*]] = witness_method $Self, #NSRuncing.mince!1.foreign
80+
// CHECK-NEXT: [[RESULT:%.*]] = apply [[FN]]<Self>(%0)
81+
// CHECK-NEXT: return [[RESULT]]
82+
4083
// CHECK-LABEL: sil hidden @_TF14objc_protocols13objc_protocol
4184
func objc_protocol(x: NSRuncing) -> (NSObject, NSObject) {
4285
return (x.runce(), x.copyRuncing())
@@ -54,6 +97,19 @@ func objc_protocol(x: NSRuncing) -> (NSObject, NSObject) {
5497
// CHECK: release [[THIS2_ORIG]]
5598
}
5699

100+
func objc_protocol_partial_apply(x: NSRuncing) {
101+
// CHECK: [[THIS1:%.*]] = open_existential_ref %0 : $NSRuncing to $[[OPENED:@opened(.*) NSRuncing]]
102+
// CHECK: [[FN:%.*]] = function_ref @_TTOFP14objc_protocols9NSRuncing5runceFT_CSo8NSObject
103+
// CHECK: strong_retain [[THIS1]]
104+
// CHECK: [[RESULT:%.*]] = apply [[FN]]<[[OPENED]]>([[THIS1]])
105+
// CHECK: strong_release [[RESULT]]
106+
// CHECK: strong_release %0
107+
_ = x.runce
108+
109+
// FIXME: rdar://21289579
110+
// _ = NSRuncing.runce
111+
}
112+
57113
// CHECK-LABEL: sil hidden @_TF14objc_protocols25objc_protocol_composition
58114
func objc_protocol_composition(x: protocol<NSRuncing, NSFunging>) {
59115
// CHECK: [[THIS:%.*]] = open_existential_ref [[THIS_ORIG:%.*]] : $protocol<NSFunging, NSRuncing> to $[[OPENED:@opened(.*) protocol<NSFunging, NSRuncing>]]
@@ -73,6 +129,8 @@ class Foo : NSRuncing, NSFunging, Ansible {
73129
@objc func runce() -> NSObject { return NSObject() }
74130
@objc func copyRuncing() -> NSObject { return NSObject() }
75131

132+
@objc static func mince() -> NSObject { return NSObject() }
133+
76134
// -- NSFunging
77135
@objc func funge() {}
78136

@@ -95,6 +153,7 @@ extension Bar : NSRuncing {
95153
@objc func runce() -> NSObject { return NSObject() }
96154
@objc func copyRuncing() -> NSObject { return NSObject() }
97155
@objc func foo() {}
156+
@objc static func mince() -> NSObject { return NSObject() }
98157
}
99158

100159
// CHECK-LABEL: sil hidden [thunk] @_TToFC14objc_protocols3Bar5runce
@@ -106,6 +165,7 @@ extension Bas : NSRuncing {
106165
// runce() implementation from the original definition of Bas
107166
@objc func copyRuncing() -> NSObject { return NSObject() }
108167
@objc func foo() {}
168+
@objc static func mince() -> NSObject { return NSObject() }
109169
}
110170

111171
// CHECK-LABEL: sil hidden [thunk] @_TToFE14objc_protocolsC18objc_protocols_Bas3Bas11copyRuncing

0 commit comments

Comments
 (0)