Merge pull request #10832 from rjmccall/fix-function-component-bridging-import

Bridge types during import only if we are in a fully-bridgeable context.
This commit is contained in:
John McCall
2017-07-09 16:47:01 -04:00
committed by GitHub
9 changed files with 118 additions and 57 deletions

View File

@@ -2303,7 +2303,7 @@ namespace {
SwiftType = Impl.importType(ClangType,
ImportTypeKind::Typedef,
isInSystemModule(DC),
ClangType->isBlockPointerType(),
getTypedefBridgeability(ClangType),
OTK_Optional);
}
@@ -2410,7 +2410,7 @@ namespace {
auto underlyingType = Impl.importType(decl->getIntegerType(),
ImportTypeKind::Enum,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!underlyingType)
return nullptr;
@@ -2447,7 +2447,7 @@ namespace {
// Compute the underlying type.
auto underlyingType = Impl.importType(
decl->getIntegerType(), ImportTypeKind::Enum, isInSystemModule(dc),
/*isFullyBridgeable*/ false);
Bridgeability::None);
if (!underlyingType)
return nullptr;
@@ -3063,7 +3063,7 @@ namespace {
auto type = Impl.importType(clangContext.getTagDeclType(clangEnum),
ImportTypeKind::Value,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!type)
return nullptr;
// FIXME: Importing the type will recursively revisit this same
@@ -3101,7 +3101,7 @@ namespace {
Impl.getClangASTContext().getTagDeclType(clangEnum),
ImportTypeKind::Value,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!enumType)
return nullptr;
@@ -3162,7 +3162,7 @@ namespace {
auto type = Impl.importType(decl->getType(),
ImportTypeKind::Variable,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!type)
return nullptr;
@@ -3385,7 +3385,7 @@ namespace {
auto type = Impl.importType(decl->getType(),
ImportTypeKind::RecordField,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!type)
return nullptr;
@@ -3454,7 +3454,7 @@ namespace {
(isAudited ? ImportTypeKind::AuditedVariable
: ImportTypeKind::Variable),
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!type)
return nullptr;
@@ -4332,7 +4332,7 @@ namespace {
superclassType = Impl.importType(clangSuperclassType,
ImportTypeKind::Abstract,
isInSystemModule(dc),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (superclassType) {
assert(superclassType->is<ClassType>() ||
superclassType->is<BoundGenericClassType>());
@@ -4938,7 +4938,7 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
// Import the type of the underlying storage
auto storedUnderlyingType = Impl.importType(
decl->getUnderlyingType(), ImportTypeKind::Value, isInSystemModule(dc),
decl->getUnderlyingType()->isBlockPointerType(), OTK_None);
Bridgeability::None, OTK_None);
if (auto objTy = storedUnderlyingType->getAnyOptionalObjectType())
storedUnderlyingType = objTy;
@@ -4956,7 +4956,7 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
// Find a bridged type, which may be different
auto computedPropertyUnderlyingType = Impl.importType(
decl->getUnderlyingType(), ImportTypeKind::Property, isInSystemModule(dc),
decl->getUnderlyingType()->isBlockPointerType(), OTK_None);
Bridgeability::Full, OTK_None);
if (auto objTy = computedPropertyUnderlyingType->getAnyOptionalObjectType())
computedPropertyUnderlyingType = objTy;
@@ -5173,7 +5173,7 @@ SwiftDeclConverter::importAsOptionSetType(DeclContext *dc, Identifier name,
// Compute the underlying type.
auto underlyingType = Impl.importType(
decl->getIntegerType(), ImportTypeKind::Enum, isInSystemModule(dc),
/*isFullyBridgeable*/ false);
Bridgeability::None);
if (!underlyingType)
return nullptr;
@@ -5492,7 +5492,7 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
Type swiftPropertyType = Impl.importType(
propertyType, ImportTypeKind::Property,
Impl.shouldAllowNSUIntegerAsInt(isFromSystemModule, getter),
/*isFullyBridgeable*/ true, OTK_ImplicitlyUnwrappedOptional);
Bridgeability::Full, OTK_ImplicitlyUnwrappedOptional);
if (!swiftPropertyType)
return nullptr;
@@ -6406,7 +6406,8 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
clangBound->stripObjCKindOfTypeAndQuals(Impl.getClangASTContext());
Type superclassType =
Impl.importType(clang::QualType(unqualifiedClangBound, 0),
ImportTypeKind::Abstract, false, false);
ImportTypeKind::Abstract, false,
Bridgeability::None);
if (!superclassType) {
return None;
}

View File

@@ -113,7 +113,7 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
auto clangTy = parsed->getType();
auto literalType = Impl.importType(clangTy, ImportTypeKind::Value,
isInSystemModule(DC),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!literalType)
return nullptr;
@@ -123,7 +123,7 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
} else {
constantType = Impl.importType(castType, ImportTypeKind::Value,
isInSystemModule(DC),
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!constantType)
return nullptr;
}
@@ -300,7 +300,7 @@ static Optional<std::pair<llvm::APSInt, Type>>
auto type = impl.importType(literal->getType(),
ImportTypeKind::Value,
isInSystemModule(DC),
/*isFullyBridgeable*/false);
Bridgeability::None);
return {{ value, type }};
}

View File

@@ -176,14 +176,14 @@ namespace {
{
ClangImporter::Implementation &Impl;
bool AllowNSUIntegerAsInt;
bool CanFullyBridgeTypes;
Bridgeability Bridging;
public:
SwiftTypeConverter(ClangImporter::Implementation &impl,
bool allowNSUIntegerAsInt,
bool canFullyBridgeTypes)
Bridgeability bridging)
: Impl(impl), AllowNSUIntegerAsInt(allowNSUIntegerAsInt),
CanFullyBridgeTypes(canFullyBridgeTypes) {}
Bridging(bridging) {}
using TypeVisitor::Visit;
ImportResult Visit(clang::QualType type) {
@@ -356,7 +356,7 @@ namespace {
pointeeType = Impl.importType(pointeeQualType,
ImportTypeKind::Pointee,
AllowNSUIntegerAsInt,
/*isFullyBridgeable*/false);
Bridgeability::None);
// If the pointed-to type is unrepresentable in Swift, import as
// OpaquePointer.
@@ -404,7 +404,7 @@ namespace {
Type pointeeType = Impl.importType(type->getPointeeType(),
ImportTypeKind::Abstract,
AllowNSUIntegerAsInt,
CanFullyBridgeTypes);
Bridging);
if (!pointeeType)
return Type();
FunctionType *fTy = pointeeType->castTo<FunctionType>();
@@ -443,7 +443,7 @@ namespace {
Type elementType = Impl.importType(type->getElementType(),
ImportTypeKind::Pointee,
AllowNSUIntegerAsInt,
/*isFullyBridgeable*/false);
Bridgeability::None);
if (!elementType)
return Type();
@@ -498,7 +498,7 @@ namespace {
auto resultTy = Impl.importType(type->getReturnType(),
ImportTypeKind::Result,
AllowNSUIntegerAsInt,
CanFullyBridgeTypes,
Bridging,
OTK_Optional);
if (!resultTy)
return Type();
@@ -509,7 +509,7 @@ namespace {
param != paramEnd; ++param) {
auto swiftParamTy = Impl.importType(*param, ImportTypeKind::Parameter,
AllowNSUIntegerAsInt,
CanFullyBridgeTypes,
Bridging,
OTK_Optional);
if (!swiftParamTy)
return Type();
@@ -534,7 +534,7 @@ namespace {
auto resultTy = Impl.importType(type->getReturnType(),
ImportTypeKind::Result,
AllowNSUIntegerAsInt,
CanFullyBridgeTypes,
Bridging,
OTK_Optional);
if (!resultTy)
return Type();
@@ -665,12 +665,32 @@ namespace {
}
// Any other interesting mapped types should be hinted here.
// Otherwise, recurse on the underlying type in order to compute
// the hint correctly.
// Otherwise, recurse on the underlying type. We need to recompute
// the hint, and if the typedef uses different bridgeability than the
// context then we may also need to bypass the typedef.
} else {
auto underlyingType = type->desugar();
// Figure out the bridgeability we would normally use for this typedef.
auto typedefBridgeability = getTypedefBridgeability(underlyingType);
// Figure out the typedef we should actually use.
auto underlyingBridgeability =
(Bridging == Bridgeability::Full
? typedefBridgeability : Bridgeability::None);
SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt,
/*can fully bridge*/false);
auto underlyingResult = innerConverter.Visit(type->desugar());
underlyingBridgeability);
auto underlyingResult = innerConverter.Visit(underlyingType);
// If we used different bridgeability than this typedef normally
// would because we're in a non-bridgeable context, and therefore
// the underlying type is different from the mapping of the typedef,
// use the underlying type.
if (underlyingBridgeability != typedefBridgeability &&
!underlyingResult.AbstractType->isEqual(mappedType)) {
return underlyingResult;
}
#ifndef NDEBUG
switch (underlyingResult.Hint) {
case ImportHint::Block:
@@ -960,7 +980,7 @@ namespace {
Type importedTypeArg = Impl.importType(typeArg,
ImportTypeKind::BridgedValue,
AllowNSUIntegerAsInt,
CanFullyBridgeTypes,
Bridging,
OTK_None);
if (!importedTypeArg) {
importedTypeArgs.clear();
@@ -1146,7 +1166,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
ImportTypeKind importKind,
ImportHint hint,
bool allowNSUIntegerAsInt,
bool canFullyBridgeTypes,
Bridgeability bridging,
OptionalTypeKind optKind,
bool resugarNSErrorPointer) {
if (importKind == ImportTypeKind::Abstract) {
@@ -1261,10 +1281,14 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
importedType = outParamTy;
}
// Turn block pointer types back into normal function types in any
// context where bridging is possible, unless the block has a typedef.
// 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. But this
// does means that, when we're using a typedef of a block pointer type in
// an unbridgable context, we need to go back and do a fully-unbridged
// import of the underlying type.
if (hint == ImportHint::Block) {
if (!canFullyBridgeTypes) {
if (bridging == Bridgeability::None) {
if (auto typedefType = clangType->getAs<clang::TypedefType>()) {
// In non-bridged contexts, drop the typealias sugar for blocks.
// FIXME: This will do the wrong thing if there's any adjustment to do
@@ -1272,7 +1296,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
Type underlyingTy = impl.importType(typedefType->desugar(),
importKind,
allowNSUIntegerAsInt,
canFullyBridgeTypes,
bridging,
OTK_None);
if (Type unwrappedTy = underlyingTy->getAnyOptionalObjectType())
underlyingTy = unwrappedTy;
@@ -1281,7 +1305,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
}
}
if (canBridgeTypes(importKind) || importKind == ImportTypeKind::Typedef) {
if (bridging == Bridgeability::Full) {
auto fTy = importedType->castTo<FunctionType>();
FunctionType::ExtInfo einfo = fTy->getExtInfo();
if (einfo.getRepresentation() != FunctionTypeRepresentation::Swift) {
@@ -1294,7 +1318,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
// Turn BOOL and DarwinBoolean into Bool in contexts that can bridge types
// losslessly.
if ((hint == ImportHint::BOOL || hint == ImportHint::Boolean) &&
canFullyBridgeTypes && canBridgeTypes(importKind)) {
bridging == Bridgeability::Full && canBridgeTypes(importKind)) {
return impl.SwiftContext.getBoolDecl()->getDeclaredType();
}
@@ -1323,7 +1347,9 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
// If we have a bridged Objective-C type and we are allowed to
// bridge, do so.
if (hint == ImportHint::ObjCBridged && canBridgeTypes(importKind) &&
if (hint == ImportHint::ObjCBridged &&
bridging == Bridgeability::Full &&
canBridgeTypes(importKind) &&
importKind != ImportTypeKind::PropertyWithReferenceSemantics) {
// id and Any can be bridged without Foundation. There would be
// bootstrapping issues with the ObjectiveC module otherwise.
@@ -1373,7 +1399,7 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
Type ClangImporter::Implementation::importType(clang::QualType type,
ImportTypeKind importKind,
bool allowNSUIntegerAsInt,
bool canFullyBridgeTypes,
Bridgeability bridging,
OptionalTypeKind optionality,
bool resugarNSErrorPointer) {
if (type.isNull())
@@ -1414,14 +1440,13 @@ Type ClangImporter::Implementation::importType(clang::QualType type,
}
// Perform abstract conversion, ignoring how the type is actually used.
SwiftTypeConverter converter(*this, allowNSUIntegerAsInt,canFullyBridgeTypes);
SwiftTypeConverter converter(*this, allowNSUIntegerAsInt, bridging);
auto importResult = converter.Visit(type);
// Now fix up the type based on we're concretely using it.
return adjustTypeForConcreteImport(*this, type, importResult.AbstractType,
importKind, importResult.Hint,
allowNSUIntegerAsInt,
canFullyBridgeTypes,
allowNSUIntegerAsInt, bridging,
optionality,
resugarNSErrorPointer);
}
@@ -1493,7 +1518,7 @@ Type ClangImporter::Implementation::importPropertyType(
OptionalTypeKind optionality = OTK_ImplicitlyUnwrappedOptional;
return importType(decl->getType(), importKind,
shouldAllowNSUIntegerAsInt(isFromSystemModule, decl),
/*isFullyBridgeable*/ true, optionality);
Bridgeability::Full, optionality);
}
/// Apply the @noescape attribute
@@ -1566,7 +1591,7 @@ Type ClangImporter::Implementation::importFunctionReturnType(
(isAuditedResult ? ImportTypeKind::AuditedResult
: ImportTypeKind::Result),
allowNSUIntegerAsInt,
/*isFullyBridgeable*/ true, OptionalityOfReturn);
Bridgeability::Full, OptionalityOfReturn);
}
Type ClangImporter::Implementation::
@@ -1628,7 +1653,7 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
// Import the parameter type into Swift.
Type swiftParamTy =
importType(paramTy, importKind, allowNSUIntegerAsInt,
/*isFullyBridgeable*/ true, OptionalityOfParam);
Bridgeability::Full, OptionalityOfParam);
if (!swiftParamTy)
return nullptr;
@@ -1919,7 +1944,7 @@ Type ClangImporter::Implementation::importMethodType(
clang::QualType resultType = clangDecl->getReturnType();
swiftResultTy = importType(resultType, resultKind,
allowNSUIntegerAsIntInResult,
/*isFullyBridgeable*/true,
Bridgeability::Full,
OptionalityOfReturn);
// Adjust the result type for a throwing function.
if (swiftResultTy && errorInfo) {
@@ -1927,7 +1952,7 @@ Type ClangImporter::Implementation::importMethodType(
// Get the original unbridged result type.
origSwiftResultTy = importType(resultType, resultKind,
allowNSUIntegerAsIntInResult,
/*isFullyBridgeable*/false,
Bridgeability::None,
OptionalityOfReturn)
->getCanonicalType();
@@ -2042,7 +2067,7 @@ Type ClangImporter::Implementation::importMethodType(
// being lazier.)
swiftParamTy = importType(paramTy, importKind,
allowNSUIntegerAsIntInParam,
/*isFullyBridgeable*/true,
Bridgeability::Full,
optionalityOfParam,
/*resugarNSErrorPointer=*/!paramIsError);
}

View File

@@ -181,6 +181,22 @@ enum class ImportTypeKind {
Enum
};
enum class Bridgeability {
/// This context does not permit bridging at all. For example, the
/// target of a C pointer.
None,
/// This context permits all kinds of bridging. For example, the
/// imported result of a method declaration.
Full
};
static inline Bridgeability getTypedefBridgeability(clang::QualType type) {
return (type->isBlockPointerType() || type->isFunctionType())
? Bridgeability::Full
: Bridgeability::None;
}
/// \brief Describes the kind of the C type that can be mapped to a stdlib
/// swift type.
enum class MappedCTypeKind {
@@ -893,16 +909,17 @@ public:
/// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int
/// in certain contexts. If false, it will always be imported as UInt.
///
/// \param canFullyBridgeTypes True if we can bridge types losslessly.
/// This is an additional guarantee on top of the ImportTypeKind
/// cases that allow bridging, and applies to the entire type.
/// \param bridgeability Whether we can bridge types in this context.
/// This may restrict the ability to bridge types even in contexts
/// that otherwise allow bridging, such as function results and
/// parameters.
///
/// \returns The imported type, or null if this type could
/// not be represented in Swift.
Type importType(clang::QualType type,
ImportTypeKind kind,
bool allowNSUIntegerAsInt,
bool canFullyBridgeTypes,
Bridgeability bridgeability,
OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional,
bool resugarNSErrorPointer = true);

View File

@@ -24,3 +24,10 @@ idLover.takesArray(ofId: &y) // expected-error{{argument type 'Any' does not con
idLover.takesId(x)
idLover.takesId(y)
install_global_event_handler(idLover) // expected-error {{cannot convert value of type 'NSIdLover' to expected argument type 'event_handler?' (aka 'Optional<@convention(c) (AnyObject) -> ()>')}}
// FIXME: this should not type-check!
// Function conversions are not legal when converting to a thin function type.
let handler: @convention(c) (Any) -> () = { object in () }
install_global_event_handler(handler)

View File

@@ -40,9 +40,13 @@ ObjCBoolBlock testObjCBoolFnToBlockTypedef(ObjCBoolFn);
DarwinBooleanBlock testDarwinBooleanFnToBlockTypedef(DarwinBooleanFn);
typedef __typeof(testCBoolFnToBlockTypedef) CBoolFnToBlockType;
typedef __typeof(testObjCBoolFnToBlockTypedef) ObjCCBoolFnToBlockType;
typedef __typeof(testObjCBoolFnToBlockTypedef) ObjCBoolFnToBlockType;
typedef __typeof(testDarwinBooleanFnToBlockTypedef) DarwinBooleanFnToBlockType;
extern ObjCBoolFnToBlockType *globalObjCBoolFnToBlockFP;
extern ObjCBoolFnToBlockType * __nonnull * __nullable globalObjCBoolFnToBlockFPP;
extern ObjCBoolFnToBlockType ^globalObjCBoolFnToBlockBP;
extern CBoolFn globalCBoolFn;
extern ObjCBoolFn globalObjCBoolFn;
extern DarwinBooleanFn globalDarwinBooleanFn;

View File

@@ -43,8 +43,12 @@ func testObjCBoolFnToBlockTypedef(_: @escaping ObjCBoolFn) -> ObjCBoolBlock
func testDarwinBooleanFnToBlockTypedef(_: @escaping DarwinBooleanFn) -> DarwinBooleanBlock
typealias CBoolFnToBlockType = (CBoolFn) -> CBoolBlock
typealias ObjCCBoolFnToBlockType = (ObjCBoolFn) -> (ObjCBool) -> ObjCBool
typealias DarwinBooleanFnToBlockType = (DarwinBooleanFn) -> (DarwinBoolean) -> DarwinBoolean
typealias ObjCBoolFnToBlockType = (ObjCBoolFn) -> ObjCBoolBlock
typealias DarwinBooleanFnToBlockType = (DarwinBooleanFn) -> DarwinBooleanBlock
var globalObjCBoolFnToBlockFP: @convention(c) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool
var globalObjCBoolFnToBlockFPP: UnsafeMutablePointer<@convention(c) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool>?
var globalObjCBoolFnToBlockBP: @convention(block) (ObjCBoolFn) -> @convention(block) (ObjCBool) -> ObjCBool
var globalCBoolFn: CBoolFn
var globalObjCBoolFn: ObjCBoolFn

View File

@@ -143,7 +143,7 @@
// CHECK-FOUNDATION: func doSomethingElse(with: NSCopying & NSObjectProtocol)
// Note: Function type -> "Function".
// CHECK-FOUNDATION: func sort(_: @escaping @convention(c) (Any, Any) -> Int)
// CHECK-FOUNDATION: func sort(_: @escaping @convention(c) (AnyObject, AnyObject) -> Int)
// Note: Plural: NSArray without type arguments -> "Objects".
// CHECK-FOUNDATION: func remove(_: [Any])

View File

@@ -1110,3 +1110,6 @@ typedef enum __attribute__((ns_error_domain(NSLaundryErrorDomain))) __attribute_
NSLaundryErrorTooMuchSoap = 1,
NSLaundryErrorCatInWasher = 2
};
typedef void (*event_handler)(__nonnull id);
void install_global_event_handler(__nullable event_handler handler);