@@ -885,6 +885,8 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
885885 }
886886 };
887887
888+ bool sourceWrappedInOptional = false ;
889+
888890 if (auto sourceOptObjectType = sourceLoweredType.getOptionalObjectType ()) {
889891 // Translate the value from an enum representation to a possibly-null
890892 // representation. Note that we assume that this projection is safe
@@ -898,6 +900,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
898900 value = std::move (optValue);
899901 sourceLoweredType = sourceOptObjectType;
900902 sourceFormalType = sourceFormalType.getOptionalObjectType ();
903+ sourceWrappedInOptional = true ;
901904
902905 // We need a null-check because the runtime function can't handle null in
903906 // some of the cases.
@@ -1021,9 +1024,12 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
10211024 return ;
10221025 }
10231026
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);
10271033 return ;
10281034 }
10291035
@@ -1039,10 +1045,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
10391045// / It also avoids a call to the metadata accessor of the class (which calls
10401046// / `swift_getInitializedObjCClass`). For comparing the metadata pointers it's
10411047// / 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 ) {
10461052 if (!doesCastPreserveOwnershipForTypes (IGF.IGM .getSILModule (),
10471053 sourceFormalType, targetFormalType)) {
10481054 return nullptr ;
@@ -1074,6 +1080,19 @@ llvm::Value *irgen::emitFastClassCastIfPossible(IRGenFunction &IGF,
10741080 if (toClass->checkAncestry () & forbidden)
10751081 return nullptr ;
10761082
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+
10771096 // Get the metadata pointer of the destination class type.
10781097 llvm::Value *destMetadata = IGF.IGM .getAddrOfTypeMetadata (targetFormalType);
10791098 if (IGF.IGM .IRGen .Opts .LazyInitializeClassMetadata ) {
0 commit comments