Merge pull request #13207 from rjmccall/bridging-peephole-blocks-and-optionality-4.1
[4.1] Weaken an assertion: conversions can go through Any
diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp
index 5cb229c..7de2c5d 100644
--- a/lib/SILGen/SILGenBridging.cpp
+++ b/lib/SILGen/SILGenBridging.cpp
@@ -665,6 +665,14 @@
// The destination type should be AnyObject in this case.
assert(bridgedType->isEqual(SGF.getASTContext().getAnyObjectType()));
+ // Blocks bridge to id with a cast.
+ if (auto nativeFnType = dyn_cast<AnyFunctionType>(nativeType)) {
+ if (nativeFnType->getRepresentation() ==
+ FunctionTypeRepresentation::Block) {
+ return SGF.B.createBlockToAnyObject(loc, v, loweredBridgedTy);
+ }
+ }
+
// If the input argument is known to be an existential, save the runtime
// some work by opening it.
if (nativeType->isExistentialType()) {
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index 4411825..83e7ea1 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -714,6 +714,18 @@
return ManagedValue::forUnmanaged(v);
}
+ManagedValue SILGenBuilder::createBlockToAnyObject(SILLocation loc,
+ ManagedValue v,
+ SILType destType) {
+ assert(destType.isAnyObject());
+ assert(v.getType().is<SILFunctionType>());
+ assert(v.getType().castTo<SILFunctionType>()->getRepresentation() ==
+ SILFunctionTypeRepresentation::Block);
+
+ // For now, we don't have a better instruction than this.
+ return createUncheckedRefCast(loc, v, destType);
+}
+
//===----------------------------------------------------------------------===//
// Switch Enum Builder
//===----------------------------------------------------------------------===//
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index 29ddeac..dc1697e 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -291,6 +291,10 @@
ManagedValue createOpenExistentialBoxValue(SILLocation loc,
ManagedValue original, SILType type);
+ /// Convert a @convention(block) value to AnyObject.
+ ManagedValue createBlockToAnyObject(SILLocation loc, ManagedValue block,
+ SILType type);
+
using SILBuilder::createOptionalSome;
ManagedValue createOptionalSome(SILLocation Loc, ManagedValue Arg);
ManagedValue createManagedOptionalNone(SILLocation Loc, SILType Type);
diff --git a/lib/SILGen/SILGenConvert.cpp b/lib/SILGen/SILGenConvert.cpp
index 7d8193d..d749ca9 100644
--- a/lib/SILGen/SILGenConvert.cpp
+++ b/lib/SILGen/SILGenConvert.cpp
@@ -1269,7 +1269,14 @@
}
assert(to->isAny());
- return !from->isAnyClassReferenceType();
+
+ // Types that we can easily transform into AnyObject:
+ // - classes and class-bounded archetypes
+ // - class existentials, even if not pure-@objc
+ // - @convention(objc) metatypes
+ // - @convention(block) functions
+ return !from->isAnyClassReferenceType() &&
+ !from->isBridgeableObjectType();
}
/// Check whether this conversion is Any??? to AnyObject???. If the result
@@ -1283,7 +1290,7 @@
}
if (from->isAny()) {
- assert(to->isAnyObject());
+ assert(to->lookThroughAllAnyOptionalTypes()->isAnyObject());
return true;
}
return false;
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index f00e3d0..0768297 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -517,6 +517,14 @@
SGF.getLoweredLoadableType(outputSubstType));
}
+ // - block to AnyObject conversion
+ if (outputSubstType->isAnyObject()) {
+ if (auto inputFnType = dyn_cast<AnyFunctionType>(inputSubstType)) {
+ if (inputFnType->getRepresentation() == FunctionTypeRepresentation::Block)
+ return SGF.B.createBlockToAnyObject(Loc, v, loweredResultTy);
+ }
+ }
+
// - existentials
if (outputSubstType->isAnyExistentialType()) {
// We have to re-abstract payload if its a metatype or a function
diff --git a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
index e6a416e..a69ca34 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
@@ -1145,3 +1145,4 @@
@end
__nullable id returnNullableId(void);
+void takeNullableId(__nullable id);
diff --git a/test/SILGen/objc_bridging_peephole.swift b/test/SILGen/objc_bridging_peephole.swift
index e9483c0..f3df4cb 100644
--- a/test/SILGen/objc_bridging_peephole.swift
+++ b/test/SILGen/objc_bridging_peephole.swift
@@ -645,7 +645,7 @@
// rdar://35402853
// Make sure that we don't peephole AnyObject? -> Any? -> AnyObject naively.
-// CHECK: sil hidden @_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF
+// CHECK-LABEL: sil hidden @_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF
func testOptionalToNonOptionalBridge() {
// CHECK: apply {{.*}}() : $@convention(c) () -> @autoreleased Optional<AnyObject>
// CHECK: function_ref @_T0s018_bridgeAnyObjectToB0ypyXlSgF :
@@ -653,3 +653,16 @@
// CHECK: apply [[T0]]<Any>
useAnyObject(returnNullableId() as AnyObject)
} // CHECK: end sil function '_T022objc_bridging_peephole017testOptionalToNonE6BridgeyyF'
+
+// CHECK-LABEL: sil hidden @_T022objc_bridging_peephole34testBlockToOptionalAnyObjectBridgeyyyXB5block_tF
+func testBlockToOptionalAnyObjectBridge(block: @escaping @convention(block) () -> ()) {
+ // CHECK: [[FN:%.*]] = function_ref @takeNullableId : $@convention(c) (Optional<AnyObject>) -> ()
+ // CHECK-NEXT: [[T0:%.*]] = begin_borrow {{%.*}} : $@convention(block) () -> ()
+ // CHECK-NEXT: [[T1:%.*]] = copy_value [[T0]]
+ // CHECK-NEXT: [[REF:%.*]] = unchecked_ref_cast [[T1]] : $@convention(block) () -> () to $AnyObject
+ // CHECK-NEXT: [[OPTREF:%.*]] = enum $Optional<AnyObject>, #Optional.some!enumelt.1, [[REF]] : $AnyObject
+ // CHECK-NEXT: end_borrow [[T0]]
+ // CHECK-NEXT: apply [[FN]]([[OPTREF]])
+ // CHECK-NEXT: destroy_value [[OPTREF]]
+ takeNullableId(block as Any)
+}