Skip to content

Commit cb9e2ca

Browse files
committed
[Clang importer] Refactor mapping of bridged Objective-C class types.
Localize and simplify the computation of the type to which an Objective-C type is bridged. NFC.
1 parent 0e2dc7a commit cb9e2ca

File tree

2 files changed

+112
-178
lines changed

2 files changed

+112
-178
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 107 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,9 @@ namespace {
6363
/// The source type is 'Boolean'.
6464
Boolean,
6565

66-
/// The source type is 'NSString'.
67-
NSString,
68-
69-
/// The source type is 'NSArray'.
70-
NSArray,
71-
72-
/// The source type is 'NSDictionary'.
73-
NSDictionary,
74-
75-
/// The source type is 'NSSet'.
76-
NSSet,
66+
/// The source type an Objective-C class type bridged to a Swift
67+
/// type.
68+
ObjCBridged,
7769

7870
/// The source type is 'NSUInteger'.
7971
NSUInteger,
@@ -100,52 +92,21 @@ namespace {
10092

10193
ImportHintKind Kind;
10294

103-
// Type arguments, if provided.
104-
Type TypeArgs[2];
95+
/// The type to which the imported type is bridged.
96+
Type BridgedType;
10597

10698
/// Allow conversion from an import hint to an import hint kind,
10799
/// which is useful for switches and comparisons.
108100
operator ImportHintKind() const { return Kind; }
109101

110-
/// Determine the number of type arguments we expect.
111-
static unsigned getNumTypeArgs(ImportHintKind kind) {
112-
switch (kind) {
113-
case None:
114-
case Void:
115-
case BOOL:
116-
case Boolean:
117-
case NSString:
118-
case NSUInteger:
119-
case ObjCPointer:
120-
case CFPointer:
121-
case Reference:
122-
case Block:
123-
case CFunctionPointer:
124-
case CustomNullablePointer:
125-
return 0;
126-
127-
case NSArray:
128-
case NSSet:
129-
return 1;
130-
131-
case NSDictionary:
132-
return 2;
133-
}
134-
}
135-
136102
ImportHint(ImportHintKind kind) : Kind(kind) {
137-
assert(getNumTypeArgs(kind) == 0 && "Wrong number of arguments");
103+
assert(kind != ObjCBridged &&
104+
"Bridged entry point requires a bridged type");
138105
}
139106

140-
ImportHint(ImportHintKind kind, Type typeArg1) : Kind(kind) {
141-
assert(getNumTypeArgs(kind) == 1 && "Wrong number of arguments");
142-
TypeArgs[0] = typeArg1;
143-
}
144-
145-
ImportHint(ImportHintKind kind, Type typeArg1, Type typeArg2) : Kind(kind) {
146-
assert(getNumTypeArgs(kind) == 2 && "Wrong number of arguments");
147-
TypeArgs[0] = typeArg1;
148-
TypeArgs[1] = typeArg2;
107+
ImportHint(ImportHintKind kind, Type bridgedType)
108+
: Kind(kind), BridgedType(bridgedType) {
109+
assert(kind == ImportHint::ObjCBridged && "Wrong kind for bridged type");
149110
}
150111
};
151112

@@ -162,10 +123,7 @@ namespace {
162123

163124
case ImportHint::Block:
164125
case ImportHint::CFPointer:
165-
case ImportHint::NSArray:
166-
case ImportHint::NSDictionary:
167-
case ImportHint::NSSet:
168-
case ImportHint::NSString:
126+
case ImportHint::ObjCBridged:
169127
case ImportHint::ObjCPointer:
170128
case ImportHint::CFunctionPointer:
171129
case ImportHint::CustomNullablePointer:
@@ -724,76 +682,91 @@ namespace {
724682
}
725683
}
726684

727-
if (imported->hasName() &&
728-
imported->getName()
729-
== Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSString)){
730-
return { importedType, ImportHint::NSString };
731-
}
732-
733-
if (imported->hasName() &&
734-
imported->getName()
735-
== Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSArray)) {
736-
// If we have type arguments, import them.
685+
// Determine whether this Objective-C class type is bridged to
686+
// a Swift type.
687+
NominalTypeDecl *bridgedTypeDecl = nullptr;
688+
StringRef objcClassName = objcClass->getName();
689+
if (objcClassName == "NSString")
690+
bridgedTypeDecl = Impl.SwiftContext.getStringDecl();
691+
else if (objcClassName == "NSArray")
692+
bridgedTypeDecl = Impl.SwiftContext.getArrayDecl();
693+
else if (objcClassName == "NSDictionary")
694+
bridgedTypeDecl = Impl.SwiftContext.getDictionaryDecl();
695+
else if (objcClassName == "NSSet")
696+
bridgedTypeDecl = Impl.SwiftContext.getSetDecl();
697+
698+
Type bridgedType;
699+
if (bridgedTypeDecl)
700+
bridgedType = bridgedTypeDecl->getDeclaredType();
701+
702+
if (bridgedType) {
703+
// Gather the type arguments.
704+
SmallVector<Type, 2> importedTypeArgs;
737705
ArrayRef<clang::QualType> typeArgs = type->getTypeArgs();
738-
if (typeArgs.size() == 1) {
739-
Type elementType = Impl.importType(typeArgs[0],
740-
ImportTypeKind::BridgedValue,
741-
AllowNSUIntegerAsInt,
742-
CanFullyBridgeTypes,
743-
OTK_None);
744-
return { importedType,
745-
ImportHint(ImportHint::NSArray, elementType) };
706+
SmallVector<clang::QualType, 2> typeArgsScratch;
707+
708+
// If we have an unspecialized form of a parameterized
709+
// Objective-C class type, fill in the defaults.
710+
if (typeArgs.empty()) {
711+
if (auto objcGenericParams = objcClass->getTypeParamList()) {
712+
objcGenericParams->gatherDefaultTypeArgs(typeArgsScratch);
713+
typeArgs = typeArgsScratch;
714+
}
746715
}
747716

748-
return { importedType, ImportHint(ImportHint::NSArray, Type()) };
749-
}
750-
751-
if (imported->hasName() &&
752-
imported->getName()
753-
== Impl.SwiftContext.getSwiftId(
754-
KnownFoundationEntity::NSDictionary)) {
755-
// If we have type arguments, import them.
756-
ArrayRef<clang::QualType> typeArgs = type->getTypeArgs();
757-
if (typeArgs.size() == 2) {
758-
Type keyType = Impl.importType(typeArgs[0],
759-
ImportTypeKind::BridgedValue,
760-
AllowNSUIntegerAsInt,
761-
CanFullyBridgeTypes,
762-
OTK_None);
763-
Type objectType = Impl.importType(typeArgs[1],
764-
ImportTypeKind::BridgedValue,
765-
AllowNSUIntegerAsInt,
766-
CanFullyBridgeTypes,
767-
OTK_None);
768-
if (keyType.isNull() != objectType.isNull()) {
769-
keyType = nullptr;
770-
objectType = nullptr;
717+
// Convert the type arguments.
718+
for (auto typeArg : typeArgs) {
719+
Type importedTypeArg = Impl.importType(typeArg,
720+
ImportTypeKind::BridgedValue,
721+
AllowNSUIntegerAsInt,
722+
CanFullyBridgeTypes,
723+
OTK_None);
724+
if (!importedTypeArg) {
725+
importedTypeArgs.clear();
726+
break;
771727
}
772728

773-
return { importedType,
774-
ImportHint(ImportHint::NSDictionary,
775-
keyType, objectType) };
729+
importedTypeArgs.push_back(importedTypeArg);
776730
}
777-
return { importedType,
778-
ImportHint(ImportHint::NSDictionary, Type(), Type()) };
779-
}
780731

781-
if (imported->hasName() &&
782-
imported->getName()
783-
== Impl.SwiftContext.getSwiftId(KnownFoundationEntity::NSSet)) {
784-
// If we have type arguments, import them.
785-
ArrayRef<clang::QualType> typeArgs = type->getTypeArgs();
786-
if (typeArgs.size() == 1) {
787-
Type elementType = Impl.importType(typeArgs[0],
788-
ImportTypeKind::BridgedValue,
789-
AllowNSUIntegerAsInt,
790-
CanFullyBridgeTypes,
791-
OTK_None);
792-
return { importedType,
793-
ImportHint(ImportHint::NSSet, elementType) };
732+
// If we have an unbound generic bridged type, get the arguments.
733+
if (auto unboundType = bridgedType->getAs<UnboundGenericType>()) {
734+
auto unboundDecl = unboundType->getDecl();
735+
auto bridgedSig = unboundDecl->getGenericSignature();
736+
assert(bridgedSig && "Bridged signature");
737+
unsigned numExpectedTypeArgs = bridgedSig->getGenericParams().size();
738+
if (importedTypeArgs.size() != numExpectedTypeArgs)
739+
return Type();
740+
741+
// The first type argument for Dictionary or Set needs
742+
// to be NSObject-bound.
743+
if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() ||
744+
unboundDecl == Impl.SwiftContext.getSetDecl()) {
745+
auto &keyType = importedTypeArgs[0];
746+
if (!Impl.matchesNSObjectBound(keyType))
747+
keyType = Impl.getNSObjectType();
748+
}
749+
750+
// Form the specialized type.
751+
if (unboundDecl == Impl.SwiftContext.getArrayDecl()) {
752+
// Type sugar for arrays.
753+
assert(importedTypeArgs.size() == 1);
754+
bridgedType = ArraySliceType::get(importedTypeArgs[0]);
755+
} else if (unboundDecl == Impl.SwiftContext.getDictionaryDecl()) {
756+
// Type sugar for dictionaries.
757+
assert(importedTypeArgs.size() == 2);
758+
bridgedType = DictionaryType::get(importedTypeArgs[0],
759+
importedTypeArgs[1]);
760+
} else {
761+
// Everything else.
762+
bridgedType =
763+
BoundGenericType::get(cast<NominalTypeDecl>(unboundDecl),
764+
Type(), importedTypeArgs);
765+
}
794766
}
795767

796-
return { importedType, ImportHint(ImportHint::NSSet, Type()) };
768+
return { importedType,
769+
ImportHint(ImportHint::ObjCBridged, bridgedType) };
797770
}
798771

799772
return { importedType, ImportHint::ObjCPointer };
@@ -898,6 +871,19 @@ static Type getUnmanagedType(ClangImporter::Implementation &impl,
898871
return unmanagedClassType;
899872
}
900873

874+
/// Determine whether type is 'NSString.
875+
static bool isNSString(Type type) {
876+
if (auto classType = type->getAs<ClassType>()) {
877+
if (auto clangDecl = classType->getDecl()->getClangDecl()) {
878+
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
879+
return objcClass->getName() == "NSString";
880+
}
881+
}
882+
}
883+
884+
return false;
885+
}
886+
901887
static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
902888
clang::QualType clangType,
903889
Type importedType,
@@ -919,10 +905,10 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
919905
}
920906

921907
// Import NSString * globals as String.
922-
if (hint == ImportHint::NSString &&
908+
if (hint == ImportHint::ObjCBridged && isNSString(importedType) &&
923909
(importKind == ImportTypeKind::Variable ||
924910
importKind == ImportTypeKind::AuditedVariable)) {
925-
return impl.getNamedSwiftType(impl.getStdlibModule(), "String");
911+
return hint.BridgedType;
926912
}
927913

928914
// Reference types are only permitted as function parameter types.
@@ -1079,63 +1065,11 @@ static Type adjustTypeForConcreteImport(ClangImporter::Implementation &impl,
10791065
importedType = getUnmanagedType(impl, importedType);
10801066
}
10811067

1082-
// When NSString* is the type of a function parameter or a function
1083-
// result type, map it to String.
1084-
// FIXME: It's not really safe to do this when Foundation is missing.
1085-
// We do it anyway for ImportForwardDeclarations mode so that generated
1086-
// interfaces are correct, but trying to use the resulting declarations
1087-
// may result in compiler crashes further down the line.
1088-
if (hint == ImportHint::NSString && canBridgeTypes(importKind) &&
1089-
(impl.tryLoadFoundationModule() || impl.ImportForwardDeclarations)) {
1090-
importedType = impl.SwiftContext.getStringDecl()->getDeclaredType();
1091-
}
1092-
1093-
1094-
// When NSArray* is the type of a function parameter or a function
1095-
// result type, map it to [AnyObject].
1096-
if (hint == ImportHint::NSArray && canBridgeTypes(importKind) &&
1097-
impl.tryLoadFoundationModule()) {
1098-
Type elementType = hint.TypeArgs[0];
1099-
if (elementType.isNull())
1100-
elementType = impl.getNamedSwiftType(impl.getStdlibModule(), "AnyObject");
1101-
importedType = ArraySliceType::get(elementType);
1102-
}
1103-
1104-
// When NSDictionary* is the type of a function parameter or a function
1105-
// result type, map it to [K : V].
1106-
if (hint == ImportHint::NSDictionary && canBridgeTypes(importKind) &&
1107-
impl.tryLoadFoundationModule()) {
1108-
Type keyType = hint.TypeArgs[0];
1109-
Type objectType = hint.TypeArgs[1];
1110-
1111-
// If no key type was provided, or the key doesn't match the 'NSObject'
1112-
// bound required by the Swift Dictionary key, substitute in 'NSObject'.
1113-
if (keyType.isNull() || !impl.matchesNSObjectBound(keyType)) {
1114-
keyType = impl.getNSObjectType();
1115-
}
1116-
1117-
if (objectType.isNull()) {
1118-
objectType = impl.getNamedSwiftType(impl.getStdlibModule(), "AnyObject");
1119-
}
1120-
1121-
importedType = DictionaryType::get(keyType, objectType);
1122-
}
1123-
1124-
// When NSSet* is the type of a function parameter or a function
1125-
// result type, map it to Set<T>.
1126-
if (hint == ImportHint::NSSet && canBridgeTypes(importKind) &&
1127-
impl.tryLoadFoundationModule()) {
1128-
Type elementType = hint.TypeArgs[0];
1129-
1130-
// If no element type was provided, or the element type doesn't match the
1131-
// 'NSObject' bound required by the Swift Set, substitute in 'NSObject'.
1132-
if (elementType.isNull() || !impl.matchesNSObjectBound(elementType))
1133-
elementType = impl.getNSObjectType();
1134-
1135-
importedType = impl.getNamedSwiftTypeSpecialization(impl.getStdlibModule(),
1136-
"Set",
1137-
elementType);
1138-
}
1068+
// If we have a bridged Objective-C type and we are allowed to
1069+
// bridge, do so.
1070+
if (hint == ImportHint::ObjCBridged && canBridgeTypes(importKind) &&
1071+
(impl.tryLoadFoundationModule() || impl.ImportForwardDeclarations))
1072+
importedType = hint.BridgedType;
11391073

11401074
if (!importedType)
11411075
return importedType;

test/SILGen/Inputs/usr/include/BridgeTestFoundation.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010

1111
@end
1212

13-
@interface NSArray : NSObject
13+
@interface NSArray<ObjectType> : NSObject
1414

15-
- (instancetype)initWithObjects:(const id *)objects count:(int)count;
16-
- (instancetype)initWithArray:(NSArray*)array;
15+
- (instancetype)initWithObjects:(const ObjectType *)objects count:(int)count;
16+
- (instancetype)initWithArray:(NSArray<ObjectType>*)array;
1717

1818
- (id)objectAtIndexedSubscript:(NSInteger)i;
1919

2020
@end
2121

22-
@interface NSDictionary : NSObject
22+
@interface NSDictionary<KeyType, ObjectType> : NSObject
2323
@end
2424

25-
@interface NSSet : NSObject
25+
@interface NSSet<ObjectType> : NSObject
2626
@end
2727

2828
@interface NSNumber : NSObject

0 commit comments

Comments
 (0)