@@ -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,40 @@ 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
+ ex.add (phi);
832
+ valueAndWitnessTables = ex.claimNext ();
833
+ ex.reset ();
834
+ }
835
+
836
+ assert (ex.empty ());
804
837
805
838
resultValue = IGF.Builder .CreateExtractValue (valueAndWitnessTables, 0 );
806
839
if (resultValue->getType () != resultType)
@@ -945,10 +978,9 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
945
978
946
979
// Casts to existential metatypes.
947
980
if (auto existential = targetLoweredType.getAs <ExistentialMetatypeType>()) {
948
- emitScalarExistentialDowncast (IGF, metatypeVal, sourceLoweredType,
949
- targetLoweredType, mode,
950
- existential->getRepresentation (),
951
- out);
981
+ emitScalarExistentialDowncast (
982
+ IGF, metatypeVal, sourceLoweredType, targetLoweredType, mode,
983
+ sourceWrappedInOptional, existential->getRepresentation (), out);
952
984
return ;
953
985
954
986
// Casts to concrete metatypes.
@@ -1023,9 +1055,10 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
1023
1055
1024
1056
if (targetFormalType.isExistentialType ()) {
1025
1057
Explosion outRes;
1026
- emitScalarExistentialDowncast (
1027
- IGF, instance, sourceLoweredType, targetLoweredType, mode,
1028
- /* not a metatype*/ std::nullopt, outRes);
1058
+ emitScalarExistentialDowncast (IGF, instance, sourceLoweredType,
1059
+ targetLoweredType, mode,
1060
+ /* sourceWrappedInOptional*/ false ,
1061
+ /* not a metatype*/ std::nullopt, outRes);
1029
1062
returnNilCheckedResult (IGF.Builder , outRes);
1030
1063
return ;
1031
1064
}
0 commit comments