mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[ClangImporter] Add support for 'SwiftImportAsNonGeneric' in API notes (#6962)
Generic Objective-C classes with this annotation will be imported as non-generic in Swift. The Swift 3 behavior hardcoded a certain set of class /hierarchies/ as permanently non-generic, and this is preserved in Swift 3 mode. Actually using this API note in a versioned way (as opposed to just marking the class non-generic in all language versions) will cause horrible source compatibility problems in the mix-and-match cases, where Swift 3 code presents a non-generic type that Swift 4 expects to be generic or vice versa. Fixes for this will come later; right now it's more important to add support for the feature at all. To avoid unwanted changes in Swift 4, this commit also adds API notes to make any existing classes in the previously-hardcoded set continue to import as non-generic even in Swift 4. The difference is that /subclasses/ of these classes may come in as generic. (If we want to make a change here, that can be a separate commit.) rdar://problem/31226414 (Swift side of rdar://problem/28455962)
This commit is contained in:
@@ -38,6 +38,7 @@ set(SWIFT_API_NOTES_INPUTS
|
|||||||
QuickLook
|
QuickLook
|
||||||
SafariServices
|
SafariServices
|
||||||
SceneKit
|
SceneKit
|
||||||
|
ScriptingBridge
|
||||||
SpriteKit
|
SpriteKit
|
||||||
StoreKit
|
StoreKit
|
||||||
TVMLKit
|
TVMLKit
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ Classes:
|
|||||||
SwiftBridge: AffineTransform
|
SwiftBridge: AffineTransform
|
||||||
- Name: NSArray
|
- Name: NSArray
|
||||||
SwiftBridge: Swift.Array
|
SwiftBridge: Swift.Array
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
Methods:
|
Methods:
|
||||||
- Selector: 'pathsMatchingExtensions:'
|
- Selector: 'pathsMatchingExtensions:'
|
||||||
SwiftName: pathsMatchingExtensions(_:)
|
SwiftName: pathsMatchingExtensions(_:)
|
||||||
@@ -12,6 +13,15 @@ Classes:
|
|||||||
- Selector: 'filteredArrayUsingPredicate:'
|
- Selector: 'filteredArrayUsingPredicate:'
|
||||||
SwiftName: filtered(using:)
|
SwiftName: filtered(using:)
|
||||||
MethodKind: Instance
|
MethodKind: Instance
|
||||||
|
- Name: NSMutableArray
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
|
Methods:
|
||||||
|
- Selector: 'removeObjectIdenticalTo:inRange:'
|
||||||
|
SwiftName: removeObject(identicalTo:in:)
|
||||||
|
MethodKind: Instance
|
||||||
|
- Selector: 'removeObjectIdenticalTo:'
|
||||||
|
SwiftName: removeObject(identicalTo:)
|
||||||
|
MethodKind: Instance
|
||||||
- Name: NSCachedURLResponse
|
- Name: NSCachedURLResponse
|
||||||
SwiftName: CachedURLResponse
|
SwiftName: CachedURLResponse
|
||||||
- Name: NSCharacterSet
|
- Name: NSCharacterSet
|
||||||
@@ -51,6 +61,8 @@ Classes:
|
|||||||
- Selector: 'hasMemberInPlane:'
|
- Selector: 'hasMemberInPlane:'
|
||||||
SwiftName: hasMemberInPlane(_:)
|
SwiftName: hasMemberInPlane(_:)
|
||||||
MethodKind: Instance
|
MethodKind: Instance
|
||||||
|
- Name: NSCountedSet
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSData
|
- Name: NSData
|
||||||
SwiftBridge: Data
|
SwiftBridge: Data
|
||||||
Methods:
|
Methods:
|
||||||
@@ -85,6 +97,8 @@ Classes:
|
|||||||
SwiftBridge: DateComponents
|
SwiftBridge: DateComponents
|
||||||
- Name: NSDateInterval
|
- Name: NSDateInterval
|
||||||
SwiftBridge: DateInterval
|
SwiftBridge: DateInterval
|
||||||
|
- Name: NSEnumerator
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSError
|
- Name: NSError
|
||||||
SwiftBridge: Swift.Error
|
SwiftBridge: Swift.Error
|
||||||
Methods:
|
Methods:
|
||||||
@@ -93,12 +107,18 @@ Classes:
|
|||||||
MethodKind: Class
|
MethodKind: Class
|
||||||
- Name: NSDictionary
|
- Name: NSDictionary
|
||||||
SwiftBridge: Swift.Dictionary
|
SwiftBridge: Swift.Dictionary
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
|
- Name: NSMutableDictionary
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSSet
|
- Name: NSSet
|
||||||
SwiftBridge: Swift.Set
|
SwiftBridge: Swift.Set
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
Methods:
|
Methods:
|
||||||
- Selector: 'filteredSetUsingPredicate:'
|
- Selector: 'filteredSetUsingPredicate:'
|
||||||
SwiftName: filtered(using:)
|
SwiftName: filtered(using:)
|
||||||
MethodKind: Instance
|
MethodKind: Instance
|
||||||
|
- Name: NSMutableSet
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSString
|
- Name: NSString
|
||||||
SwiftBridge: Swift.String
|
SwiftBridge: Swift.String
|
||||||
Methods:
|
Methods:
|
||||||
@@ -313,14 +333,7 @@ Classes:
|
|||||||
MethodKind: Instance
|
MethodKind: Instance
|
||||||
- Name: NSMeasurement
|
- Name: NSMeasurement
|
||||||
SwiftBridge: Measurement
|
SwiftBridge: Measurement
|
||||||
- Name: NSMutableArray
|
SwiftImportAsNonGeneric: true
|
||||||
Methods:
|
|
||||||
- Selector: 'removeObjectIdenticalTo:inRange:'
|
|
||||||
SwiftName: removeObject(identicalTo:in:)
|
|
||||||
MethodKind: Instance
|
|
||||||
- Selector: 'removeObjectIdenticalTo:'
|
|
||||||
SwiftName: removeObject(identicalTo:)
|
|
||||||
MethodKind: Instance
|
|
||||||
- Name: NSMutableData
|
- Name: NSMutableData
|
||||||
Methods:
|
Methods:
|
||||||
- Selector: 'appendBytes:length:'
|
- Selector: 'appendBytes:length:'
|
||||||
@@ -445,6 +458,7 @@ Classes:
|
|||||||
- Name: unsignedIntegerValue
|
- Name: unsignedIntegerValue
|
||||||
SwiftName: uintValue
|
SwiftName: uintValue
|
||||||
- Name: NSOrderedSet
|
- Name: NSOrderedSet
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
Methods:
|
Methods:
|
||||||
- Selector: 'enumerateObjectsWithOptions:usingBlock:'
|
- Selector: 'enumerateObjectsWithOptions:usingBlock:'
|
||||||
SwiftName: enumerateObjects(options:using:)
|
SwiftName: enumerateObjects(options:using:)
|
||||||
@@ -470,6 +484,8 @@ Classes:
|
|||||||
- Selector: 'indexOfObjectWithOptions:passingTest:'
|
- Selector: 'indexOfObjectWithOptions:passingTest:'
|
||||||
SwiftName: index(_:ofObjectPassingTest:)
|
SwiftName: index(_:ofObjectPassingTest:)
|
||||||
MethodKind: Instance
|
MethodKind: Instance
|
||||||
|
- Name: NSMutableOrderedSet
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSTask
|
- Name: NSTask
|
||||||
SwiftName: Process
|
SwiftName: Process
|
||||||
Methods:
|
Methods:
|
||||||
@@ -932,6 +948,7 @@ Classes:
|
|||||||
SwiftName: ValueTransformer
|
SwiftName: ValueTransformer
|
||||||
- Name: NSDirectoryEnumerator
|
- Name: NSDirectoryEnumerator
|
||||||
SwiftName: FileManager.DirectoryEnumerator
|
SwiftName: FileManager.DirectoryEnumerator
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
- Name: NSDimension
|
- Name: NSDimension
|
||||||
SwiftName: Dimension
|
SwiftName: Dimension
|
||||||
- Name: NSUnit
|
- Name: NSUnit
|
||||||
|
|||||||
5
apinotes/ScriptingBridge.apinotes
Normal file
5
apinotes/ScriptingBridge.apinotes
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
Name: ScriptingBridge
|
||||||
|
Classes:
|
||||||
|
- Name: SBElementArray
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
@@ -1713,7 +1713,14 @@ getAccessorPropertyType(const clang::FunctionDecl *accessor, bool isSetter,
|
|||||||
/// Whether we should suppress importing the Objective-C generic type params
|
/// Whether we should suppress importing the Objective-C generic type params
|
||||||
/// of this class as Swift generic type params.
|
/// of this class as Swift generic type params.
|
||||||
static bool
|
static bool
|
||||||
shouldSuppressGenericParamsImport(const clang::ObjCInterfaceDecl *decl) {
|
shouldSuppressGenericParamsImport(const LangOptions &langOpts,
|
||||||
|
const clang::ObjCInterfaceDecl *decl) {
|
||||||
|
if (decl->hasAttr<clang::SwiftImportAsNonGenericAttr>())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (langOpts.isSwiftVersion3()) {
|
||||||
|
// In Swift 3 we used a hardcoded list of declarations, and made all of
|
||||||
|
// their subclasses drop their generic parameters when imported.
|
||||||
while (decl) {
|
while (decl) {
|
||||||
StringRef name = decl->getName();
|
StringRef name = decl->getName();
|
||||||
if (name == "NSArray" || name == "NSDictionary" || name == "NSSet" ||
|
if (name == "NSArray" || name == "NSDictionary" || name == "NSSet" ||
|
||||||
@@ -1723,6 +1730,8 @@ shouldSuppressGenericParamsImport(const clang::ObjCInterfaceDecl *decl) {
|
|||||||
}
|
}
|
||||||
decl = decl->getSuperClass();
|
decl = decl->getSuperClass();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6149,7 +6158,7 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
|
|||||||
if (!typeParamList) {
|
if (!typeParamList) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (shouldSuppressGenericParamsImport(decl)) {
|
if (shouldSuppressGenericParamsImport(Impl.SwiftContext.LangOpts, decl)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
assert(typeParamList->size() > 0);
|
assert(typeParamList->size() > 0);
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ SwiftVersions:
|
|||||||
- Name: accessorsOnlyRenamedRetypedClass
|
- Name: accessorsOnlyRenamedRetypedClass
|
||||||
PropertyKind: Class
|
PropertyKind: Class
|
||||||
SwiftImportAsAccessors: true
|
SwiftImportAsAccessors: true
|
||||||
|
- Name: NewlyGenericSub
|
||||||
|
SwiftImportAsNonGeneric: true
|
||||||
Protocols:
|
Protocols:
|
||||||
- Name: ProtoWithVersionedUnavailableMember
|
- Name: ProtoWithVersionedUnavailableMember
|
||||||
Methods:
|
Methods:
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ __attribute__((objc_root_class))
|
|||||||
-(nonnull id)methodWithA:(nonnull id)a;
|
-(nonnull id)methodWithA:(nonnull id)a;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_root_class))
|
||||||
|
@interface Base
|
||||||
|
@end
|
||||||
|
|
||||||
#endif // __OBJC__
|
#endif // __OBJC__
|
||||||
|
|
||||||
|
#import <APINotesFrameworkTest/Classes.h>
|
||||||
#import <APINotesFrameworkTest/ImportAsMember.h>
|
#import <APINotesFrameworkTest/ImportAsMember.h>
|
||||||
#import <APINotesFrameworkTest/Properties.h>
|
#import <APINotesFrameworkTest/Properties.h>
|
||||||
#import <APINotesFrameworkTest/Protocols.h>
|
#import <APINotesFrameworkTest/Protocols.h>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifdef __OBJC__
|
||||||
|
#pragma clang assume_nonnull begin
|
||||||
|
|
||||||
|
@interface NewlyGenericSub<Element> : Base
|
||||||
|
+ (Element)defaultElement;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma clang assume_nonnull end
|
||||||
|
#endif // __OBJC__
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
#pragma clang assume_nonnull begin
|
#pragma clang assume_nonnull begin
|
||||||
|
|
||||||
__attribute__((objc_root_class))
|
|
||||||
@interface Base
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface TestProperties: Base
|
@interface TestProperties: Base
|
||||||
@property (nonatomic, readwrite, retain) id accessorsOnly;
|
@property (nonatomic, readwrite, retain) id accessorsOnly;
|
||||||
@property (nonatomic, readwrite, retain, class) id accessorsOnlyForClass;
|
@property (nonatomic, readwrite, retain, class) id accessorsOnlyForClass;
|
||||||
|
|||||||
@@ -13,4 +13,14 @@ class ProtoWithVersionedUnavailableMemberImpl: ProtoWithVersionedUnavailableMemb
|
|||||||
func requirement() -> Any? { return nil }
|
func requirement() -> Any? { return nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNonGeneric() {
|
||||||
|
// CHECK-DIAGS-3:[[@LINE+1]]:{{[0-9]+}}: error: cannot convert value of type 'Any' to specified type 'Int'
|
||||||
|
let _: Int = NewlyGenericSub.defaultElement()
|
||||||
|
// CHECK-DIAGS-4:[[@LINE-1]]:{{[0-9]+}}: error: generic parameter 'Element' could not be inferred
|
||||||
|
|
||||||
|
// CHECK-DIAGS-3:[[@LINE+1]]:{{[0-9]+}}: error: cannot specialize non-generic type 'NewlyGenericSub'
|
||||||
|
let _: Int = NewlyGenericSub<Base>.defaultElement()
|
||||||
|
// CHECK-DIAGS-4:[[@LINE-1]]:{{[0-9]+}}: error: cannot convert value of type 'Base' to specified type 'Int'
|
||||||
|
}
|
||||||
|
|
||||||
let unrelatedDiagnostic: Int = nil
|
let unrelatedDiagnostic: Int = nil
|
||||||
|
|||||||
Reference in New Issue
Block a user