@@ -544,8 +544,8 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
544
544
// / Emit a checked cast to a protocol or protocol composition.
545
545
void irgen::emitScalarExistentialDowncast (
546
546
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) {
549
549
auto srcInstanceType = srcType.getASTType ();
550
550
auto destInstanceType = destType.getASTType ();
551
551
while (auto metatypeType = dyn_cast<ExistentialMetatypeType>(
@@ -800,7 +800,36 @@ void irgen::emitScalarExistentialDowncast(
800
800
for (auto proto : witnessTableProtos)
801
801
args.push_back (proto);
802
802
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
+ }
804
833
805
834
resultValue = IGF.Builder .CreateExtractValue (valueAndWitnessTables, 0 );
806
835
if (resultValue->getType () != resultType)
@@ -945,10 +974,9 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
945
974
946
975
// Casts to existential metatypes.
947
976
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);
952
980
return ;
953
981
954
982
// Casts to concrete metatypes.
@@ -1023,9 +1051,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
1023
1051
1024
1052
if (targetFormalType.isExistentialType ()) {
1025
1053
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);
1029
1058
returnNilCheckedResult (IGF.Builder , outRes);
1030
1059
return ;
1031
1060
}
0 commit comments