Skip to content

Commit 41492f2

Browse files
committed
[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. (cherry picked from commit aa215e7)
1 parent 4065cdd commit 41492f2

File tree

5 files changed

+29
-8
lines changed

5 files changed

+29
-8
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -984,13 +984,12 @@ namespace {
984984
return Type();
985985

986986
// The first type argument for Dictionary or Set needs
987-
// to be Hashable. Everything that inherits NSObject has a
988-
// -hash code in ObjC, but if something isn't NSObject, fall back
987+
// to be Hashable. If something isn't Hashable, fall back
989988
// to AnyHashable as a key type.
990989
if (unboundDecl == Impl.SwiftContext.getDictionaryDecl() ||
991990
unboundDecl == Impl.SwiftContext.getSetDecl()) {
992991
auto &keyType = importedTypeArgs[0];
993-
if (!Impl.matchesNSObjectBound(keyType)) {
992+
if (!Impl.matchesHashableBound(keyType)) {
994993
if (auto anyHashable = Impl.SwiftContext.getAnyHashableDecl())
995994
keyType = anyHashable->getDeclaredType();
996995
else
@@ -2413,7 +2412,7 @@ Type ClangImporter::Implementation::getNSObjectType() {
24132412
return Type();
24142413
}
24152414

2416-
bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
2415+
bool ClangImporter::Implementation::matchesHashableBound(Type type) {
24172416
Type NSObjectType = getNSObjectType();
24182417
if (!NSObjectType)
24192418
return false;
@@ -2425,8 +2424,14 @@ bool ClangImporter::Implementation::matchesNSObjectBound(Type type) {
24252424
// Struct or enum type must have been bridged.
24262425
// TODO: Check that the bridged type is Hashable?
24272426
if (type->getStructOrBoundGenericStruct() ||
2428-
type->getEnumOrBoundGenericEnum())
2429-
return true;
2427+
type->getEnumOrBoundGenericEnum()) {
2428+
auto nominal = type->getAnyNominal();
2429+
auto hashable = SwiftContext.getProtocol(KnownProtocolKind::Hashable);
2430+
SmallVector<ProtocolConformance *, 2> conformances;
2431+
return hashable &&
2432+
nominal->lookupConformance(nominal->getParentModule(), hashable,
2433+
conformances);
2434+
}
24302435

24312436
return false;
24322437
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
886886

887887
/// \brief Determines whether the given type matches an implicit type
888888
/// bound of "Hashable", which is used to validate NSDictionary/NSSet.
889-
bool matchesNSObjectBound(Type type);
889+
bool matchesHashableBound(Type type);
890890

891891
/// \brief Look up and attempt to import a Clang declaration with
892892
/// the given name.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@import ObjectiveC;
2+
@import Foundation;
3+
4+
@interface ObjCBridgeNonconforming
5+
@property NSSet<NSDictionary<NSString *, id> *> * _Nonnull foo;
6+
@end

test/ClangImporter/Inputs/custom-modules/module.map

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,7 @@ module MacrosRedefB {
175175
module IndirectFields {
176176
header "IndirectFields.h"
177177
}
178+
179+
module ObjCBridgeNonconforming {
180+
header "ObjCBridgeNonconforming.h"
181+
}

test/ClangImporter/objc_bridging_generics.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 %s
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -parse-as-library -verify -swift-version 4 -I %S/Inputs/custom-modules %s
22

33
// REQUIRES: objc_interop
44

55
import Foundation
66
import objc_generics
7+
import ObjCBridgeNonconforming
78

89
func testNSArrayBridging(_ hive: Hive) {
910
_ = hive.bees as [Bee]
@@ -392,3 +393,8 @@ let third: Third! = Third()
392393
func useThird() {
393394
_ = third.description
394395
}
396+
397+
398+
func testNonconforming(bnc: ObjCBridgeNonconforming) {
399+
let _: Int = bnc.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
400+
}

0 commit comments

Comments
 (0)