Skip to content

[4.2 2018-06-11] [Clang importer] Don't bridge blocks to Swift functions in ObjC generic arguments. #17261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -974,8 +974,8 @@ namespace {
// Convert the type arguments.
for (auto typeArg : typeArgs) {
Type importedTypeArg = Impl.importTypeIgnoreIUO(
typeArg, ImportTypeKind::BridgedValue, AllowNSUIntegerAsInt,
Bridging, OTK_None);
typeArg, ImportTypeKind::ObjCCollectionElement,
AllowNSUIntegerAsInt, Bridging, OTK_None);
if (!importedTypeArg) {
importedTypeArgs.clear();
break;
Expand Down Expand Up @@ -1102,7 +1102,7 @@ static bool canBridgeTypes(ImportTypeKind importKind) {
case ImportTypeKind::CFUnretainedOutParameter:
case ImportTypeKind::Property:
case ImportTypeKind::PropertyWithReferenceSemantics:
case ImportTypeKind::BridgedValue:
case ImportTypeKind::ObjCCollectionElement:
case ImportTypeKind::Typedef:
return true;
}
Expand All @@ -1116,7 +1116,7 @@ static bool isCFAudited(ImportTypeKind importKind) {
case ImportTypeKind::Abstract:
case ImportTypeKind::Typedef:
case ImportTypeKind::Value:
case ImportTypeKind::BridgedValue:
case ImportTypeKind::ObjCCollectionElement:
case ImportTypeKind::Variable:
case ImportTypeKind::Result:
case ImportTypeKind::Pointee:
Expand Down Expand Up @@ -1283,14 +1283,29 @@ static ImportedType adjustTypeForConcreteImport(
}

// SwiftTypeConverter turns block pointers into @convention(block) types.
// In a bridgeable context, or in the direct structure of a typedef,
// we would prefer to instead use the default Swift convention.
// In some contexts, we bridge them to use the Swift function type
// representation. This includes typedefs of block types, which use the
// Swift function type representation.
if (hint == ImportHint::Block) {
if (canBridgeTypes(importKind)) {
// Determine the function type representation we need.
//
// For Objective-C collection arguments, we cannot bridge from a block
// to a Swift function type, so force the block representation. Normally
// the mapped type will have a block representation (making this a no-op),
// but in cases where the Clang type was written as a typedef of a
// block type, that typedef will have a Swift function type
// representation. This code will then break down the imported type
// alias and produce a function type with block representation.
auto requiredFunctionTypeRepr = FunctionTypeRepresentation::Swift;
if (importKind == ImportTypeKind::ObjCCollectionElement) {
requiredFunctionTypeRepr = FunctionTypeRepresentation::Block;
}

auto fTy = importedType->castTo<FunctionType>();
FunctionType::ExtInfo einfo = fTy->getExtInfo();
if (einfo.getRepresentation() != FunctionTypeRepresentation::Swift) {
einfo = einfo.withRepresentation(FunctionTypeRepresentation::Swift);
if (einfo.getRepresentation() != requiredFunctionTypeRepr) {
einfo = einfo.withRepresentation(requiredFunctionTypeRepr);
importedType = fTy->withExtInfo(einfo);
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ enum class ImportTypeKind {
/// \brief Import the type of a literal value.
Value,

/// \brief Import the type of a literal value that can be bridged.
BridgedValue,
/// \brief Import the type of an Objective-C generic argument.
ObjCCollectionElement,

/// \brief Import the declared type of a variable.
Variable,
Expand Down
4 changes: 4 additions & 0 deletions test/ClangImporter/objc_bridging_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,7 @@ func testHashableGenerics(
let _: Int = insufficient.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
let _: Int = extra.foo // expected-error{{cannot convert value of type 'Set<ElementConcrete>' to specified type 'Int'}}
}

func testGenericsWithTypedefBlocks(hba: HasBlockArray) {
let _: Int = hba.blockArray() // expected-error{{type '[@convention(block) () -> Void]'}}
}
8 changes: 8 additions & 0 deletions test/ClangImporter/objc_ir.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Foundation
import objc_ext
import TestProtocols
import ObjCIRExtras
import objc_generics

// CHECK: @"\01L_selector_data(method:withFloat:)" = private global [18 x i8] c"method:withFloat:\00"
// CHECK: @"\01L_selector_data(method:withDouble:)" = private global [19 x i8] c"method:withDouble:\00"
Expand Down Expand Up @@ -337,6 +338,13 @@ func testCompatibilityAliasMangling(obj: SwiftNameAlias) {
}


// CHECK-LABEL: S7objc_ir22testBlocksWithGenerics3hbaypSo13HasBlockArrayC_tF
func testBlocksWithGenerics(hba: HasBlockArray) -> Any {
// CHECK: {{call swiftcc.*SSo13HasBlockArrayC05blockC0SayyyXBGyFTcTO}}
let _ = hba.blockPointerType()
return hba.blockArray
}

// CHECK: linkonce_odr hidden {{.*}} @"$SSo1BC3intABSgs5Int32V_tcfcTO"
// CHECK: load i8*, i8** @"\01L_selector(initWithInt:)"
// CHECK: call [[OPAQUE:%.*]]* bitcast (void ()* @objc_msgSend
Expand Down
7 changes: 7 additions & 0 deletions test/Inputs/clang-importer-sdk/usr/include/objc_generics.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,10 @@ typedef id <Fungible> FungibleObject;

@interface Third : Second<Third *>
@end

typedef void (^ _Nonnull BlockPointerType)(void);

@interface HasBlockArray : NSObject
- (NSArray<BlockPointerType> * _Nonnull)blockArray;
- (BlockPointerType)blockPointerType;
@end