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();
|
return Type();
|
||||||
|
|
||||||
// The first type argument for Dictionary or Set needs
|
// The first type argument for Dictionary or Set needs
|
||||||
// to be Hashable. Everything that inherits NSObject has a
|
// to be Hashable. If something isn't Hashable, fall back
|
||||||
// -hash code in ObjC, but if something isn't NSObject, fall back
|
|
||||||
// to AnyHashable as a key type.
|
// to AnyHashable as a key type.
|
||||||
if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() ||
|
if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() ||
|
||||||
unboundDecl == Impl.SwiftContext.getSetDecl()) {
|
unboundDecl == Impl.SwiftContext.getSetDecl()) {
|
||||||
auto &keyType = importedTypeArgs[0];
|
auto &keyType = importedTypeArgs[0];
|
||||||
if (!Impl.matchesNSObjectBound(keyType)) {
|
if (!Impl.matchesHashableBound(keyType)) {
|
||||||
if (auto anyHashable = Impl.SwiftContext.getAnyHashableDecl())
|
if (auto anyHashable = Impl.SwiftContext.getAnyHashableDecl())
|
||||||
keyType = anyHashable->getDeclaredType();
|
keyType = anyHashable->getDeclaredType();
|
||||||
else
|
else
|
||||||
@@ -2413,7 +2412,7 @@ Type ClangImporter::Implementation::getNSObjectType() {
|
|||||||
return Type();
|
return Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
|
bool ClangImporter::Implementation::matchesHashableBound(Type type) {
|
||||||
Type NSObjectType = getNSObjectType();
|
Type NSObjectType = getNSObjectType();
|
||||||
if (!NSObjectType)
|
if (!NSObjectType)
|
||||||
return false;
|
return false;
|
||||||
@@ -2425,8 +2424,14 @@ bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
|
|||||||
// Struct or enum type must have been bridged.
|
// Struct or enum type must have been bridged.
|
||||||
// TODO: Check that the bridged type is Hashable?
|
// TODO: Check that the bridged type is Hashable?
|
||||||
if (type->getStructOrBoundGenericStruct() ||
|
if (type->getStructOrBoundGenericStruct() ||
|
||||||
type->getEnumOrBoundGenericEnum())
|
type->getEnumOrBoundGenericEnum()) {
|
||||||
return true;
|
auto nominal = type->getAnyNominal();
|
||||||
|
auto hashable = SwiftContext.getProtocol(KnownProtocolKind::Hashable);
|
||||||
|
SmallVector<ProtocolConformance *, 2> conformances;
|
||||||
|
return hashable &&
|
||||||
|
nominal->lookupConformance(nominal->getParentModule(), hashable,
|
||||||
|
conformances);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -886,7 +886,7 @@ public:
|
|||||||
|
|
||||||
/// \brief Determines whether the given type matches an implicit type
|
/// \brief Determines whether the given type matches an implicit type
|
||||||
/// bound of "Hashable", which is used to validate NSDictionary/NSSet.
|
/// 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
|
/// \brief Look up and attempt to import a Clang declaration with
|
||||||
/// the given name.
|
/// 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 {
|
module IndirectFields {
|
||||||
header "IndirectFields.h"
|
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
|
// REQUIRES: objc_interop
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import objc_generics
|
import objc_generics
|
||||||
|
import ObjCBridgeNonconforming
|
||||||
|
|
||||||
func testNSArrayBridging(_ hive: Hive) {
|
func testNSArrayBridging(_ hive: Hive) {
|
||||||
_ = hive.bees as [Bee]
|
_ = hive.bees as [Bee]
|
||||||
@@ -392,3 +393,8 @@ let third: Third! = Third()
|
|||||||
func useThird() {
|
func useThird() {
|
||||||
_ = third.description
|
_ = 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