Skip to content

Commit ea8c273

Browse files
authored
Merge pull request #35764 from kavon/diagnostics-bermuda-triangle
Ensure that delayed diagnostics in protocol conformance checking are emitted.
2 parents 0d1e7ab + f60f500 commit ea8c273

File tree

5 files changed

+52
-11
lines changed

5 files changed

+52
-11
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,13 @@ class ASTContext final {
986986

987987
/// Check whether current context has any errors associated with
988988
/// ill-formed protocol conformances which haven't been produced yet.
989-
bool hasDelayedConformanceErrors() const;
989+
///
990+
/// @param conformance if non-null, will check only for errors specific to the
991+
/// provided conformance. Otherwise, checks for _any_ errors.
992+
///
993+
/// @returns true iff there are any delayed diagnostic errors
994+
bool hasDelayedConformanceErrors(
995+
NormalProtocolConformance const* conformance = nullptr) const;
990996

991997
/// Add a delayed diagnostic produced while type-checking a
992998
/// particular protocol conformance.
@@ -996,7 +1002,7 @@ class ASTContext final {
9961002
/// Retrieve the delayed-conformance diagnostic callbacks for the
9971003
/// given normal protocol conformance.
9981004
std::vector<DelayedConformanceDiag>
999-
takeDelayedConformanceDiags(NormalProtocolConformance *conformance);
1005+
takeDelayedConformanceDiags(NormalProtocolConformance const* conformance);
10001006

10011007
/// Add delayed missing witnesses for the given normal protocol conformance.
10021008
void addDelayedMissingWitnesses(

lib/AST/ASTContext.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,13 +2207,28 @@ LazyIterableDeclContextData *ASTContext::getOrCreateLazyIterableContextData(
22072207
lazyLoader);
22082208
}
22092209

2210-
bool ASTContext::hasDelayedConformanceErrors() const {
2211-
for (const auto &entry : getImpl().DelayedConformanceDiags) {
2212-
auto &diagnostics = entry.getSecond();
2213-
if (std::any_of(diagnostics.begin(), diagnostics.end(),
2214-
[](const ASTContext::DelayedConformanceDiag &diag) {
2210+
bool ASTContext::hasDelayedConformanceErrors(
2211+
NormalProtocolConformance const* conformance) const {
2212+
2213+
auto hasDelayedErrors = [](std::vector<DelayedConformanceDiag> const& diags) {
2214+
return std::any_of(diags.begin(), diags.end(),
2215+
[](ASTContext::DelayedConformanceDiag const& diag) {
22152216
return diag.IsError;
2216-
}))
2217+
});
2218+
};
2219+
2220+
if (conformance) {
2221+
auto entry = getImpl().DelayedConformanceDiags.find(conformance);
2222+
if (entry != getImpl().DelayedConformanceDiags.end())
2223+
return hasDelayedErrors(entry->second);
2224+
2225+
return false; // unknown conformance, so no delayed delayed diags either.
2226+
}
2227+
2228+
// check all conformances for any delayed errors
2229+
for (const auto &entry : getImpl().DelayedConformanceDiags) {
2230+
auto const& diagnostics = entry.getSecond();
2231+
if (hasDelayedErrors(diagnostics))
22172232
return true;
22182233
}
22192234

@@ -2247,9 +2262,9 @@ ASTContext::takeDelayedMissingWitnesses(
22472262
}
22482263

22492264
std::vector<ASTContext::DelayedConformanceDiag>
2250-
ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance *conformance){
2265+
ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance const* cnfrm){
22512266
std::vector<ASTContext::DelayedConformanceDiag> result;
2252-
auto known = getImpl().DelayedConformanceDiags.find(conformance);
2267+
auto known = getImpl().DelayedConformanceDiags.find(cnfrm);
22532268
if (known != getImpl().DelayedConformanceDiags.end()) {
22542269
result = std::move(known->second);
22552270
getImpl().DelayedConformanceDiags.erase(known);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,17 @@ class swift::MultiConformanceChecker {
15431543
public:
15441544
MultiConformanceChecker(ASTContext &ctx) : Context(ctx) {}
15451545

1546+
~MultiConformanceChecker() {
1547+
// force-flush diagnostics in checkers that have not already complained
1548+
for (auto &checker : AllUsedCheckers) {
1549+
if (checker.AlreadyComplained)
1550+
continue;
1551+
1552+
checker.SuppressDiagnostics = false; // no need to restore to prev value
1553+
checker.emitDelayedDiags();
1554+
}
1555+
}
1556+
15461557
ASTContext &getASTContext() const { return Context; }
15471558

15481559
/// Add a conformance into the batched checker.
@@ -2546,6 +2557,13 @@ ConformanceChecker::ConformanceChecker(
25462557
LocalMissingWitnessesStartIndex(GlobalMissingWitnesses.size()),
25472558
SuppressDiagnostics(suppressDiagnostics) {}
25482559

2560+
ConformanceChecker::~ConformanceChecker() {
2561+
// its not OK to forget about error diagnostics, unless if we have already
2562+
// complained or are suppose to suppress diagnostics.
2563+
assert(AlreadyComplained || SuppressDiagnostics ||
2564+
!getASTContext().hasDelayedConformanceErrors(Conformance));
2565+
}
2566+
25492567
ArrayRef<AssociatedTypeDecl *>
25502568
ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) {
25512569
// Check whether we've already cached this information.

lib/Sema/TypeCheckProtocol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ class ConformanceChecker : public WitnessChecker {
815815
llvm::SetVector<MissingWitness> &GlobalMissingWitnesses,
816816
bool suppressDiagnostics = true);
817817

818+
~ConformanceChecker();
819+
818820
/// Resolve all of the type witnesses.
819821
void resolveTypeWitnesses();
820822

test/ClangImporter/objc_async_conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension C2 {
2222
// a version of C2 that requires both sync and async methods (differing only by
2323
// completion handler) in ObjC, is not possible to conform to with 'async' in
2424
// a Swift protocol
25-
class C3 : NSObject, RequiredObserver {}
25+
class C3 : NSObject, RequiredObserver {} // expected-error {{type 'C3' does not conform to protocol 'RequiredObserver'}}
2626
extension C3 {
2727
func hello() -> Bool { true } // expected-note {{'hello()' previously declared here}}
2828
func hello() async -> Bool { true } // expected-error {{invalid redeclaration of 'hello()'}}

0 commit comments

Comments
 (0)