Skip to content

Commit 4cc5def

Browse files
committed
Work around Foundation NS_TYPED_ENUM bug
Consider code like: ``` // Foo.h typealias NSString * FooKey NS_EXTENSIBLE_TYPED_ENUM; // Foo.swift extension FooKey { … } ``` When Swift binds the extension to `FooKey`, that forces ClangImporter to import `FooKey`. ClangImporter’s newtype logic, among other things, checks whether the underlying type (`Swift.String` here) is Objective-C bridgeable and, if so, makes `FooKey` bridgeable too. But what happens if this code is actually *in* Foundation, which is where the `extension String: _ObjectiveCBridgeable` lives? Well, if the compiler has already bound that extension, it works fine…but if it hasn’t, `FooKey` ends up unbridgeable, which can cause both type checking failures and IRGen crashes when code tries to use its bridging capabilities. And these symptoms are sensitive to precise details of the order Swift happens to bind extensions in, so e.g. adding empty files to the project can make the bug appear or disappear. Spooky. Add a narrow hack to ClangImporter (only active for types in Foundation) to *assume* that `String` is bridgeable even if the extension declaring this hasn’t been bound yet. Fixes rdar://142693093.
1 parent 014d6df commit 4cc5def

File tree

4 files changed

+23
-1
lines changed

4 files changed

+23
-1
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6277,6 +6277,19 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl,
62776277
synthesizedProtocols.push_back(kind);
62786278
return true;
62796279
}
6280+
// HACK: This method may be called before all extensions have been bound.
6281+
// This is a problem for newtypes in Foundation, which is what provides the
6282+
// `String: _ObjectiveCBridgeable` conformance; it can cause us to create
6283+
// `String`-backed newtypes which aren't bridgeable, causing typecheck
6284+
// failures and crashes down the line (rdar://142693093). Hardcode knowledge
6285+
// that this conformance will exist.
6286+
// FIXME: Defer adding conformances to newtypes instead of this. (#78731)
6287+
if (structDecl->getModuleContext()->isFoundationModule()
6288+
&& kind == KnownProtocolKind::ObjectiveCBridgeable
6289+
&& computedNominal == ctx.getStringDecl()) {
6290+
synthesizedProtocols.push_back(kind);
6291+
return true;
6292+
}
62806293

62816294
return false;
62826295
};

test/ClangImporter/newtype_conformance.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func acceptHashable<T: Hashable>(_: T) {}
1818
func acceptComparable<T: Comparable>(_: T) {}
1919
// expected-note@-1 {{where 'T' = 'NSNotification.Name'}}
2020

21-
func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
21+
func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name, z: NSFileAttributeKey) {
2222
acceptEquatable(x)
2323
acceptHashable(x)
2424
acceptComparable(x) // expected-error {{global function 'acceptComparable' requires that 'NSNotification.Name' conform to 'Comparable'}}
@@ -28,6 +28,8 @@ func testNewTypeWrapper(x: NSNotification.Name, y: NSNotification.Name) {
2828
_ = x != y
2929
_ = x.hashValue
3030
_ = x as NSString
31+
32+
_ = z as NSString
3133
}
3234

3335

test/Inputs/clang-importer-sdk/swift-modules/Foundation.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
public let NSUTF8StringEncoding: UInt = 8
66

7+
// This extension will cause ClangImporter/newtype_conformance.swift to fail
8+
// unless rdar://142693093 is fixed. To reproduce, it's important that this
9+
// extension come *before* the _ObjectiveCBridgeable extension for String.
10+
extension NSFileAttributeKey { }
11+
712
extension AnyHashable : _ObjectiveCBridgeable {
813
public func _bridgeToObjectiveC() -> NSObject {
914
return NSObject()

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,8 @@ extern void CGColorRelease(CGColorRef color) __attribute__((availability(macosx,
867867

868868
typedef NSString *_Nonnull NSNotificationName
869869
__attribute((swift_newtype(struct)));
870+
typedef NSString *_Nonnull NSFileAttributeKey
871+
__attribute((swift_newtype(struct)));
870872

871873
NS_SWIFT_UNAVAILABLE("Use NSXPCConnection instead")
872874
extern NSString * const NSConnectionReplyMode;

0 commit comments

Comments
 (0)