@@ -544,8 +544,8 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
544544// / Emit a checked cast to a protocol or protocol composition.
545545void irgen::emitScalarExistentialDowncast (
546546 IRGenFunction &IGF, llvm::Value *value, SILType srcType, SILType destType,
547- CheckedCastMode mode, std::optional<MetatypeRepresentation> metatypeKind ,
548- Explosion &ex) {
547+ CheckedCastMode mode, bool sourceWrappedInOptional ,
548+ std::optional<MetatypeRepresentation> metatypeKind, Explosion &ex) {
549549 auto srcInstanceType = srcType.getASTType ();
550550 auto destInstanceType = destType.getASTType ();
551551 while (auto metatypeType = dyn_cast<ExistentialMetatypeType>(
@@ -800,7 +800,36 @@ void irgen::emitScalarExistentialDowncast(
800800 for (auto proto : witnessTableProtos)
801801 args.push_back (proto);
802802
803- auto valueAndWitnessTables = IGF.Builder .CreateCall (fn, args);
803+ llvm::BasicBlock *nilCheckedCont = nullptr ;
804+ llvm::BasicBlock *nilBB = nullptr ;
805+ llvm::BasicBlock *nonNilBB = nullptr ;
806+ if (sourceWrappedInOptional) {
807+ nilBB = IGF.createBasicBlock (" is-nil" );
808+ nonNilBB = IGF.createBasicBlock (" is-non-nil" );
809+ nilCheckedCont = IGF.createBasicBlock (" nil-checked-cont" );
810+
811+ auto isNotNil = IGF.Builder .CreateICmpNE (
812+ metadataValue, llvm::ConstantPointerNull::get (
813+ cast<llvm::PointerType>(IGF.IGM .Int8PtrTy )));
814+
815+ IGF.Builder .CreateCondBr (isNotNil, nonNilBB, nilBB);
816+ IGF.Builder .emitBlock (nilBB);
817+ IGF.Builder .CreateBr (nilCheckedCont);
818+ IGF.Builder .emitBlock (nonNilBB);
819+ }
820+
821+ llvm::Value *valueAndWitnessTables = IGF.Builder .CreateCall (fn, args);
822+
823+ if (nilCheckedCont) {
824+ IGF.Builder .CreateBr (nilCheckedCont);
825+ IGF.Builder .emitBlock (nilCheckedCont);
826+ auto *returnTy = valueAndWitnessTables->getType ();
827+ auto failureVal = llvm::Constant::getNullValue (returnTy);
828+ auto phi = IGF.Builder .CreatePHI (returnTy, 2 );
829+ phi->addIncoming (valueAndWitnessTables, nonNilBB);
830+ phi->addIncoming (failureVal, nilBB);
831+ valueAndWitnessTables = phi;
832+ }
804833
805834 resultValue = IGF.Builder .CreateExtractValue (valueAndWitnessTables, 0 );
806835 if (resultValue->getType () != resultType)
@@ -945,10 +974,9 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
945974
946975 // Casts to existential metatypes.
947976 if (auto existential = targetLoweredType.getAs <ExistentialMetatypeType>()) {
948- emitScalarExistentialDowncast (IGF, metatypeVal, sourceLoweredType,
949- targetLoweredType, mode,
950- existential->getRepresentation (),
951- out);
977+ emitScalarExistentialDowncast (
978+ IGF, metatypeVal, sourceLoweredType, targetLoweredType, mode,
979+ sourceWrappedInOptional, existential->getRepresentation (), out);
952980 return ;
953981
954982 // Casts to concrete metatypes.
@@ -1023,9 +1051,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
10231051
10241052 if (targetFormalType.isExistentialType ()) {
10251053 Explosion outRes;
1026- emitScalarExistentialDowncast (
1027- IGF, instance, sourceLoweredType, targetLoweredType, mode,
1028- /* not a metatype*/ std::nullopt , outRes);
1054+ emitScalarExistentialDowncast (IGF, instance, sourceLoweredType,
1055+ targetLoweredType, mode,
1056+ /* sourceWrappedInOptional*/ false ,
1057+ /* not a metatype*/ std::nullopt , outRes);
10291058 returnNilCheckedResult (IGF.Builder , outRes);
10301059 return ;
10311060 }
0 commit comments