@@ -731,26 +731,49 @@ tryCastToAnyHashable(
731
731
// TODO: Implement a fast path for NSString->AnyHashable casts.
732
732
// These are incredibly common because an NSDictionary with
733
733
// NSString keys is bridged by default to [AnyHashable:Any].
734
- // Until this is implemented, fall through to the default case
735
- SWIFT_FALLTHROUGH ;
734
+ // Until this is implemented, fall through to the general case
735
+ break ;
736
736
#else
737
- // If no Obj-C interop, just fall through to the default case.
738
- SWIFT_FALLTHROUGH ;
737
+ // If no Obj-C interop, just fall through to the general case.
738
+ break ;
739
739
#endif
740
740
}
741
- default : {
742
- auto hashableConformance = reinterpret_cast <const HashableWitnessTable *>(
743
- swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
744
- if (hashableConformance) {
745
- _swift_convertToAnyHashableIndirect (srcValue, destLocation,
746
- srcType, hashableConformance);
747
- return DynamicCastResult::SuccessViaCopy;
748
- } else {
749
- return DynamicCastResult::Failure;
741
+ case MetadataKind::Optional: {
742
+ // Until SR-9047 fixes the interactions between AnyHashable and Optional, we
743
+ // avoid directly injecting Optionals. In particular, this allows
744
+ // casts from [String?:String] to [AnyHashable:Any] to work the way people
745
+ // expect. Otherwise, without SR-9047, the resulting dictionary can only be
746
+ // indexed with an explicit Optional<String>, not a plain String.
747
+ // After SR-9047, we can consider dropping this special case entirely.
748
+
749
+ // !!!! This breaks compatibility with compiler-optimized casts
750
+ // (which just inject) and violates the Casting Spec. It just preserves
751
+ // the behavior of the older casting code until we can clean things up.
752
+ auto srcInnerType = cast<EnumMetadata>(srcType)->getGenericArgs ()[0 ];
753
+ unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload (
754
+ srcValue, /* emptyCases=*/ 1 );
755
+ auto nonNil = (sourceEnumCase == 0 );
756
+ if (nonNil) {
757
+ return DynamicCastResult::Failure; // Our caller will unwrap the optional and try again
750
758
}
759
+ // Else Optional is nil -- the general case below will inject it
760
+ break ;
751
761
}
762
+ default :
763
+ break ;
764
+ }
765
+
766
+
767
+ // General case: If it conforms to Hashable, we cast it
768
+ auto hashableConformance = reinterpret_cast <const HashableWitnessTable *>(
769
+ swift_conformsToProtocol (srcType, &HashableProtocolDescriptor));
770
+ if (hashableConformance) {
771
+ _swift_convertToAnyHashableIndirect (srcValue, destLocation,
772
+ srcType, hashableConformance);
773
+ return DynamicCastResult::SuccessViaCopy;
774
+ } else {
775
+ return DynamicCastResult::Failure;
752
776
}
753
- return DynamicCastResult::Failure;
754
777
}
755
778
756
779
static DynamicCastResult
0 commit comments