@@ -709,8 +709,49 @@ tryCastToAnyHashable(
709709 assert (cast<StructMetadata>(destType)->Description
710710 == &STRUCT_TYPE_DESCR_SYM (s11AnyHashable));
711711
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
712753 auto hashableConformance = reinterpret_cast <const HashableWitnessTable *>(
713- swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
754+ swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
714755 if (hashableConformance) {
715756 _swift_convertToAnyHashableIndirect (srcValue, destLocation,
716757 srcType, hashableConformance);
0 commit comments