Bridge types during import only if we are in a fully-bridgeable context.

Somehow the logic had slipped so that we were basing this decision purely
on the ImportTypeKind and not on whether the broader context is bridgeable.
This was allowing us to use bridged types when e.g. importing the results
and parameters of C function pointer types, which is really bad.

Also, when importing a reference to a typedef of block type, do not use
the typedef in a non-bridgeable context.  We import typedefs of block type
as fully-bridged types, but this means that it is invalid to import a type
using the typedef in a context where the original C type must be used.
Similarly, make sure we use a properly-imported underlying type of the
typedef when the typedef itself is unavailable.

Also, extend the special behavior of block typedefs to abstract-function
typedefs, which seems to be consistent with the expected behavior of the
tests.

Finally, I changed importType to take a new Bridgeability enum instead of
a raw canFullyBridgeTypes bool.  At the time, I was doing that because I
was going to make it tri-valued; that turned out to be unnecessary, but I
think it's an improvement anyway.
This commit is contained in:
John McCall
2017-07-09 01:36:42 -04:00
parent 72c8d6ac47
commit 0e89efa1c8
9 changed files with 118 additions and 57 deletions

View File

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

View File

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

View File

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

View File

@@ -181,6 +181,22 @@ enum class ImportTypeKind {
Enum 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 /// \brief Describes the kind of the C type that can be mapped to a stdlib
/// swift type. /// swift type.
enum class MappedCTypeKind { enum class MappedCTypeKind {
@@ -893,16 +909,17 @@ public:
/// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int /// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int
/// in certain contexts. If false, it will always be imported as UInt. /// in certain contexts. If false, it will always be imported as UInt.
/// ///
/// \param canFullyBridgeTypes True if we can bridge types losslessly. /// \param bridgeability Whether we can bridge types in this context.
/// This is an additional guarantee on top of the ImportTypeKind /// This may restrict the ability to bridge types even in contexts
/// cases that allow bridging, and applies to the entire type. /// that otherwise allow bridging, such as function results and
/// parameters.
/// ///
/// \returns The imported type, or null if this type could /// \returns The imported type, or null if this type could
/// not be represented in Swift. /// not be represented in Swift.
Type importType(clang::QualType type, Type importType(clang::QualType type,
ImportTypeKind kind, ImportTypeKind kind,
bool allowNSUIntegerAsInt, bool allowNSUIntegerAsInt,
bool canFullyBridgeTypes, Bridgeability bridgeability,
OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional, OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional,
bool resugarNSErrorPointer = true); 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(x)
idLover.takesId(y) 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); DarwinBooleanBlock testDarwinBooleanFnToBlockTypedef(DarwinBooleanFn);
typedef __typeof(testCBoolFnToBlockTypedef) CBoolFnToBlockType; typedef __typeof(testCBoolFnToBlockTypedef) CBoolFnToBlockType;
typedef __typeof(testObjCBoolFnToBlockTypedef) ObjCCBoolFnToBlockType; typedef __typeof(testObjCBoolFnToBlockTypedef) ObjCBoolFnToBlockType;
typedef __typeof(testDarwinBooleanFnToBlockTypedef) DarwinBooleanFnToBlockType; typedef __typeof(testDarwinBooleanFnToBlockTypedef) DarwinBooleanFnToBlockType;
extern ObjCBoolFnToBlockType *globalObjCBoolFnToBlockFP;
extern ObjCBoolFnToBlockType * __nonnull * __nullable globalObjCBoolFnToBlockFPP;
extern ObjCBoolFnToBlockType ^globalObjCBoolFnToBlockBP;
extern CBoolFn globalCBoolFn; extern CBoolFn globalCBoolFn;
extern ObjCBoolFn globalObjCBoolFn; extern ObjCBoolFn globalObjCBoolFn;
extern DarwinBooleanFn globalDarwinBooleanFn; extern DarwinBooleanFn globalDarwinBooleanFn;

View File

@@ -43,8 +43,12 @@ func testObjCBoolFnToBlockTypedef(_: @escaping ObjCBoolFn) -> ObjCBoolBlock
func testDarwinBooleanFnToBlockTypedef(_: @escaping DarwinBooleanFn) -> DarwinBooleanBlock func testDarwinBooleanFnToBlockTypedef(_: @escaping DarwinBooleanFn) -> DarwinBooleanBlock
typealias CBoolFnToBlockType = (CBoolFn) -> CBoolBlock typealias CBoolFnToBlockType = (CBoolFn) -> CBoolBlock
typealias ObjCCBoolFnToBlockType = (ObjCBoolFn) -> (ObjCBool) -> ObjCBool typealias ObjCBoolFnToBlockType = (ObjCBoolFn) -> ObjCBoolBlock
typealias DarwinBooleanFnToBlockType = (DarwinBooleanFn) -> (DarwinBoolean) -> DarwinBoolean 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 globalCBoolFn: CBoolFn
var globalObjCBoolFn: ObjCBoolFn var globalObjCBoolFn: ObjCBoolFn

View File

@@ -143,7 +143,7 @@
// CHECK-FOUNDATION: func doSomethingElse(with: NSCopying & NSObjectProtocol) // CHECK-FOUNDATION: func doSomethingElse(with: NSCopying & NSObjectProtocol)
// Note: Function type -> "Function". // 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". // Note: Plural: NSArray without type arguments -> "Objects".
// CHECK-FOUNDATION: func remove(_: [Any]) // CHECK-FOUNDATION: func remove(_: [Any])

View File

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