diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index acb827f9ccf34..318a03735a50b 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5816,6 +5816,8 @@ Expr *ExprRewriter::buildCollectionUpcastExpr(Expr *expr, Type toType, Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType, ConstraintLocatorBuilder locator) { + auto &tc = cs.getTypeChecker(); + Type fromType = cs.getType(expr); // Bridged collection casts always succeed, so we treat them as @@ -5838,6 +5840,20 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType, if (!objcExpr) return nullptr; + // We might have a coercion of a Swift type to a CF type toll-free + // bridged to Objective-C. + // + // FIXME: Ideally we would instead have already recorded a restriction + // when solving the constraint, and we wouldn't need to duplicate this + // part of coerceToType() here. + if (auto foreignClass = toType->getClassOrBoundGenericClass()) { + if (foreignClass->getForeignClassKind() == + ClassDecl::ForeignKind::CFType) { + return cs.cacheType( + new (tc.Context) ForeignObjectConversionExpr(objcExpr, toType)); + } + } + return coerceToType(objcExpr, toType, locator); } diff --git a/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h b/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h index f628500186737..3f96927daf69f 100644 --- a/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h +++ b/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h @@ -14,6 +14,10 @@ typedef struct __attribute__((objc_bridge(NSString))) __CFString const *CFString typedef struct __CFTree *CFTreeRef; typedef const struct __attribute__((objc_bridge(CFURL))) __CFURL * CFURLRef; +typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary const *CFDictionaryRef; +typedef struct __attribute__((objc_bridge(NSArray))) __CFArray const *CFArrayRef; +typedef struct __attribute__((objc_bridge(NSSet))) __CFSet const *CFSetRef; + typedef CFTypeRef CFAliasForTypeRef; diff --git a/test/expr/cast/cf.swift b/test/expr/cast/cf.swift index 90d1d7fc95314..343d8cf1a1bae 100644 --- a/test/expr/cast/cf.swift +++ b/test/expr/cast/cf.swift @@ -80,3 +80,25 @@ func testCFConvWithIUO(_ x: CFString!, y: NSString!) { acceptNSString(x) acceptCFString(y) } + +func testBridgedCFDowncast(array: [Any], dictionary: [AnyHashable : Any], set: Set) { + let cfArray = array as CFArray + let cfDictionary = dictionary as CFDictionary + let cfSet = set as CFSet + + _ = array as? CFArray // expected-warning {{conditional cast from '[Any]' to 'CFArray' always succeeds}} + _ = dictionary as? CFDictionary // expected-warning {{conditional cast from '[AnyHashable : Any]' to 'CFDictionary' always succeeds}} + _ = set as? CFSet // expected-warning {{conditional cast from 'Set' to 'CFSet' always succeeds}} + + _ = array as! CFArray // expected-warning {{forced cast from '[Any]' to 'CFArray' always succeeds}} + _ = dictionary as! CFDictionary // expected-warning {{forced cast from '[AnyHashable : Any]' to 'CFDictionary' always succeeds}} + _ = set as! CFSet // expected-warning {{forced cast from 'Set' to 'CFSet' always succeeds}} + + _ = cfArray as! [Any] + _ = cfDictionary as! [AnyHashable : Any] + _ = cfSet as! Set + + _ = cfArray as? [Any] + _ = cfDictionary as? [AnyHashable : Any] + _ = cfSet as? Set +}