@@ -885,6 +885,8 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
885
885
}
886
886
};
887
887
888
+ bool sourceWrappedInOptional = false ;
889
+
888
890
if (auto sourceOptObjectType = sourceLoweredType.getOptionalObjectType ()) {
889
891
// Translate the value from an enum representation to a possibly-null
890
892
// representation. Note that we assume that this projection is safe
@@ -898,6 +900,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
898
900
value = std::move (optValue);
899
901
sourceLoweredType = sourceOptObjectType;
900
902
sourceFormalType = sourceFormalType.getOptionalObjectType ();
903
+ sourceWrappedInOptional = true ;
901
904
902
905
// We need a null-check because the runtime function can't handle null in
903
906
// some of the cases.
@@ -1021,9 +1024,12 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
1021
1024
return ;
1022
1025
}
1023
1026
1024
- if (llvm::Value *fastResult = emitFastClassCastIfPossible (IGF, instance,
1025
- sourceFormalType, targetFormalType)) {
1026
- out.add (fastResult);
1027
+ if (llvm::Value *fastResult = emitFastClassCastIfPossible (
1028
+ IGF, instance, sourceFormalType, targetFormalType,
1029
+ sourceWrappedInOptional, nilCheckBB, nilMergeBB)) {
1030
+ Explosion fastExplosion;
1031
+ fastExplosion.add (fastResult);
1032
+ returnNilCheckedResult (IGF.Builder , fastExplosion);
1027
1033
return ;
1028
1034
}
1029
1035
@@ -1039,10 +1045,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
1039
1045
// / It also avoids a call to the metadata accessor of the class (which calls
1040
1046
// / `swift_getInitializedObjCClass`). For comparing the metadata pointers it's
1041
1047
// / not required that the metadata is fully initialized.
1042
- llvm::Value *irgen::emitFastClassCastIfPossible (IRGenFunction &IGF,
1043
- llvm::Value *instance,
1044
- CanType sourceFormalType ,
1045
- CanType targetFormalType ) {
1048
+ llvm::Value *irgen::emitFastClassCastIfPossible (
1049
+ IRGenFunction &IGF, llvm::Value *instance, CanType sourceFormalType ,
1050
+ CanType targetFormalType, bool sourceWrappedInOptional ,
1051
+ llvm::BasicBlock *&nilCheckBB, llvm::BasicBlock *&nilMergeBB ) {
1046
1052
if (!doesCastPreserveOwnershipForTypes (IGF.IGM .getSILModule (),
1047
1053
sourceFormalType, targetFormalType)) {
1048
1054
return nullptr ;
@@ -1074,6 +1080,19 @@ llvm::Value *irgen::emitFastClassCastIfPossible(IRGenFunction &IGF,
1074
1080
if (toClass->checkAncestry () & forbidden)
1075
1081
return nullptr ;
1076
1082
1083
+ // If the source was originally wrapped in an Optional, check it for nil now.
1084
+ if (sourceWrappedInOptional) {
1085
+ auto isNotNil = IGF.Builder .CreateICmpNE (
1086
+ instance, llvm::ConstantPointerNull::get (
1087
+ cast<llvm::PointerType>(instance->getType ())));
1088
+ auto *isNotNilContBB = llvm::BasicBlock::Create (IGF.IGM .getLLVMContext ());
1089
+ nilMergeBB = llvm::BasicBlock::Create (IGF.IGM .getLLVMContext ());
1090
+ nilCheckBB = IGF.Builder .GetInsertBlock ();
1091
+ IGF.Builder .CreateCondBr (isNotNil, isNotNilContBB, nilMergeBB);
1092
+
1093
+ IGF.Builder .emitBlock (isNotNilContBB);
1094
+ }
1095
+
1077
1096
// Get the metadata pointer of the destination class type.
1078
1097
llvm::Value *destMetadata = IGF.IGM .getAddrOfTypeMetadata (targetFormalType);
1079
1098
if (IGF.IGM .IRGen .Opts .LazyInitializeClassMetadata ) {
0 commit comments