[ClangImporter] Generic parameters can be Hashable too! (#10900)
aa215e7e54 made sure we didn't try to construct Sets and Dictionaries
with a non-Hashable key. However, that commit was a little too
restrictive: there was no handling for imported generic parameters
that were constrained to inherit from NSObject. Fortunately,
recovering that information is fairly straightforward.
rdar://problem/33222646
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index c195326..28771e7 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -2417,6 +2417,15 @@
if (!NSObjectType)
return false;
+ // Match generic parameters against their bounds.
+ if (auto *genericTy = type->getAs<GenericTypeParamType>()) {
+ if (auto *generic = genericTy->getDecl()) {
+ type = generic->getSuperclass();
+ if (!type)
+ return false;
+ }
+ }
+
// Class type or existential that inherits from NSObject.
if (NSObjectType->isExactSuperclassOf(type))
return true;
diff --git a/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h b/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h
index e68e7b1..9f49a39 100644
--- a/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h
+++ b/test/ClangImporter/Inputs/custom-modules/ObjCBridgeNonconforming.h
@@ -4,3 +4,26 @@
@interface ObjCBridgeNonconforming
@property NSSet<NSDictionary<NSString *, id> *> * _Nonnull foo;
@end
+
+@interface ObjCBridgeGeneric<Element> : NSObject
+@property NSSet<Element> * _Nonnull foo;
+@end
+
+@interface ElementBase : NSObject
+@end
+@protocol ExtraElementProtocol
+@end
+@interface ElementConcrete : ElementBase <ExtraElementProtocol>
+@end
+
+@interface ObjCBridgeGenericConstrained<Element: ElementBase *> : NSObject
+@property NSSet<Element> * _Nonnull foo;
+@end
+
+@interface ObjCBridgeGenericInsufficientlyConstrained<Element: id <NSObject>> : NSObject
+@property NSSet<Element> * _Nonnull foo;
+@end
+
+@interface ObjCBridgeGenericConstrainedExtra<Element: NSObject <ExtraElementProtocol> *> : NSObject
+@property NSSet<Element> * _Nonnull foo;
+@end
diff --git a/test/ClangImporter/objc_bridging_generics.swift b/test/ClangImporter/objc_bridging_generics.swift
index 6e15c0d..6fee23f 100644
--- a/test/ClangImporter/objc_bridging_generics.swift
+++ b/test/ClangImporter/objc_bridging_generics.swift
@@ -398,3 +398,14 @@
func testNonconforming(bnc: ObjCBridgeNonconforming) {
let _: Int = bnc.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
}
+
+func testHashableGenerics(
+ any: ObjCBridgeGeneric<ElementConcrete>,
+ constrained: ObjCBridgeGenericConstrained<ElementConcrete>,
+ insufficient: ObjCBridgeGenericInsufficientlyConstrained<ElementConcrete>,
+ extra: ObjCBridgeGenericConstrainedExtra<ElementConcrete>) {
+ let _: Int = any.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
+ let _: Int = constrained.foo // expected-error{{cannot convert value of type 'Set<ElementConcrete>' to specified type 'Int'}}
+ let _: Int = insufficient.foo // expected-error{{cannot convert value of type 'Set<AnyHashable>' to specified type 'Int'}}
+ let _: Int = extra.foo // expected-error{{cannot convert value of type 'Set<ElementConcrete>' to specified type 'Int'}}
+}