Skip to content

Commit c23b9a4

Browse files
committed
SILGen: Handle key paths with @objc optional property components
1 parent b68457b commit c23b9a4

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2843,13 +2843,27 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
28432843
auto subscriptIndices =
28442844
loadIndexValuesForKeyPathComponent(subSGF, loc, property,
28452845
indexes, indexPtrArg);
2846-
2847-
auto resultSubst = subSGF.emitRValueForStorageLoad(loc, baseSubstValue,
2848-
baseType, /*super*/false,
2849-
property, std::move(subscriptIndices),
2850-
subs, AccessSemantics::Ordinary,
2851-
propertyType, SGFContext())
2852-
.getAsSingleValue(subSGF, loc);
2846+
2847+
ManagedValue resultSubst;
2848+
{
2849+
RValue resultRValue;
2850+
2851+
// Emit a dynamic method branch if the storage decl is an @objc optional
2852+
// requirement, or just a load otherwise.
2853+
if (property->getAttrs().hasAttribute<OptionalAttr>() &&
2854+
isa<VarDecl>(property)) {
2855+
resultRValue = subSGF.emitDynamicMemberRef(
2856+
loc, baseSubstValue.getValue(), ConcreteDeclRef(property, subs),
2857+
propertyType, SGFContext());
2858+
} else {
2859+
resultRValue = subSGF.emitRValueForStorageLoad(
2860+
loc, baseSubstValue, baseType, /*super*/ false, property,
2861+
std::move(subscriptIndices), subs, AccessSemantics::Ordinary,
2862+
propertyType, SGFContext());
2863+
}
2864+
resultSubst = std::move(resultRValue).getAsSingleValue(subSGF, loc);
2865+
}
2866+
28532867
if (resultSubst.getType().getAddressType() != resultArg->getType())
28542868
resultSubst = subSGF.emitSubstToOrigValue(loc, resultSubst,
28552869
AbstractionPattern::getOpaque(),
@@ -3561,6 +3575,12 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
35613575
->mapTypeOutOfContext()
35623576
->getCanonicalType(
35633577
genericEnv ? genericEnv->getGenericSignature() : nullptr);
3578+
3579+
// The component type for an @objc optional requirement needs to be
3580+
// wrapped in an optional.
3581+
if (var->getAttrs().hasAttribute<OptionalAttr>()) {
3582+
componentTy = OptionalType::get(componentTy)->getCanonicalType();
3583+
}
35643584
}
35653585

35663586
if (canStorageUseStoredKeyPathComponent(var, expansion)) {

test/SILGen/keypaths_objc.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,21 @@ func dynamicMemberLookupMixedKeypaths(foo: DynamicClass<Foo>) {
156156
// CHECK: keypath $KeyPath<Foo, NonObjC>, (root
157157
// CHECK: keypath $KeyPath<NonObjC, NSObject>, (root
158158
_ = foo.bar.foo.nonobjc.y
159-
}
159+
}
160+
161+
@objc protocol ObjCProtoOptional {
162+
@objc optional var optionalProperty: Bool { get }
163+
}
164+
165+
// CHECK-LABEL: sil hidden [ossa] @{{.*}}0B28ProtocolOptionalRequirementsyyF
166+
// CHECK: keypath $KeyPath<ObjCProtoOptional, Optional<Bool>>, (objc "optionalProperty"; root $ObjCProtoOptional; gettable_property $Optional<Bool>, id #ObjCProtoOptional.optionalProperty!getter.foreign : <Self where Self : ObjCProtoOptional> (Self) -> () -> Bool, getter @$[[PROP_GETTER:[_a-zA-Z0-9]+]]
167+
// CHECK: } // end sil function '${{.*}}0B28ProtocolOptionalRequirementsyyF'
168+
//
169+
// CHECK: sil shared [thunk] [ossa] @$[[PROP_GETTER]] : $@convention(thin) (@in_guaranteed ObjCProtoOptional) -> @out Optional<Bool> {
170+
// CHECK: [[BASE:%[0-9]+]] = open_existential_ref {{%[0-9]+}} : $ObjCProtoOptional to $[[OPENED_TY:@opened\("[-A-F0-9]+"\) ObjCProtoOptional]]
171+
// CHECK: dynamic_method_br [[BASE]] : $[[OPENED_TY]], #ObjCProtoOptional.optionalProperty!getter.foreign, bb1
172+
// CHECK: bb1({{%[0-9]+}} : $@convention(objc_method) ([[OPENED_TY]]) -> ObjCBool)
173+
// CHECK: } // end sil function '$[[PROP_GETTER]]'
174+
func objcProtocolOptionalRequirements() {
175+
_ = \ObjCProtoOptional.optionalProperty
176+
}

0 commit comments

Comments
 (0)