Don't classify bridging casts as WillSucceed if the object-to-value cast can fail.

When casting from an object type to a bridged Swift value type, classifyDynamicCast would use the cast classification for the target type's bridged object type, which would be trivially WillSucceed for thinks like NSNumber-to-Int or NSError-to-SomeError, even though the bridging itself could fail. Fixing this fixes SR-2920|rdar://problem/31404281.
This commit is contained in:
Joe Groff
2017-05-11 19:37:58 -07:00
parent e353163b58
commit 4e9851b032
9 changed files with 242 additions and 187 deletions

View File

@@ -425,6 +425,10 @@ public:
/// Retrieve the declaration of Foundation.NSError. /// Retrieve the declaration of Foundation.NSError.
ClassDecl *getNSErrorDecl() const; ClassDecl *getNSErrorDecl() const;
/// Retrieve the declaration of Foundation.NSNumber.
ClassDecl *getNSNumberDecl() const;
/// Retrieve the declaration of Foundation.NSValue.
ClassDecl *getNSValueDecl() const;
// Declare accessors for the known declarations. // Declare accessors for the known declarations.
#define FUNC_DECL(Name, Id) \ #define FUNC_DECL(Name, Id) \
@@ -487,6 +491,11 @@ public:
/// module's overlay, for layering or implementation detail reasons. /// module's overlay, for layering or implementation detail reasons.
bool isTypeBridgedInExternalModule(NominalTypeDecl *nominal) const; bool isTypeBridgedInExternalModule(NominalTypeDecl *nominal) const;
/// True if the given type is an Objective-C class that serves as the bridged
/// object type for many Swift value types, meaning that the conversion from
/// an object to a value is a conditional cast.
bool isObjCClassWithMultipleSwiftBridgedTypes(Type t);
/// Get the Objective-C type that a Swift type bridges to, if any. /// Get the Objective-C type that a Swift type bridges to, if any.
/// ///
/// \param dc The context in which bridging is occurring. /// \param dc The context in which bridging is occurring.

View File

@@ -83,6 +83,11 @@ using AssociativityCacheType =
llvm::DenseMap<std::pair<PrecedenceGroupDecl *, PrecedenceGroupDecl *>, llvm::DenseMap<std::pair<PrecedenceGroupDecl *, PrecedenceGroupDecl *>,
Associativity>; Associativity>;
#define FOR_KNOWN_FOUNDATION_TYPES(MACRO) \
MACRO(NSError) \
MACRO(NSNumber) \
MACRO(NSValue)
struct ASTContext::Implementation { struct ASTContext::Implementation {
Implementation(); Implementation();
~Implementation(); ~Implementation();
@@ -153,8 +158,11 @@ struct ASTContext::Implementation {
/// The declaration of ObjectiveC.ObjCBool. /// The declaration of ObjectiveC.ObjCBool.
StructDecl *ObjCBoolDecl = nullptr; StructDecl *ObjCBoolDecl = nullptr;
/// The declaration of Foundation.NSError. #define CACHE_FOUNDATION_DECL(NAME) \
ClassDecl *NSErrorDecl = nullptr; /** The declaration of Foundation.NAME. */ \
ClassDecl *NAME##Decl = nullptr;
FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
#undef CACHE_FOUNDATION_DECL
// Declare cached declarations for each of the known declarations. // Declare cached declarations for each of the known declarations.
#define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr; #define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr;
@@ -731,26 +739,31 @@ StructDecl *ASTContext::getObjCBoolDecl() const {
return Impl.ObjCBoolDecl; return Impl.ObjCBoolDecl;
} }
ClassDecl *ASTContext::getNSErrorDecl() const { #define GET_FOUNDATION_DECL(NAME) \
if (!Impl.NSErrorDecl) { ClassDecl *ASTContext::get##NAME##Decl() const { \
if (ModuleDecl *M = getLoadedModule(Id_Foundation)) { if (!Impl.NAME##Decl) { \
// Note: use unqualified lookup so we find NSError regardless of if (ModuleDecl *M = getLoadedModule(Id_Foundation)) { \
// whether it's defined in the Foundation module or the Clang /* Note: use unqualified lookup so we find NSError regardless of */ \
// Foundation module it imports. /* whether it's defined in the Foundation module or the Clang */ \
UnqualifiedLookup lookup(getIdentifier("NSError"), M, nullptr); /* Foundation module it imports. */ \
if (auto type = lookup.getSingleTypeResult()) { UnqualifiedLookup lookup(getIdentifier(#NAME), M, nullptr); \
if (auto classDecl = dyn_cast<ClassDecl>(type)) { if (auto type = lookup.getSingleTypeResult()) { \
if (classDecl->getGenericParams() == nullptr) { if (auto classDecl = dyn_cast<ClassDecl>(type)) { \
Impl.NSErrorDecl = classDecl; if (classDecl->getGenericParams() == nullptr) { \
} Impl.NAME##Decl = classDecl; \
} } \
} } \
} } \
} } \
} \
return Impl.NSErrorDecl; \
return Impl.NAME##Decl; \
} }
FOR_KNOWN_FOUNDATION_TYPES(GET_FOUNDATION_DECL)
#undef GET_FOUNDATION_DECL
#undef FOR_KNOWN_FOUNDATION_TYPES
ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const { ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
// Check whether we've already looked for and cached this protocol. // Check whether we've already looked for and cached this protocol.
unsigned index = (unsigned)kind; unsigned index = (unsigned)kind;
@@ -4044,6 +4057,21 @@ bool ASTContext::isTypeBridgedInExternalModule(
nominal->getParentModule()->getName() == Id_CoreMedia); nominal->getParentModule()->getName() == Id_CoreMedia);
} }
bool ASTContext::isObjCClassWithMultipleSwiftBridgedTypes(Type t) {
auto clas = t->getClassOrBoundGenericClass();
if (!clas)
return false;
if (clas == getNSErrorDecl())
return true;
if (clas == getNSNumberDecl())
return true;
if (clas == getNSValueDecl())
return true;
return false;
}
Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
Type *bridgedValueType) const { Type *bridgedValueType) const {
if (type->isBridgeableObjectType()) { if (type->isBridgeableObjectType()) {

View File

@@ -217,8 +217,8 @@ bool swift::isError(ModuleDecl *M, CanType Ty) {
M->getASTContext().getProtocol(KnownProtocolKind::Error); M->getASTContext().getProtocol(KnownProtocolKind::Error);
if (errorTypeProto) { if (errorTypeProto) {
// Find the conformance of the value type to _BridgedToObjectiveC. // Find the conformance of the value type to Error.
// Check whether the type conforms to _BridgedToObjectiveC. // Check whether the type conforms to Error.
auto conformance = M->lookupConformance(Ty, errorTypeProto, nullptr); auto conformance = M->lookupConformance(Ty, errorTypeProto, nullptr);
return conformance.hasValue(); return conformance.hasValue();
} }
@@ -636,9 +636,15 @@ swift::classifyDynamicCast(ModuleDecl *M,
if (Type ObjCTy = M->getASTContext().getBridgedToObjC(M, target)) { if (Type ObjCTy = M->getASTContext().getBridgedToObjC(M, target)) {
// If the bridged ObjC type is known, check if // If the bridged ObjC type is known, check if
// source type can be cast into it. // source type can be cast into it.
return classifyDynamicCast(M, source, auto canCastToBridgedType = classifyDynamicCast(M, source,
ObjCTy->getCanonicalType(), ObjCTy->getCanonicalType(),
/* isSourceTypeExact */ false, isWholeModuleOpts); /* isSourceTypeExact */ false, isWholeModuleOpts);
// Temper our enthusiasm if the bridge from the ObjC type to the target
// value type may fail.
if (canCastToBridgedType == DynamicCastFeasibility::WillSucceed
&& M->getASTContext().isObjCClassWithMultipleSwiftBridgedTypes(ObjCTy))
return DynamicCastFeasibility::MaySucceed;
return canCastToBridgedType;
} }
return DynamicCastFeasibility::MaySucceed; return DynamicCastFeasibility::MaySucceed;
} }

View File

@@ -1802,10 +1802,6 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) {
isSourceTypeExact, isSourceTypeExact,
Mod.isWholeModule()); Mod.isWholeModule());
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
if (Feasibility == DynamicCastFeasibility::WillFail) { if (Feasibility == DynamicCastFeasibility::WillFail) {
if (shouldDestroyOnFailure(Inst->getConsumptionKind())) { if (shouldDestroyOnFailure(Inst->getConsumptionKind())) {
auto &srcTL = Builder.getModule().getTypeLowering(Src->getType()); auto &srcTL = Builder.getModule().getTypeLowering(Src->getType());
@@ -1817,60 +1813,67 @@ simplifyCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *Inst) {
return NewI; return NewI;
} }
// Cast will succeed
// Replace by unconditional_addr_cast, followed by a branch.
// The unconditional_addr_cast can be skipped, if the result of a cast
// is not used afterwards.
bool ResultNotUsed = isa<AllocStackInst>(Dest); bool ResultNotUsed = isa<AllocStackInst>(Dest);
for (auto Use : Dest->getUses()) { if (ResultNotUsed) {
auto *User = Use->getUser(); for (auto Use : Dest->getUses()) {
if (isa<DeallocStackInst>(User) || User == Inst) auto *User = Use->getUser();
continue; if (isa<DeallocStackInst>(User) || User == Inst)
ResultNotUsed = false; continue;
break; ResultNotUsed = false;
break;
}
} }
auto *BB = Inst->getParent(); auto *BB = Inst->getParent();
if (!ResultNotUsed) { SILInstruction *BridgedI = nullptr;
SILInstruction *BridgedI = nullptr;
// To apply the bridged optimizations, we should // To apply the bridged optimizations, we should
// ensure that types are not existential, // ensure that types are not existential,
// and that not both types are classes. // and that not both types are classes.
BridgedI = optimizeBridgedCasts(Inst, Inst->getConsumptionKind(), BridgedI = optimizeBridgedCasts(Inst, Inst->getConsumptionKind(),
true, Src, Dest, SourceType, true, Src, Dest, SourceType,
TargetType, SuccessBB, FailureBB); TargetType, SuccessBB, FailureBB);
if (!BridgedI) { if (!BridgedI) {
// Since it is an addr cast, only address types are handled here. // If the cast may succeed or fail, and it can't be optimized into a
if (!Src->getType().isAddress() || !Dest->getType().isAddress()) { // bridging operation, then let it be.
return nullptr; if (Feasibility == DynamicCastFeasibility::MaySucceed) {
} else if (!emitSuccessfulIndirectUnconditionalCast( return nullptr;
Builder, Mod.getSwiftModule(), Loc, }
Inst->getConsumptionKind(), Src, SourceType, Dest,
TargetType, Inst)) { assert(Feasibility == DynamicCastFeasibility::WillSucceed);
// No optimization was possible.
return nullptr; // Replace by unconditional_addr_cast, followed by a branch.
} // The unconditional_addr_cast can be skipped, if the result of a cast
// is not used afterwards.
if (ResultNotUsed) {
EraseInstAction(Inst); EraseInstAction(Inst);
}
SILInstruction *NewI = &BB->back();
if (!isa<TermInst>(NewI)) {
Builder.setInsertionPoint(BB); Builder.setInsertionPoint(BB);
NewI = Builder.createBranch(Loc, SuccessBB); auto *NewI = Builder.createBranch(Loc, SuccessBB);
WillSucceedAction();
return NewI;
}
// Since it is an addr cast, only address types are handled here.
if (!Src->getType().isAddress() || !Dest->getType().isAddress()) {
return nullptr;
} else if (!emitSuccessfulIndirectUnconditionalCast(
Builder, Mod.getSwiftModule(), Loc,
Inst->getConsumptionKind(), Src, SourceType, Dest,
TargetType, Inst)) {
// No optimization was possible.
return nullptr;
} }
WillSucceedAction();
return NewI;
} else {
// Result is not used.
EraseInstAction(Inst); EraseInstAction(Inst);
Builder.setInsertionPoint(BB);
auto *NewI = Builder.createBranch(Loc, SuccessBB);
WillSucceedAction();
return NewI;
} }
SILInstruction *NewI = &BB->back();
if (!isa<TermInst>(NewI)) {
Builder.setInsertionPoint(BB);
NewI = Builder.createBranch(Loc, SuccessBB);
}
WillSucceedAction();
return NewI;
} }
SILInstruction * SILInstruction *
@@ -1926,10 +1929,6 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
TargetType, TargetType,
isSourceTypeExact); isSourceTypeExact);
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
SILBuilderWithScope Builder(Inst); SILBuilderWithScope Builder(Inst);
if (Feasibility == DynamicCastFeasibility::WillFail) { if (Feasibility == DynamicCastFeasibility::WillFail) {
@@ -1939,39 +1938,45 @@ CastOptimizer::simplifyCheckedCastBranchInst(CheckedCastBranchInst *Inst) {
return NewI; return NewI;
} }
// Casting will succeed.
// Replace by unconditional_cast, followed by a branch.
// The unconditional_cast can be skipped, if the result of a cast
// is not used afterwards.
bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty(); bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty();
SILValue CastedValue; SILValue CastedValue;
if (Op->getType() != LoweredTargetType) { if (Op->getType() != LoweredTargetType) {
if (!ResultNotUsed) { auto Src = Inst->getOperand();
auto Src = Inst->getOperand(); auto Dest = SILValue();
auto Dest = SILValue(); // Apply the bridged cast optimizations.
// To apply the bridged casts optimizations. auto BridgedI = optimizeBridgedCasts(Inst,
auto BridgedI = optimizeBridgedCasts(Inst, CastConsumptionKind::CopyOnSuccess, false, Src, Dest, SourceType,
CastConsumptionKind::CopyOnSuccess, false, Src, Dest, SourceType, TargetType, nullptr, nullptr);
TargetType, nullptr, nullptr);
if (BridgedI) { if (BridgedI) {
CastedValue = BridgedI; CastedValue = BridgedI;
} else { } else {
// If the cast may succeed or fail and can't be turned into a bridging
// call, then let it be.
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
// Replace by unconditional_cast, followed by a branch.
// The unconditional_cast can be skipped, if the result of a cast
// is not used afterwards.
if (!ResultNotUsed) {
if (!canUseScalarCheckedCastInstructions(Mod, SourceType, TargetType)) if (!canUseScalarCheckedCastInstructions(Mod, SourceType, TargetType))
return nullptr; return nullptr;
CastedValue = emitSuccessfulScalarUnconditionalCast( CastedValue = emitSuccessfulScalarUnconditionalCast(
Builder, Mod.getSwiftModule(), Loc, Op, LoweredTargetType, Builder, Mod.getSwiftModule(), Loc, Op, LoweredTargetType,
SourceType, TargetType, Inst); SourceType, TargetType, Inst);
} else {
CastedValue = SILUndef::get(LoweredTargetType, Mod);
} }
if (!CastedValue) if (!CastedValue)
CastedValue = CastedValue =
Builder.createUnconditionalCheckedCast(Loc, Op, LoweredTargetType); Builder.createUnconditionalCheckedCast(Loc, Op, LoweredTargetType);
} else {
CastedValue = SILUndef::get(LoweredTargetType, Mod);
} }
} else { } else {
// No need to cast. // No need to cast.
CastedValue = Op; CastedValue = Op;
@@ -2005,10 +2010,6 @@ SILInstruction *CastOptimizer::simplifyCheckedCastValueBranchInst(
auto Feasibility = classifyDynamicCast(Mod.getSwiftModule(), SourceType, auto Feasibility = classifyDynamicCast(Mod.getSwiftModule(), SourceType,
TargetType, isSourceTypeExact); TargetType, isSourceTypeExact);
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
SILBuilderWithScope Builder(Inst); SILBuilderWithScope Builder(Inst);
if (Feasibility == DynamicCastFeasibility::WillFail) { if (Feasibility == DynamicCastFeasibility::WillFail) {
@@ -2020,37 +2021,45 @@ SILInstruction *CastOptimizer::simplifyCheckedCastValueBranchInst(
// Casting will succeed. // Casting will succeed.
// Replace by unconditional_cast, followed by a branch.
// The unconditional_cast can be skipped, if the result of a cast
// is not used afterwards.
bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty(); bool ResultNotUsed = SuccessBB->getArgument(0)->use_empty();
SILValue CastedValue; SILValue CastedValue;
if (Op->getType() != LoweredTargetType) { if (Op->getType() != LoweredTargetType) {
if (!ResultNotUsed) { auto Src = Inst->getOperand();
auto Src = Inst->getOperand(); auto Dest = SILValue();
auto Dest = SILValue(); // Apply the bridged cast optimizations.
// To apply the bridged casts optimizations. auto BridgedI = optimizeBridgedCasts(
auto BridgedI = optimizeBridgedCasts( Inst, CastConsumptionKind::CopyOnSuccess, false, Src, Dest,
Inst, CastConsumptionKind::CopyOnSuccess, false, Src, Dest, SourceType, TargetType, nullptr, nullptr);
SourceType, TargetType, nullptr, nullptr);
if (BridgedI) { if (BridgedI) {
CastedValue = BridgedI; CastedValue = BridgedI;
} else { } else {
if (!canUseScalarCheckedCastInstructions(Mod, SourceType, TargetType)) // If the cast may succeed or fail and can't be turned into a bridging
return nullptr; // call, then let it be.
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
// Replace by unconditional_cast, followed by a branch.
// The unconditional_cast can be skipped, if the result of a cast
// is not used afterwards.
if (!canUseScalarCheckedCastInstructions(Mod, SourceType, TargetType))
return nullptr;
if (!ResultNotUsed) {
CastedValue = emitSuccessfulScalarUnconditionalCast( CastedValue = emitSuccessfulScalarUnconditionalCast(
Builder, Mod.getSwiftModule(), Loc, Op, LoweredTargetType, Builder, Mod.getSwiftModule(), Loc, Op, LoweredTargetType,
SourceType, TargetType, Inst); SourceType, TargetType, Inst);
} else {
CastedValue = SILUndef::get(LoweredTargetType, Mod);
} }
if (!CastedValue)
CastedValue = Builder.createUnconditionalCheckedCastValue(
Loc, CastConsumptionKind::TakeAlways, Op, LoweredTargetType);
} else {
CastedValue = SILUndef::get(LoweredTargetType, Mod);
} }
if (!CastedValue)
CastedValue = Builder.createUnconditionalCheckedCastValue(
Loc, CastConsumptionKind::TakeAlways, Op, LoweredTargetType);
} else { } else {
// No need to cast. // No need to cast.
CastedValue = Op; CastedValue = Op;
@@ -2326,10 +2335,6 @@ optimizeUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *Inst) {
Inst->getTargetType(), Inst->getTargetType(),
isSourceTypeExact); isSourceTypeExact);
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
if (Feasibility == DynamicCastFeasibility::WillFail) { if (Feasibility == DynamicCastFeasibility::WillFail) {
// Remove the cast and insert a trap, followed by an // Remove the cast and insert a trap, followed by an
// unreachable instruction. // unreachable instruction.
@@ -2356,44 +2361,52 @@ optimizeUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *Inst) {
WillSucceedAction(); WillSucceedAction();
return nullptr; return nullptr;
} }
}
SILBuilderWithScope Builder(Inst); SILBuilderWithScope Builder(Inst);
// Try to apply the bridged casts optimizations // Try to apply the bridged casts optimizations
auto SourceType = LoweredSourceType.getSwiftRValueType(); auto SourceType = LoweredSourceType.getSwiftRValueType();
auto TargetType = LoweredTargetType.getSwiftRValueType(); auto TargetType = LoweredTargetType.getSwiftRValueType();
auto Src = Inst->getOperand(); auto Src = Inst->getOperand();
auto NewI = optimizeBridgedCasts(Inst, CastConsumptionKind::CopyOnSuccess, auto NewI = optimizeBridgedCasts(Inst, CastConsumptionKind::CopyOnSuccess,
false, Src, SILValue(), SourceType, false, Src, SILValue(), SourceType,
TargetType, nullptr, nullptr); TargetType, nullptr, nullptr);
if (NewI) { if (NewI) {
ReplaceInstUsesAction(Inst, NewI); ReplaceInstUsesAction(Inst, NewI);
EraseInstAction(Inst);
WillSucceedAction();
return NewI;
}
if (isBridgingCast(SourceType, TargetType))
return nullptr;
auto Result = emitSuccessfulScalarUnconditionalCast(Builder,
Mod.getSwiftModule(), Loc, Op,
LoweredTargetType,
LoweredSourceType.getSwiftRValueType(),
LoweredTargetType.getSwiftRValueType(),
Inst);
if (!Result) {
// No optimization was possible.
return nullptr;
}
ReplaceInstUsesAction(Inst, Result);
EraseInstAction(Inst); EraseInstAction(Inst);
WillSucceedAction(); WillSucceedAction();
return Result; return NewI;
} }
// If the cast may succeed or fail and can't be optimized into a bridging
// call, let it be.
if (Feasibility == DynamicCastFeasibility::MaySucceed) {
return nullptr;
}
assert(Feasibility == DynamicCastFeasibility::WillSucceed);
if (isBridgingCast(SourceType, TargetType))
return nullptr;
auto Result = emitSuccessfulScalarUnconditionalCast(Builder,
Mod.getSwiftModule(), Loc, Op,
LoweredTargetType,
LoweredSourceType.getSwiftRValueType(),
LoweredTargetType.getSwiftRValueType(),
Inst);
if (!Result) {
// No optimization was possible.
return nullptr;
}
ReplaceInstUsesAction(Inst, Result);
EraseInstAction(Inst);
WillSucceedAction();
return Result;
return nullptr; return nullptr;
} }

View File

@@ -3559,7 +3559,7 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
// We accepted these coercions in Swift 3 mode, so we have to live with // We accepted these coercions in Swift 3 mode, so we have to live with
// them (but give a warning) in that language mode. // them (but give a warning) in that language mode.
if (!TC.Context.LangOpts.isSwiftVersion3() if (!TC.Context.LangOpts.isSwiftVersion3()
&& TC.isObjCClassWithMultipleSwiftBridgedTypes(objcClass, DC)) && TC.Context.isObjCClassWithMultipleSwiftBridgedTypes(objcClass))
return SolutionKind::Error; return SolutionKind::Error;
// If the bridged value type is generic, the generic arguments // If the bridged value type is generic, the generic arguments

View File

@@ -3466,7 +3466,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
if (Context.LangOpts.isSwiftVersion3() && extraFromOptionals == 0) { if (Context.LangOpts.isSwiftVersion3() && extraFromOptionals == 0) {
// Do the check for a bridging conversion now that we deferred above. // Do the check for a bridging conversion now that we deferred above.
if (isObjCBridgedTo(fromType, toType, dc, &unwrappedIUO) && !unwrappedIUO) { if (isObjCBridgedTo(fromType, toType, dc, &unwrappedIUO) && !unwrappedIUO) {
if (isObjCClassWithMultipleSwiftBridgedTypes(fromType, dc)) { if (Context.isObjCClassWithMultipleSwiftBridgedTypes(fromType)) {
return CheckedCastKind::Swift3BridgingDowncast; return CheckedCastKind::Swift3BridgingDowncast;
} }
return CheckedCastKind::BridgingCoercion; return CheckedCastKind::BridgingCoercion;

View File

@@ -171,33 +171,6 @@ Type TypeChecker::getNSErrorType(DeclContext *dc) {
dc); dc);
} }
Type TypeChecker::getNSNumberType(DeclContext *dc) {
return getObjectiveCNominalType(*this, NSNumberType, Context.Id_Foundation,
Context.getSwiftId(
KnownFoundationEntity::NSNumber),
dc);
}
Type TypeChecker::getNSValueType(DeclContext *dc) {
return getObjectiveCNominalType(*this, NSValueType, Context.Id_Foundation,
Context.getSwiftId(
KnownFoundationEntity::NSValue),
dc);
}
bool TypeChecker::isObjCClassWithMultipleSwiftBridgedTypes(Type t,
DeclContext *dc) {
if (auto nsNumber = getNSNumberType(dc)) {
if (t->isEqual(nsNumber))
return true;
}
if (auto nsValue = getNSValueType(dc)) {
if (t->isEqual(nsValue))
return true;
}
return false;
}
Type TypeChecker::getObjCSelectorType(DeclContext *dc) { Type TypeChecker::getObjCSelectorType(DeclContext *dc) {
return getObjectiveCNominalType(*this, ObjCSelectorType, return getObjectiveCNominalType(*this, ObjCSelectorType,
Context.Id_ObjectiveC, Context.Id_ObjectiveC,

View File

@@ -888,14 +888,9 @@ public:
Type getUInt8Type(DeclContext *dc); Type getUInt8Type(DeclContext *dc);
Type getNSObjectType(DeclContext *dc); Type getNSObjectType(DeclContext *dc);
Type getNSErrorType(DeclContext *dc); Type getNSErrorType(DeclContext *dc);
Type getNSNumberType(DeclContext *dc);
Type getNSValueType(DeclContext *dc);
Type getObjCSelectorType(DeclContext *dc); Type getObjCSelectorType(DeclContext *dc);
Type getExceptionType(DeclContext *dc, SourceLoc loc); Type getExceptionType(DeclContext *dc, SourceLoc loc);
/// True if `t` is an ObjC class that multiple Swift value types bridge into.
bool isObjCClassWithMultipleSwiftBridgedTypes(Type t, DeclContext *dc);
/// \brief Try to resolve an IdentTypeRepr, returning either the referenced /// \brief Try to resolve an IdentTypeRepr, returning either the referenced
/// Type or an ErrorType in case of error. /// Type or an ErrorType in case of error.
Type resolveIdentifierType(DeclContext *DC, Type resolveIdentifierType(DeclContext *DC,

View File

@@ -0,0 +1,31 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil %s | %FileCheck %s
// REQUIRES: objc_interop
sil_stage raw
import Swift
import Foundation
struct MyError: Error {}
// CHECK-LABEL: sil @cast_nserror_to_specific_error
sil @cast_nserror_to_specific_error : $@convention(thin) (@in NSError, @in NSNumber, @in NSValue) -> () {
entry(%0 : $*NSError, %1 : $*NSNumber, %2 : $*NSValue):
%f = function_ref @use : $@convention(thin) <T> (@in T) -> ()
%a = alloc_stack $MyError
// CHECK: checked_cast_addr_br {{.*}} NSError {{.*}} to MyError
checked_cast_addr_br take_always NSError in %0 : $*NSError to MyError in %a : $*MyError, yes, no
yes:
apply %f<MyError>(%a) : $@convention(thin) <T> (@in T) -> ()
br done
no:
br done
done:
dealloc_stack %a : $*MyError
return undef : $()
}
sil @use : $@convention(thin) <T> (@in T) -> ()