Skip to content

Commit deef5ff

Browse files
authored
Merge pull request #9537 from jckarter/classify-conditional-bridging-cast-4.0
[4.0] Don't classify bridging casts as WillSucceed if the object-to-value cast can fail.
2 parents b777b80 + 8bdbcc8 commit deef5ff

File tree

9 files changed

+242
-187
lines changed

9 files changed

+242
-187
lines changed

include/swift/AST/ASTContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ class ASTContext {
425425

426426
/// Retrieve the declaration of Foundation.NSError.
427427
ClassDecl *getNSErrorDecl() const;
428+
/// Retrieve the declaration of Foundation.NSNumber.
429+
ClassDecl *getNSNumberDecl() const;
430+
/// Retrieve the declaration of Foundation.NSValue.
431+
ClassDecl *getNSValueDecl() const;
428432

429433
// Declare accessors for the known declarations.
430434
#define FUNC_DECL(Name, Id) \
@@ -487,6 +491,11 @@ class ASTContext {
487491
/// module's overlay, for layering or implementation detail reasons.
488492
bool isTypeBridgedInExternalModule(NominalTypeDecl *nominal) const;
489493

494+
/// True if the given type is an Objective-C class that serves as the bridged
495+
/// object type for many Swift value types, meaning that the conversion from
496+
/// an object to a value is a conditional cast.
497+
bool isObjCClassWithMultipleSwiftBridgedTypes(Type t);
498+
490499
/// Get the Objective-C type that a Swift type bridges to, if any.
491500
///
492501
/// \param dc The context in which bridging is occurring.

lib/AST/ASTContext.cpp

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ using AssociativityCacheType =
8383
llvm::DenseMap<std::pair<PrecedenceGroupDecl *, PrecedenceGroupDecl *>,
8484
Associativity>;
8585

86+
#define FOR_KNOWN_FOUNDATION_TYPES(MACRO) \
87+
MACRO(NSError) \
88+
MACRO(NSNumber) \
89+
MACRO(NSValue)
90+
8691
struct ASTContext::Implementation {
8792
Implementation();
8893
~Implementation();
@@ -153,8 +158,11 @@ struct ASTContext::Implementation {
153158
/// The declaration of ObjectiveC.ObjCBool.
154159
StructDecl *ObjCBoolDecl = nullptr;
155160

156-
/// The declaration of Foundation.NSError.
157-
ClassDecl *NSErrorDecl = nullptr;
161+
#define CACHE_FOUNDATION_DECL(NAME) \
162+
/** The declaration of Foundation.NAME. */ \
163+
ClassDecl *NAME##Decl = nullptr;
164+
FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
165+
#undef CACHE_FOUNDATION_DECL
158166

159167
// Declare cached declarations for each of the known declarations.
160168
#define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr;
@@ -743,25 +751,30 @@ StructDecl *ASTContext::getObjCBoolDecl() const {
743751
return Impl.ObjCBoolDecl;
744752
}
745753

746-
ClassDecl *ASTContext::getNSErrorDecl() const {
747-
if (!Impl.NSErrorDecl) {
748-
if (ModuleDecl *M = getLoadedModule(Id_Foundation)) {
749-
// Note: use unqualified lookup so we find NSError regardless of
750-
// whether it's defined in the Foundation module or the Clang
751-
// Foundation module it imports.
752-
UnqualifiedLookup lookup(getIdentifier("NSError"), M, nullptr);
753-
if (auto type = lookup.getSingleTypeResult()) {
754-
if (auto classDecl = dyn_cast<ClassDecl>(type)) {
755-
if (classDecl->getGenericParams() == nullptr) {
756-
Impl.NSErrorDecl = classDecl;
757-
}
758-
}
759-
}
760-
}
761-
}
762-
763-
return Impl.NSErrorDecl;
764-
}
754+
#define GET_FOUNDATION_DECL(NAME) \
755+
ClassDecl *ASTContext::get##NAME##Decl() const { \
756+
if (!Impl.NAME##Decl) { \
757+
if (ModuleDecl *M = getLoadedModule(Id_Foundation)) { \
758+
/* Note: use unqualified lookup so we find NSError regardless of */ \
759+
/* whether it's defined in the Foundation module or the Clang */ \
760+
/* Foundation module it imports. */ \
761+
UnqualifiedLookup lookup(getIdentifier(#NAME), M, nullptr); \
762+
if (auto type = lookup.getSingleTypeResult()) { \
763+
if (auto classDecl = dyn_cast<ClassDecl>(type)) { \
764+
if (classDecl->getGenericParams() == nullptr) { \
765+
Impl.NAME##Decl = classDecl; \
766+
} \
767+
} \
768+
} \
769+
} \
770+
} \
771+
\
772+
return Impl.NAME##Decl; \
773+
}
774+
775+
FOR_KNOWN_FOUNDATION_TYPES(GET_FOUNDATION_DECL)
776+
#undef GET_FOUNDATION_DECL
777+
#undef FOR_KNOWN_FOUNDATION_TYPES
765778

766779
ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
767780
// Check whether we've already looked for and cached this protocol.
@@ -4056,6 +4069,21 @@ bool ASTContext::isTypeBridgedInExternalModule(
40564069
nominal->getParentModule()->getName() == Id_CoreMedia);
40574070
}
40584071

4072+
bool ASTContext::isObjCClassWithMultipleSwiftBridgedTypes(Type t) {
4073+
auto clas = t->getClassOrBoundGenericClass();
4074+
if (!clas)
4075+
return false;
4076+
4077+
if (clas == getNSErrorDecl())
4078+
return true;
4079+
if (clas == getNSNumberDecl())
4080+
return true;
4081+
if (clas == getNSValueDecl())
4082+
return true;
4083+
4084+
return false;
4085+
}
4086+
40594087
Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
40604088
Type *bridgedValueType) const {
40614089
if (type->isBridgeableObjectType()) {

lib/SIL/DynamicCasts.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ bool swift::isError(ModuleDecl *M, CanType Ty) {
217217
M->getASTContext().getProtocol(KnownProtocolKind::Error);
218218

219219
if (errorTypeProto) {
220-
// Find the conformance of the value type to _BridgedToObjectiveC.
221-
// Check whether the type conforms to _BridgedToObjectiveC.
220+
// Find the conformance of the value type to Error.
221+
// Check whether the type conforms to Error.
222222
auto conformance = M->lookupConformance(Ty, errorTypeProto, nullptr);
223223
return conformance.hasValue();
224224
}
@@ -636,9 +636,15 @@ swift::classifyDynamicCast(ModuleDecl *M,
636636
if (Type ObjCTy = M->getASTContext().getBridgedToObjC(M, target)) {
637637
// If the bridged ObjC type is known, check if
638638
// source type can be cast into it.
639-
return classifyDynamicCast(M, source,
639+
auto canCastToBridgedType = classifyDynamicCast(M, source,
640640
ObjCTy->getCanonicalType(),
641641
/* isSourceTypeExact */ false, isWholeModuleOpts);
642+
// Temper our enthusiasm if the bridge from the ObjC type to the target
643+
// value type may fail.
644+
if (canCastToBridgedType == DynamicCastFeasibility::WillSucceed
645+
&& M->getASTContext().isObjCClassWithMultipleSwiftBridgedTypes(ObjCTy))
646+
return DynamicCastFeasibility::MaySucceed;
647+
return canCastToBridgedType;
642648
}
643649
return DynamicCastFeasibility::MaySucceed;
644650
}

0 commit comments

Comments
 (0)