Skip to content

Commit 0e0e4ef

Browse files
authored
Merge pull request #28401 from slavapestov/fix-cast-to-self
Fix casts involving the 'Self' type
2 parents 45df041 + c8da158 commit 0e0e4ef

File tree

8 files changed

+281
-54
lines changed

8 files changed

+281
-54
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ getDynamicCastArguments(IRGenFunction &IGF,
164164

165165
/// Emit a checked unconditional downcast of a class value.
166166
llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
167-
SILType toType, CheckedCastMode mode) {
167+
CanType toType, CheckedCastMode mode) {
168168
// Emit the value we're casting from.
169169
if (from->getType() != IGF.IGM.Int8PtrTy)
170170
from = IGF.Builder.CreateBitOrPointerCast(from, IGF.IGM.Int8PtrTy);
@@ -174,11 +174,19 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
174174
llvm::Value *metadataRef;
175175
llvm::Constant *castFn;
176176

177+
// If true, the target class is not known at compile time because it is a
178+
// class-bounded archetype or the dynamic Self type.
179+
bool nonSpecificClass = false;
180+
177181
// Get the best known type information about the destination type.
178182
ClassDecl *destClass = nullptr;
179-
if (auto archetypeTy = toType.getAs<ArchetypeType>()) {
183+
if (auto archetypeTy = dyn_cast<ArchetypeType>(toType)) {
184+
nonSpecificClass = true;
180185
if (auto superclassTy = archetypeTy->getSuperclass())
181186
destClass = superclassTy->getClassOrBoundGenericClass();
187+
} else if (auto selfTy = dyn_cast<DynamicSelfType>(toType)) {
188+
nonSpecificClass = true;
189+
destClass = selfTy->getSelfType()->getClassOrBoundGenericClass();
182190
} else {
183191
destClass = toType.getClassOrBoundGenericClass();
184192
assert(destClass != nullptr);
@@ -187,7 +195,7 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
187195
// If the destination type is known to have a Swift-compatible
188196
// implementation, use the most specific entrypoint.
189197
if (destClass && destClass->hasKnownSwiftImplementation()) {
190-
metadataRef = IGF.emitTypeMetadataRef(toType.getASTType());
198+
metadataRef = IGF.emitTypeMetadataRef(toType);
191199

192200
switch (mode) {
193201
case CheckedCastMode::Unconditional:
@@ -200,9 +208,9 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
200208

201209
// If the destination type is a CF type or a non-specific
202210
// class-bounded archetype, use the most general cast entrypoint.
203-
} else if (toType.is<ArchetypeType>() ||
211+
} else if (nonSpecificClass ||
204212
destClass->getForeignClassKind()==ClassDecl::ForeignKind::CFType) {
205-
metadataRef = IGF.emitTypeMetadataRef(toType.getASTType());
213+
metadataRef = IGF.emitTypeMetadataRef(toType);
206214

207215
switch (mode) {
208216
case CheckedCastMode::Unconditional:
@@ -249,7 +257,7 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
249257
call->setCallingConv(cc);
250258
call->setDoesNotThrow();
251259

252-
llvm::Type *subTy = IGF.getTypeInfo(toType).getStorageType();
260+
llvm::Type *subTy = IGF.getTypeInfoForUnlowered(toType).getStorageType();
253261
return IGF.Builder.CreateBitCast(call, subTy);
254262
}
255263

@@ -871,12 +879,14 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
871879
/// isn't exposed.
872880
void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
873881
Explosion &value,
874-
SILType sourceType,
875-
SILType targetType,
882+
SILType sourceLoweredType,
883+
CanType sourceFormalType,
884+
SILType targetLoweredType,
885+
CanType targetFormalType,
876886
CheckedCastMode mode,
877887
Explosion &out) {
878-
assert(sourceType.isObject());
879-
assert(targetType.isObject());
888+
assert(sourceLoweredType.isObject());
889+
assert(targetLoweredType.isObject());
880890

881891
llvm::BasicBlock *nilCheckBB = nullptr;
882892
llvm::BasicBlock *nilMergeBB = nullptr;
@@ -906,22 +916,23 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
906916
}
907917
};
908918

909-
if (auto sourceOptObjectType = sourceType.getOptionalObjectType()) {
919+
if (auto sourceOptObjectType = sourceLoweredType.getOptionalObjectType()) {
910920
// Translate the value from an enum representation to a possibly-null
911921
// representation. Note that we assume that this projection is safe
912922
// for the particular case of an optional class-reference or metatype
913923
// value.
914924
Explosion optValue;
915925
auto someDecl = IGF.IGM.Context.getOptionalSomeDecl();
916-
emitProjectLoadableEnum(IGF, sourceType, value, someDecl, optValue);
926+
emitProjectLoadableEnum(IGF, sourceLoweredType, value, someDecl, optValue);
917927

918928
assert(value.empty());
919929
value = std::move(optValue);
920-
sourceType = sourceOptObjectType;
930+
sourceLoweredType = sourceOptObjectType;
931+
sourceFormalType = sourceFormalType.getOptionalObjectType();
921932

922933
// We need a null-check because the runtime function can't handle null in
923934
// some of the cases.
924-
if (targetType.isExistentialType()) {
935+
if (targetLoweredType.isExistentialType()) {
925936
auto &Builder = IGF.Builder;
926937
auto val = value.getAll()[0];
927938
auto isNotNil = Builder.CreateICmpNE(
@@ -938,7 +949,7 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
938949

939950
// If the source value is a metatype, either do a metatype-to-metatype
940951
// cast or cast it to an object instance and continue.
941-
if (auto sourceMetatype = sourceType.getAs<AnyMetatypeType>()) {
952+
if (auto sourceMetatype = sourceLoweredType.getAs<AnyMetatypeType>()) {
942953
llvm::Value *metatypeVal = nullptr;
943954
if (sourceMetatype->getRepresentation() != MetatypeRepresentation::Thin)
944955
metatypeVal = value.claimNext();
@@ -952,60 +963,61 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
952963
SmallVector<ProtocolDecl*, 1> protocols;
953964

954965
// Casts to existential metatypes.
955-
if (auto existential = targetType.getAs<ExistentialMetatypeType>()) {
956-
emitScalarExistentialDowncast(IGF, metatypeVal, sourceType, targetType,
957-
mode, existential->getRepresentation(),
966+
if (auto existential = targetLoweredType.getAs<ExistentialMetatypeType>()) {
967+
emitScalarExistentialDowncast(IGF, metatypeVal, sourceLoweredType,
968+
targetLoweredType, mode,
969+
existential->getRepresentation(),
958970
out);
959971
return;
960972

961973
// Casts to concrete metatypes.
962-
} else if (auto destMetaType = targetType.getAs<MetatypeType>()) {
974+
} else if (auto destMetaType = targetLoweredType.getAs<MetatypeType>()) {
963975
emitMetatypeDowncast(IGF, metatypeVal, destMetaType, mode, out);
964976
return;
965977
}
966978

967979
// Otherwise, this is a metatype-to-object cast.
968-
assert(targetType.isAnyClassReferenceType());
980+
assert(targetLoweredType.isAnyClassReferenceType());
969981

970982
// Convert the metatype value to AnyObject.
971983
llvm::Value *object =
972984
emitMetatypeToAnyObjectDowncast(IGF, metatypeVal, sourceMetatype, mode);
973985

974-
SILType anyObjectType =
975-
SILType::getPrimitiveObjectType(
976-
IGF.IGM.Context.getAnyObjectType());
986+
sourceFormalType = IGF.IGM.Context.getAnyObjectType();
987+
sourceLoweredType = SILType::getPrimitiveObjectType(sourceFormalType);
977988

978989
// Continue, pretending that the source value was an (optional) value.
979990
Explosion newValue;
980991
newValue.add(object);
981992
value = std::move(newValue);
982-
sourceType = anyObjectType;
983993
}
984994

985-
assert(!targetType.is<AnyMetatypeType>() &&
995+
assert(!targetLoweredType.is<AnyMetatypeType>() &&
986996
"scalar cast of class reference to metatype is unimplemented");
987997

988998
// If the source type is existential, project out the class pointer.
989999
//
9901000
// TODO: if we're casting to an existential type, don't throw away the
9911001
// protocol conformance information we already have.
9921002
llvm::Value *instance;
993-
if (sourceType.isExistentialType()) {
994-
instance = emitClassExistentialProjection(IGF, value, sourceType,
1003+
if (sourceLoweredType.isExistentialType()) {
1004+
instance = emitClassExistentialProjection(IGF, value, sourceLoweredType,
9951005
CanArchetypeType());
9961006
} else {
9971007
instance = value.claimNext();
9981008
}
9991009

1000-
if (targetType.isExistentialType()) {
1010+
if (targetFormalType.isExistentialType()) {
10011011
Explosion outRes;
1002-
emitScalarExistentialDowncast(IGF, instance, sourceType, targetType,
1003-
mode, /*not a metatype*/ None, outRes);
1012+
emitScalarExistentialDowncast(IGF, instance, sourceLoweredType,
1013+
targetLoweredType, mode,
1014+
/*not a metatype*/ None, outRes);
10041015
returnNilCheckedResult(IGF.Builder, outRes);
10051016
return;
10061017
}
10071018

10081019
Explosion outRes;
1009-
llvm::Value *result = emitClassDowncast(IGF, instance, targetType, mode);
1020+
llvm::Value *result = emitClassDowncast(IGF, instance, targetFormalType,
1021+
mode);
10101022
out.add(result);
10111023
}

lib/IRGen/GenCast.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,17 @@ namespace irgen {
4848
CheckedCastMode mode);
4949

5050
void emitScalarCheckedCast(IRGenFunction &IGF, Explosion &value,
51-
SILType valueType, SILType loweredTargetType,
51+
SILType sourceLoweredType,
52+
CanType sourceFormalType,
53+
SILType targetLoweredType,
54+
CanType targetFormalType,
5255
CheckedCastMode mode, Explosion &out);
5356

5457
/// Convert a class object to the given destination type,
5558
/// using a runtime-checked cast.
56-
///
57-
/// FIXME: toType should be an AST CanType.
5859
llvm::Value *emitClassDowncast(IRGenFunction &IGF,
5960
llvm::Value *from,
60-
SILType toType,
61+
CanType toType,
6162
CheckedCastMode mode);
6263

6364
/// A result of a cast generation function.

lib/IRGen/IRGenSIL.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4834,7 +4834,11 @@ void IRGenSILFunction::visitUnconditionalCheckedCastInst(
48344834
swift::UnconditionalCheckedCastInst *i) {
48354835
Explosion value = getLoweredExplosion(i->getOperand());
48364836
Explosion ex;
4837-
emitScalarCheckedCast(*this, value, i->getOperand()->getType(), i->getType(),
4837+
emitScalarCheckedCast(*this, value,
4838+
i->getSourceLoweredType(),
4839+
i->getSourceFormalType(),
4840+
i->getTargetLoweredType(),
4841+
i->getTargetFormalType(),
48384842
CheckedCastMode::Unconditional, ex);
48394843
setLoweredExplosion(i, ex);
48404844
}
@@ -5038,20 +5042,21 @@ void IRGenSILFunction::visitCheckedCastValueBranchInst(
50385042

50395043
void IRGenSILFunction::visitCheckedCastBranchInst(
50405044
swift::CheckedCastBranchInst *i) {
5041-
SILType destTy = i->getTargetLoweredType();
50425045
FailableCastResult castResult;
50435046
Explosion ex;
50445047
if (i->isExact()) {
50455048
auto operand = i->getOperand();
50465049
Explosion source = getLoweredExplosion(operand);
50475050
castResult = emitClassIdenticalCast(*this, source.claimNext(),
50485051
i->getSourceLoweredType(),
5049-
destTy);
5052+
i->getTargetLoweredType());
50505053
} else {
50515054
Explosion value = getLoweredExplosion(i->getOperand());
50525055
emitScalarCheckedCast(*this, value,
50535056
i->getSourceLoweredType(),
5057+
i->getSourceFormalType(),
50545058
i->getTargetLoweredType(),
5059+
i->getTargetFormalType(),
50555060
CheckedCastMode::Conditional, ex);
50565061
auto val = ex.claimNext();
50575062
castResult.casted = val;
@@ -5065,7 +5070,7 @@ void IRGenSILFunction::visitCheckedCastBranchInst(
50655070

50665071

50675072
auto &successBB = getLoweredBB(i->getSuccessBB());
5068-
llvm::Type *toTy = IGM.getTypeInfo(destTy).getStorageType();
5073+
llvm::Type *toTy = IGM.getTypeInfo(i->getTargetLoweredType()).getStorageType();
50695074
if (toTy->isPointerTy())
50705075
castResult.casted = Builder.CreateBitCast(castResult.casted, toTy);
50715076

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -400,22 +400,18 @@ void DCE::propagateLiveness(SILInstruction *I) {
400400
case TermKind::SwitchEnumInst:
401401
case TermKind::SwitchEnumAddrInst:
402402
case TermKind::DynamicMethodBranchInst:
403-
case TermKind::CheckedCastBranchInst:
404-
case TermKind::CheckedCastValueBranchInst:
405403
markValueLive(I->getOperand(0));
406404
return;
407405

406+
case TermKind::CheckedCastBranchInst:
407+
case TermKind::CheckedCastValueBranchInst:
408+
case TermKind::CheckedCastAddrBranchInst:
408409
case TermKind::TryApplyInst:
409410
case TermKind::SwitchValueInst:
410411
case TermKind::YieldInst:
411412
for (auto &O : I->getAllOperands())
412413
markValueLive(O.get());
413414
return;
414-
415-
case TermKind::CheckedCastAddrBranchInst:
416-
markValueLive(I->getOperand(0));
417-
markValueLive(I->getOperand(1));
418-
return;
419415
}
420416
llvm_unreachable("corrupt instruction!");
421417
}

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,9 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
997997
// Check if we can statically predict the outcome of the cast.
998998
auto Feasibility =
999999
dynamicCast.classifyFeasibility(false /*allow whole module*/);
1000+
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
1001+
return nullptr;
1002+
}
10001003

10011004
SILBuilderWithScope Builder(Inst, builderContext);
10021005
if (Feasibility == DynamicCastFeasibility::WillFail) {
@@ -1009,6 +1012,8 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
10091012
return NewI;
10101013
}
10111014

1015+
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
1016+
10121017
bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty();
10131018
SILValue CastedValue;
10141019
if (Op->getType() != TargetLoweredType) {
@@ -1022,14 +1027,6 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
10221027
llvm_unreachable(
10231028
"Bridged casts cannot be expressed by checked_cast_br yet");
10241029
} else {
1025-
// If the cast may succeed or fail and can't be turned into a bridging
1026-
// call, then let it be.
1027-
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
1028-
return nullptr;
1029-
}
1030-
1031-
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
1032-
10331030
// Replace by unconditional_cast, followed by a branch.
10341031
// The unconditional_cast can be skipped, if the result of a cast
10351032
// is not used afterwards.

0 commit comments

Comments
 (0)