Skip to content

Commit 231db9d

Browse files
committed
Clang importer: Import ObjC 'id' as Swift 'Any' (behind a flag).
For experimentation purposes, add a flag to cause the Clang importer to map ObjC APIs using `id` to `Any` instead of `AnyObject`.
1 parent 55b8555 commit 231db9d

File tree

7 files changed

+53
-2
lines changed

7 files changed

+53
-2
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ namespace swift {
157157
/// Whether we are stripping the "NS" prefix from Foundation et al.
158158
bool StripNSPrefix = true;
159159

160+
/// Should 'id' in Objective-C be imported as 'Any' in Swift?
161+
bool EnableIdAsAny = false;
162+
160163
/// Enable the Swift 3 migration via Fix-Its.
161164
bool Swift3Migration = false;
162165

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,5 +347,8 @@ def group_info_path : Separate<["-"], "group-info-path">,
347347

348348
def enable_protocol_typealiases: Flag<["-"], "enable-protocol-typealiases">,
349349
HelpText<"Enable typealiases inside protocol declarations">;
350+
351+
def enable_id_as_any: Flag<["-"], "enable-id-as-any">,
352+
HelpText<"Enable importing ObjC 'id' as Swift 'Any' type">;
350353

351354
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

lib/ClangImporter/ImportDecl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,16 @@ namespace {
15001500

15011501
Type SwiftType;
15021502
if (Decl->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
1503+
// Ignore the 'id' typedef. We want to bridge the underlying
1504+
// ObjCId type.
1505+
//
1506+
// When we remove the EnableIdAsAny staging flag, the 'id' entry
1507+
// should be removed from MappedTypes.def, and this conditional should
1508+
// become unnecessary.
1509+
if (Name.str() == "id" && Impl.SwiftContext.LangOpts.EnableIdAsAny) {
1510+
return nullptr;
1511+
}
1512+
15031513
bool IsError;
15041514
StringRef StdlibTypeName;
15051515
MappedTypeNameKind NameMapping;

lib/ClangImporter/ImportType.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,9 +926,15 @@ namespace {
926926
if (!proto)
927927
return Type();
928928

929-
// id maps to AnyObject.
929+
// id maps to Any in bridgeable contexts, AnyObject otherwise.
930930
if (type->isObjCIdType()) {
931-
return { proto->getDeclaredType(), ImportHint::ObjCPointer };
931+
if (Impl.SwiftContext.LangOpts.EnableIdAsAny) {
932+
return { proto->getDeclaredType(),
933+
ImportHint(ImportHint::ObjCBridged,
934+
ProtocolCompositionType::get(Impl.SwiftContext, {})) };
935+
} else {
936+
return { proto->getDeclaredType(), ImportHint::ObjCPointer };
937+
}
932938
}
933939

934940
// Class maps to AnyObject.Type.

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
776776

777777
Opts.EnableThrowWithoutTry |= Args.hasArg(OPT_enable_throw_without_try);
778778
Opts.EnableProtocolTypealiases |= Args.hasArg(OPT_enable_protocol_typealiases);
779+
Opts.EnableIdAsAny |= Args.hasArg(OPT_enable_id_as_any);
779780

780781
if (auto A = Args.getLastArg(OPT_enable_objc_attr_requires_foundation_module,
781782
OPT_disable_objc_attr_requires_foundation_module)) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse -verify -enable-id-as-any %s
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
6+
func assertTypeIsAny(_: Any.Protocol) {}
7+
func staticType<T>(_: T) -> T.Type { return T.self }
8+
9+
let idLover = IdLover()
10+
11+
let t1 = staticType(idLover.makesId())
12+
assertTypeIsAny(t1)
13+
14+
struct ArbitraryThing {}
15+
idLover.takesId(ArbitraryThing())
16+
17+
var x: AnyObject = NSObject()
18+
idLover.takesArray(ofId: &x)
19+
var y: Any = NSObject()
20+
idLover.takesArray(ofId: &y) // expected-error{{}}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,14 @@ extern NSString *NSHTTPRequestKey;
10341034

10351035
@end
10361036

1037+
@interface NSIdLover: NSObject
1038+
1039+
- (id _Nonnull)makesId;
1040+
- (void)takesId:(id _Nonnull)x;
1041+
- (void)takesArrayOfId:(const id _Nonnull * _Nonnull)x;
1042+
1043+
@end
1044+
10371045
#define NSTimeIntervalSince1970 978307200.0
10381046
#define NS_DO_SOMETHING 17
10391047

0 commit comments

Comments
 (0)