mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Disallow conforming to ObjC protocols with requirements that can't be imported.
For example, variadic ObjC method requirements. <rdar://problem/17366999> Swift SVN r19121
This commit is contained in:
@@ -462,8 +462,12 @@ class alignas(8) Decl {
|
|||||||
|
|
||||||
/// The stage of the circularity check for this protocol.
|
/// The stage of the circularity check for this protocol.
|
||||||
unsigned Circularity : 2;
|
unsigned Circularity : 2;
|
||||||
|
|
||||||
|
/// True if the protocol has requirements that cannot be satisfied (e.g.
|
||||||
|
/// because they could not be imported from Objective-C).
|
||||||
|
unsigned HasMissingRequirements : 1;
|
||||||
};
|
};
|
||||||
enum { NumProtocolDeclBits = NumNominalTypeDeclBits + 11 };
|
enum { NumProtocolDeclBits = NumNominalTypeDeclBits + 12 };
|
||||||
static_assert(NumProtocolDeclBits <= 32, "fits in an unsigned");
|
static_assert(NumProtocolDeclBits <= 32, "fits in an unsigned");
|
||||||
|
|
||||||
class ClassDeclBitfields {
|
class ClassDeclBitfields {
|
||||||
@@ -3045,6 +3049,20 @@ public:
|
|||||||
ProtocolDeclBits.Circularity = static_cast<unsigned>(circularity);
|
ProtocolDeclBits.Circularity = static_cast<unsigned>(circularity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the protocol has requirements that are not listed in its
|
||||||
|
/// members.
|
||||||
|
///
|
||||||
|
/// This can occur, for example, if the protocol is an Objective-C protocol
|
||||||
|
/// with requirements that cannot be represented in Swift.
|
||||||
|
bool hasMissingRequirements() const {
|
||||||
|
(void)getMembers();
|
||||||
|
return ProtocolDeclBits.HasMissingRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHasMissingRequirements(bool newValue) {
|
||||||
|
ProtocolDeclBits.HasMissingRequirements = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the name to use for this protocol when interoperating
|
/// Retrieve the name to use for this protocol when interoperating
|
||||||
/// with the Objective-C runtime.
|
/// with the Objective-C runtime.
|
||||||
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
||||||
|
|||||||
@@ -456,6 +456,9 @@ ERROR(type_does_not_inherit,sema_tcd,none,
|
|||||||
ERROR(non_class_cannot_conform_to_class_protocol,sema_tcd,none,
|
ERROR(non_class_cannot_conform_to_class_protocol,sema_tcd,none,
|
||||||
"non-class type %0 cannot conform to class protocol %1",
|
"non-class type %0 cannot conform to class protocol %1",
|
||||||
(Type, Type))
|
(Type, Type))
|
||||||
|
ERROR(protocol_has_missing_requirements,sema_tcd,none,
|
||||||
|
"type %0 cannot conform to protocol %1 because it has requirements that "
|
||||||
|
"cannot be satisfied", (Type, Type))
|
||||||
ERROR(witness_argument_name_mismatch,sema_tcd,none,
|
ERROR(witness_argument_name_mismatch,sema_tcd,none,
|
||||||
"%select{method|initializer}0 %1 has different argument names from those "
|
"%select{method|initializer}0 %1 has different argument names from those "
|
||||||
"required by protocol %2 (%3)", (bool, DeclName, Type, DeclName))
|
"required by protocol %2 (%3)", (bool, DeclName, Type, DeclName))
|
||||||
|
|||||||
@@ -106,8 +106,12 @@ public:
|
|||||||
/// \p D.
|
/// \p D.
|
||||||
///
|
///
|
||||||
/// The implementation should \em not call setMembers on \p D.
|
/// The implementation should \em not call setMembers on \p D.
|
||||||
virtual ArrayRef<Decl *> loadAllMembers(const Decl *D,
|
///
|
||||||
uint64_t contextData) {
|
/// \param[out] hasMissingRequiredMembers If present, set to true if any
|
||||||
|
/// members failed to import and were non-optional protocol requirements.
|
||||||
|
virtual ArrayRef<Decl *>
|
||||||
|
loadAllMembers(const Decl *D, uint64_t contextData,
|
||||||
|
bool *hasMissingRequiredMembers = nullptr) {
|
||||||
llvm_unreachable("unimplemented");
|
llvm_unreachable("unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -524,7 +524,8 @@ public:
|
|||||||
GenericParamList *outerParams = nullptr);
|
GenericParamList *outerParams = nullptr);
|
||||||
|
|
||||||
virtual ArrayRef<Decl *> loadAllMembers(const Decl *D,
|
virtual ArrayRef<Decl *> loadAllMembers(const Decl *D,
|
||||||
uint64_t contextData) override;
|
uint64_t contextData,
|
||||||
|
bool *ignored) override;
|
||||||
|
|
||||||
virtual ArrayRef<ProtocolConformance *>
|
virtual ArrayRef<ProtocolConformance *>
|
||||||
loadAllConformances(const Decl *D, uint64_t contextData) override;
|
loadAllConformances(const Decl *D, uint64_t contextData) override;
|
||||||
|
|||||||
@@ -1770,6 +1770,7 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
|
|||||||
ProtocolDeclBits.KnownProtocol = 0;
|
ProtocolDeclBits.KnownProtocol = 0;
|
||||||
ProtocolDeclBits.Circularity
|
ProtocolDeclBits.Circularity
|
||||||
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
||||||
|
ProtocolDeclBits.HasMissingRequirements = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *Super) const {
|
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *Super) const {
|
||||||
|
|||||||
@@ -531,10 +531,16 @@ void IterableDeclContext::loadAllMembers() const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto member : resolver->loadAllMembers(container, contextData)) {
|
bool hasMissingRequiredMembers = false;
|
||||||
|
for (auto member : resolver->loadAllMembers(container, contextData,
|
||||||
|
&hasMissingRequiredMembers)) {
|
||||||
const_cast<IterableDeclContext *>(this)->addMember(member);
|
const_cast<IterableDeclContext *>(this)->addMember(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasMissingRequiredMembers)
|
||||||
|
if (auto proto = dyn_cast<ProtocolDecl>(this))
|
||||||
|
const_cast<ProtocolDecl *>(proto)->setHasMissingRequirements(true);
|
||||||
|
|
||||||
--NumUnloadedLazyIterableDeclContexts;
|
--NumUnloadedLazyIterableDeclContexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3464,7 +3464,8 @@ namespace {
|
|||||||
/// list of corresponding Swift members.
|
/// list of corresponding Swift members.
|
||||||
void importObjCMembers(const clang::ObjCContainerDecl *decl,
|
void importObjCMembers(const clang::ObjCContainerDecl *decl,
|
||||||
DeclContext *swiftContext,
|
DeclContext *swiftContext,
|
||||||
SmallVectorImpl<Decl *> &members) {
|
SmallVectorImpl<Decl *> &members,
|
||||||
|
bool &hasMissingRequiredMember) {
|
||||||
llvm::SmallPtrSet<Decl *, 4> knownMembers;
|
llvm::SmallPtrSet<Decl *, 4> knownMembers;
|
||||||
for (auto m = decl->decls_begin(), mEnd = decl->decls_end();
|
for (auto m = decl->decls_begin(), mEnd = decl->decls_end();
|
||||||
m != mEnd; ++m) {
|
m != mEnd; ++m) {
|
||||||
@@ -3473,8 +3474,18 @@ namespace {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto member = Impl.importDecl(nd);
|
auto member = Impl.importDecl(nd);
|
||||||
if (!member)
|
if (!member) {
|
||||||
|
if (auto method = dyn_cast<clang::ObjCMethodDecl>(nd)) {
|
||||||
|
if (method->getImplementationControl() ==
|
||||||
|
clang::ObjCMethodDecl::Required)
|
||||||
|
hasMissingRequiredMember = true;
|
||||||
|
} else if (auto prop = dyn_cast<clang::ObjCPropertyDecl>(nd)) {
|
||||||
|
if (prop->getPropertyImplementation() ==
|
||||||
|
clang::ObjCPropertyDecl::Required)
|
||||||
|
hasMissingRequiredMember = true;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If this member is a method that is a getter or setter for a property
|
// If this member is a method that is a getter or setter for a property
|
||||||
// that was imported, don't add it to the list of members so it won't
|
// that was imported, don't add it to the list of members so it won't
|
||||||
@@ -4903,7 +4914,8 @@ createUnavailableDecl(Identifier name, DeclContext *dc, Type type,
|
|||||||
|
|
||||||
|
|
||||||
ArrayRef<Decl *>
|
ArrayRef<Decl *>
|
||||||
ClangImporter::Implementation::loadAllMembers(const Decl *D, uint64_t unused) {
|
ClangImporter::Implementation::loadAllMembers(const Decl *D, uint64_t unused,
|
||||||
|
bool *hasMissingRequiredMembers) {
|
||||||
assert(D->hasClangNode());
|
assert(D->hasClangNode());
|
||||||
auto clangDecl = cast<clang::ObjCContainerDecl>(D->getClangDecl());
|
auto clangDecl = cast<clang::ObjCContainerDecl>(D->getClangDecl());
|
||||||
|
|
||||||
@@ -4921,8 +4933,13 @@ ClangImporter::Implementation::loadAllMembers(const Decl *D, uint64_t unused) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImportingEntityRAII Importing(*this);
|
ImportingEntityRAII Importing(*this);
|
||||||
|
|
||||||
|
bool scratch;
|
||||||
|
if (!hasMissingRequiredMembers)
|
||||||
|
hasMissingRequiredMembers = &scratch;
|
||||||
|
*hasMissingRequiredMembers = false;
|
||||||
converter.importObjCMembers(clangDecl, const_cast<DeclContext *>(DC),
|
converter.importObjCMembers(clangDecl, const_cast<DeclContext *>(DC),
|
||||||
members);
|
members, *hasMissingRequiredMembers);
|
||||||
|
|
||||||
if (auto clangClass = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
|
if (auto clangClass = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
|
||||||
auto swiftClass = cast<ClassDecl>(D);
|
auto swiftClass = cast<ClassDecl>(D);
|
||||||
|
|||||||
@@ -924,8 +924,9 @@ public:
|
|||||||
typeResolver = newResolver;
|
typeResolver = newResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ArrayRef<Decl *> loadAllMembers(const Decl *D,
|
virtual ArrayRef<Decl *>
|
||||||
uint64_t unused) override;
|
loadAllMembers(const Decl *D, uint64_t unused,
|
||||||
|
bool *hasMissingRequiredMembers) override;
|
||||||
|
|
||||||
template <typename DeclTy, typename ...Targs>
|
template <typename DeclTy, typename ...Targs>
|
||||||
DeclTy *createDeclWithClangNode(ClangNode ClangN, Targs &&... Args) {
|
DeclTy *createDeclWithClangNode(ClangNode ClangN, Targs &&... Args) {
|
||||||
|
|||||||
@@ -1832,6 +1832,15 @@ checkConformsToProtocol(TypeChecker &TC, Type T, ProtocolDecl *Proto,
|
|||||||
return conformance;
|
return conformance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the protocol contains missing requirements, it can't be conformed to
|
||||||
|
// at all.
|
||||||
|
if (Proto->hasMissingRequirements()) {
|
||||||
|
TC.diagnose(ComplainLoc, diag::protocol_has_missing_requirements,
|
||||||
|
T, Proto->getDeclaredType());
|
||||||
|
conformance->setState(ProtocolConformanceState::Invalid);
|
||||||
|
return conformance;
|
||||||
|
}
|
||||||
|
|
||||||
// Check that T conforms to all inherited protocols.
|
// Check that T conforms to all inherited protocols.
|
||||||
for (auto InheritedProto : Proto->getProtocols()) {
|
for (auto InheritedProto : Proto->getProtocols()) {
|
||||||
ProtocolConformance *InheritedConformance = nullptr;
|
ProtocolConformance *InheritedConformance = nullptr;
|
||||||
|
|||||||
@@ -3207,7 +3207,8 @@ Type ModuleFile::getType(TypeID TID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayRef<Decl *> ModuleFile::loadAllMembers(const Decl *D,
|
ArrayRef<Decl *> ModuleFile::loadAllMembers(const Decl *D,
|
||||||
uint64_t contextData) {
|
uint64_t contextData,
|
||||||
|
bool *) {
|
||||||
// FIXME: Add PrettyStackTrace.
|
// FIXME: Add PrettyStackTrace.
|
||||||
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
||||||
DeclTypeCursor.JumpToBit(contextData);
|
DeclTypeCursor.JumpToBit(contextData);
|
||||||
|
|||||||
@@ -73,3 +73,14 @@ extern NSNumber * const SomeNumber;
|
|||||||
|
|
||||||
|
|
||||||
__weak id globalWeakVar;
|
__weak id globalWeakVar;
|
||||||
|
|
||||||
|
@protocol Incomplete
|
||||||
|
- (id)getObject;
|
||||||
|
- (id)getObjectFromVarArgs:(id)first, ...;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol IncompleteOptional
|
||||||
|
@optional
|
||||||
|
- (id)getObject;
|
||||||
|
- (id)getObjectFromVarArgs:(id)first, ...;
|
||||||
|
@end
|
||||||
|
|||||||
@@ -426,3 +426,7 @@ func testWeakVariable() {
|
|||||||
let _: AnyObject = globalWeakVar
|
let _: AnyObject = globalWeakVar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IncompleteProtocolAdopter : Incomplete, IncompleteOptional { // expected-error {{type 'IncompleteProtocolAdopter' cannot conform to protocol 'Incomplete' because it has requirements that cannot be satisfied}}
|
||||||
|
func getObject() -> AnyObject { return self }
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user