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