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