@@ -709,8 +709,49 @@ tryCastToAnyHashable(
709
709
assert (cast<StructMetadata>(destType)->Description
710
710
== &STRUCT_TYPE_DESCR_SYM (s11AnyHashable));
711
711
712
+ switch (srcType->getKind ()) {
713
+ case MetadataKind::ForeignClass: // CF -> String
714
+ case MetadataKind::ObjCClassWrapper: { // Obj-C -> String
715
+ #if SWIFT_OBJC_INTEROP
716
+ // TODO: Implement a fast path for NSString->AnyHashable casts.
717
+ // These are incredibly common because an NSDictionary with
718
+ // NSString keys is bridged by default to [AnyHashable:Any].
719
+ // Until this is implemented, fall through to the general case
720
+ break ;
721
+ #else
722
+ // If no Obj-C interop, just fall through to the general case.
723
+ break ;
724
+ #endif
725
+ }
726
+ case MetadataKind::Optional: {
727
+ // Until SR-9047 fixes the interactions between AnyHashable and Optional, we
728
+ // avoid directly injecting Optionals. In particular, this allows
729
+ // casts from [String?:String] to [AnyHashable:Any] to work the way people
730
+ // expect. Otherwise, without SR-9047, the resulting dictionary can only be
731
+ // indexed with an explicit Optional<String>, not a plain String.
732
+ // After SR-9047, we can consider dropping this special case entirely.
733
+
734
+ // !!!! This breaks compatibility with compiler-optimized casts
735
+ // (which just inject) and violates the Casting Spec. It just preserves
736
+ // the behavior of the older casting code until we can clean things up.
737
+ auto srcInnerType = cast<EnumMetadata>(srcType)->getGenericArgs ()[0 ];
738
+ unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload (
739
+ srcValue, /* emptyCases=*/ 1 );
740
+ auto nonNil = (sourceEnumCase == 0 );
741
+ if (nonNil) {
742
+ return DynamicCastResult::Failure; // Our caller will unwrap the optional and try again
743
+ }
744
+ // Else Optional is nil -- the general case below will inject it
745
+ break ;
746
+ }
747
+ default :
748
+ break ;
749
+ }
750
+
751
+
752
+ // General case: If it conforms to Hashable, we cast it
712
753
auto hashableConformance = reinterpret_cast <const HashableWitnessTable *>(
713
- swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
754
+ swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
714
755
if (hashableConformance) {
715
756
_swift_convertToAnyHashableIndirect (srcValue, destLocation,
716
757
srcType, hashableConformance);
0 commit comments