Skip to content

Commit 0ca496c

Browse files
authored
Merge pull request #13137 from rjmccall/bridging-peephole-blocks-and-optionality
Fix a compatibility suite regression involving the bridging peephole
2 parents 53bb5ea + ad0f8ab commit 0ca496c

File tree

7 files changed

+57
-3
lines changed

7 files changed

+57
-3
lines changed

lib/SILGen/SILGenBridging.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,14 @@ static ManagedValue emitNativeToCBridgedNonoptionalValue(SILGenFunction &SGF,
665665
// The destination type should be AnyObject in this case.
666666
assert(bridgedType->isEqual(SGF.getASTContext().getAnyObjectType()));
667667

668+
// Blocks bridge to id with a cast.
669+
if (auto nativeFnType = dyn_cast<AnyFunctionType>(nativeType)) {
670+
if (nativeFnType->getRepresentation() ==
671+
FunctionTypeRepresentation::Block) {
672+
return SGF.B.createBlockToAnyObject(loc, v, loweredBridgedTy);
673+
}
674+
}
675+
668676
// If the input argument is known to be an existential, save the runtime
669677
// some work by opening it.
670678
if (nativeType->isExistentialType()) {

lib/SILGen/SILGenBuilder.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,18 @@ ManagedValue SILGenBuilder::createBridgeObjectToRef(SILLocation loc,
723723
return cloner.clone(result);
724724
}
725725

726+
ManagedValue SILGenBuilder::createBlockToAnyObject(SILLocation loc,
727+
ManagedValue v,
728+
SILType destType) {
729+
assert(destType.isAnyObject());
730+
assert(v.getType().is<SILFunctionType>());
731+
assert(v.getType().castTo<SILFunctionType>()->getRepresentation() ==
732+
SILFunctionTypeRepresentation::Block);
733+
734+
// For now, we don't have a better instruction than this.
735+
return createUncheckedRefCast(loc, v, destType);
736+
}
737+
726738
BranchInst *SILGenBuilder::createBranch(SILLocation loc,
727739
SILBasicBlock *targetBlock,
728740
ArrayRef<ManagedValue> args) {

lib/SILGen/SILGenBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ class SILGenBuilder : public SILBuilder {
302302
ManagedValue createOpenExistentialBoxValue(SILLocation loc,
303303
ManagedValue original, SILType type);
304304

305+
/// Convert a @convention(block) value to AnyObject.
306+
ManagedValue createBlockToAnyObject(SILLocation loc, ManagedValue block,
307+
SILType type);
308+
305309
using SILBuilder::createOptionalSome;
306310
ManagedValue createOptionalSome(SILLocation Loc, ManagedValue Arg);
307311
ManagedValue createManagedOptionalNone(SILLocation Loc, SILType Type);

lib/SILGen/SILGenConvert.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,14 @@ static bool isValueToAnyConversion(CanType from, CanType to) {
12611261
}
12621262

12631263
assert(to->isAny());
1264-
return !from->isAnyClassReferenceType();
1264+
1265+
// Types that we can easily transform into AnyObject:
1266+
// - classes and class-bounded archetypes
1267+
// - class existentials, even if not pure-@objc
1268+
// - @convention(objc) metatypes
1269+
// - @convention(block) functions
1270+
return !from->isAnyClassReferenceType() &&
1271+
!from->isBridgeableObjectType();
12651272
}
12661273

12671274
/// Check whether this conversion is Any??? to AnyObject???. If the result
@@ -1275,7 +1282,7 @@ static bool isMatchedAnyToAnyObjectConversion(CanType from, CanType to) {
12751282
}
12761283

12771284
if (from->isAny()) {
1278-
assert(to->isAnyObject());
1285+
assert(to->lookThroughAllAnyOptionalTypes()->isAnyObject());
12791286
return true;
12801287
}
12811288
return false;

lib/SILGen/SILGenPoly.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,14 @@ ManagedValue Transform::transform(ManagedValue v,
523523
SGF.getLoweredLoadableType(outputSubstType));
524524
}
525525

526+
// - block to AnyObject conversion
527+
if (outputSubstType->isAnyObject()) {
528+
if (auto inputFnType = dyn_cast<AnyFunctionType>(inputSubstType)) {
529+
if (inputFnType->getRepresentation() == FunctionTypeRepresentation::Block)
530+
return SGF.B.createBlockToAnyObject(Loc, v, loweredResultTy);
531+
}
532+
}
533+
526534
// - existentials
527535
if (outputSubstType->isAnyExistentialType()) {
528536
// We have to re-abstract payload if its a metatype or a function

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,3 +1142,4 @@ void install_global_event_handler(_Nullable event_handler handler);
11421142
@end
11431143

11441144
__nullable id returnNullableId(void);
1145+
void takeNullableId(__nullable id);

test/SILGen/objc_bridging_peephole.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,11 +651,25 @@ func foo(p: P) {
651651

652652
// rdar://35402853
653653
// Make sure that we don't peephole AnyObject? -> Any? -> AnyObject naively.
654-
// CHECK: sil hidden @_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF
654+
// CHECK-LABEL: sil hidden @_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF
655655
func testOptionalToNonOptionalBridge() {
656656
// CHECK: apply {{.*}}() : $@convention(c) () -> @autoreleased Optional<AnyObject>
657657
// CHECK: function_ref @_T0s018_bridgeAnyObjectToB0ypyXlSgF :
658658
// CHECK: [[T0:%.*]] = function_ref @_T0Sq19_bridgeToObjectiveCyXlyF
659659
// CHECK: apply [[T0]]<Any>
660660
useAnyObject(returnNullableId() as AnyObject)
661661
} // CHECK: end sil function '_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF'
662+
663+
// CHECK-LABEL: sil hidden @_T022objc_bridging_peephole34testBlockToOptionalAnyObjectBridgeyyyXB5block_tF
664+
func testBlockToOptionalAnyObjectBridge(block: @escaping @convention(block) () -> ()) {
665+
// CHECK: [[T0:%.*]] = begin_borrow {{%.*}} : $@convention(block) () -> ()
666+
// CHECK-NEXT: [[T1:%.*]] = copy_value [[T0]]
667+
// CHECK-NEXT: [[REF:%.*]] = unchecked_ref_cast [[T1]] : $@convention(block) () -> () to $AnyObject
668+
// CHECK-NEXT: [[OPTREF:%.*]] = enum $Optional<AnyObject>, #Optional.some!enumelt.1, [[REF]] : $AnyObject
669+
// CHECK-NEXT: end_borrow [[T0]]
670+
// CHECK-NEXT: // function_ref
671+
// CHECK-NEXT: [[FN:%.*]] = function_ref @takeNullableId : $@convention(c) (Optional<AnyObject>) -> ()
672+
// CHECK-NEXT: apply [[FN]]([[OPTREF]])
673+
// CHECK-NEXT: destroy_value [[OPTREF]]
674+
takeNullableId(block as Any)
675+
}

0 commit comments

Comments
 (0)