mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Clang importer] Make sure that the first argument of Set/Dictionary types are Hashable.
Extend the check to make sure that the first type argument to an imported Set or Dictionary type is Hashable actually checks struct/enum types for Hashable conformances. Fixes rdar://problem/30622665.
This commit is contained in:
@@ -984,13 +984,12 @@ namespace {
|
||||
return Type();
|
||||
|
||||
// The first type argument for Dictionary or Set needs
|
||||
// to be Hashable. Everything that inherits NSObject has a
|
||||
// -hash code in ObjC, but if something isn't NSObject, fall back
|
||||
// to be Hashable. If something isn't Hashable, fall back
|
||||
// to AnyHashable as a key type.
|
||||
if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() ||
|
||||
unboundDecl == Impl.SwiftContext.getSetDecl()) {
|
||||
auto &keyType = importedTypeArgs[0];
|
||||
if (!Impl.matchesNSObjectBound(keyType)) {
|
||||
if (!Impl.matchesHashableBound(keyType)) {
|
||||
if (auto anyHashable = Impl.SwiftContext.getAnyHashableDecl())
|
||||
keyType = anyHashable->getDeclaredType();
|
||||
else
|
||||
@@ -2413,7 +2412,7 @@ Type ClangImporter::Implementation::getNSObjectType() {
|
||||
return Type();
|
||||
}
|
||||
|
||||
bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
|
||||
bool ClangImporter::Implementation::matchesHashableBound(Type type) {
|
||||
Type NSObjectType = getNSObjectType();
|
||||
if (!NSObjectType)
|
||||
return false;
|
||||
@@ -2425,8 +2424,14 @@ bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
|
||||
// Struct or enum type must have been bridged.
|
||||
// TODO: Check that the bridged type is Hashable?
|
||||
if (type->getStructOrBoundGenericStruct() ||
|
||||
type->getEnumOrBoundGenericEnum())
|
||||
return true;
|
||||
type->getEnumOrBoundGenericEnum()) {
|
||||
auto nominal = type->getAnyNominal();
|
||||
auto hashable = SwiftContext.getProtocol(KnownProtocolKind::Hashable);
|
||||
SmallVector<ProtocolConformance *, 2> conformances;
|
||||
return hashable &&
|
||||
nominal->lookupConformance(nominal->getParentModule(), hashable,
|
||||
conformances);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -886,7 +886,7 @@ public:
|
||||
|
||||
/// \brief Determines whether the given type matches an implicit type
|
||||
/// bound of "Hashable", which is used to validate NSDictionary/NSSet.
|
||||
bool matchesNSObjectBound(Type type);
|
||||
bool matchesHashableBound(Type type);
|
||||
|
||||
/// \brief Look up and attempt to import a Clang declaration with
|
||||
/// the given name.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@import ObjectiveC;
|
||||
@import Foundation;
|
||||
|
||||
@interface ObjCBridgeNonconforming
|
||||
@property NSSet<NSDictionary<NSString *, id> *> * _Nonnull foo;
|
||||
@end
|
||||
@@ -175,3 +175,7 @@ module MacrosRedefB {
|
||||
module IndirectFields {
|
||||
header "IndirectFields.h"
|
||||
}
|
||||
|
||||
module ObjCBridgeNonconforming {
|
||||
header "ObjCBridgeNonconforming.h"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 %s
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 -I %S/Inputs/custom-modules %s
|
||||
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
import Foundation
|
||||
import objc_generics
|
||||
import ObjCBridgeNonconforming
|
||||
|
||||
func testNSArrayBridging(_ hive: Hive) {
|
||||
_ = hive.bees as [Bee]
|
||||
@@ -392,3 +393,8 @@ let third: Third! = Third()
|
||||
func useThird() {
|
||||
_ = third.description
|
||||
}
|
||||
|
||||
|
||||
func testNonconforming(bnc: ObjCBridgeNonconforming) {
|
||||
let _: Int = bnc.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user