@@ -2010,6 +2010,9 @@ class MultiConformanceChecker {
20102010 // / Determine whether the given requirement was left unsatisfied.
20112011 bool isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req);
20122012
2013+ // / Diagnose redundant `@preconcurrency` attributes on conformances.
2014+ void diagnoseRedundantPreconcurrency ();
2015+
20132016public:
20142017 MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
20152018
@@ -2020,6 +2023,11 @@ class MultiConformanceChecker {
20202023 AllConformances.push_back (conformance);
20212024 }
20222025
2026+ // / Get the conformances associated with this checker.
2027+ ArrayRef<NormalProtocolConformance *> getConformances () const {
2028+ return AllConformances;
2029+ }
2030+
20232031 // / Peek the unsatisfied requirements collected during conformance checking.
20242032 ArrayRef<ValueDecl*> getUnsatisfiedRequirements () {
20252033 return llvm::ArrayRef (UnsatisfiedReqs);
@@ -2082,7 +2090,74 @@ static void diagnoseProtocolStubFixit(
20822090 NormalProtocolConformance *conformance,
20832091 ArrayRef<ASTContext::MissingWitness> missingWitnesses);
20842092
2093+ void MultiConformanceChecker::diagnoseRedundantPreconcurrency () {
2094+ // Collect explicit preconcurrency conformances for which preconcurrency is
2095+ // not directly effectful.
2096+ SmallVector<NormalProtocolConformance *, 2 > explicitConformances;
2097+ for (auto *conformance : AllConformances) {
2098+ if (conformance->getSourceKind () == ConformanceEntryKind::Explicit &&
2099+ conformance->isPreconcurrency () &&
2100+ !conformance->isPreconcurrencyEffectful ()) {
2101+ explicitConformances.push_back (conformance);
2102+ }
2103+ }
2104+
2105+ if (explicitConformances.empty ()) {
2106+ return ;
2107+ }
2108+
2109+ // If preconcurrency is effectful for an implied conformance (a conformance
2110+ // to an inherited protocol), consider it effectful for the explicit implying
2111+ // one.
2112+ for (auto *conformance : AllConformances) {
2113+ switch (conformance->getSourceKind ()) {
2114+ case ConformanceEntryKind::Inherited:
2115+ case ConformanceEntryKind::PreMacroExpansion:
2116+ llvm_unreachable (" Invalid normal protocol conformance kind" );
2117+ case ConformanceEntryKind::Explicit:
2118+ case ConformanceEntryKind::Synthesized:
2119+ continue ;
2120+ case ConformanceEntryKind::Implied:
2121+ if (!conformance->isPreconcurrency () ||
2122+ !conformance->isPreconcurrencyEffectful ()) {
2123+ continue ;
2124+ }
2125+
2126+ auto *proto = conformance->getProtocol ();
2127+ for (auto *explicitConformance : explicitConformances) {
2128+ if (explicitConformance->getProtocol ()->inheritsFrom (proto)) {
2129+ explicitConformance->setPreconcurrencyEffectful ();
2130+ }
2131+ }
2132+
2133+ continue ;
2134+ }
2135+ }
2136+
2137+ // Diagnose all explicit preconcurrency conformances for which preconcurrency
2138+ // is not effectful (redundant).
2139+ for (auto *conformance : explicitConformances) {
2140+ if (conformance->isPreconcurrencyEffectful ()) {
2141+ continue ;
2142+ }
2143+
2144+ auto diag = Context.Diags .diagnose (
2145+ conformance->getLoc (), diag::preconcurrency_conformance_not_used,
2146+ conformance->getProtocol ()->getDeclaredInterfaceType ());
2147+
2148+ SourceLoc preconcurrencyLoc = conformance->getPreconcurrencyLoc ();
2149+ if (preconcurrencyLoc.isValid ()) {
2150+ SourceLoc endLoc = preconcurrencyLoc.getAdvancedLoc (1 );
2151+ diag.fixItRemove (SourceRange (preconcurrencyLoc, endLoc));
2152+ }
2153+ }
2154+ }
2155+
20852156void MultiConformanceChecker::checkAllConformances () {
2157+ if (AllConformances.empty ()) {
2158+ return ;
2159+ }
2160+
20862161 llvm::SmallVector<ASTContext::MissingWitness, 2 > MissingWitnesses;
20872162
20882163 bool anyInvalid = false ;
@@ -2147,6 +2222,9 @@ void MultiConformanceChecker::checkAllConformances() {
21472222 }
21482223 }
21492224
2225+ // Diagnose any redundant preconcurrency.
2226+ this ->diagnoseRedundantPreconcurrency ();
2227+
21502228 // Emit diagnostics at the very end.
21512229 for (auto *conformance : AllConformances) {
21522230 emitDelayedDiags (conformance);
@@ -5341,16 +5419,8 @@ void ConformanceChecker::resolveValueWitnesses() {
53415419 }
53425420 }
53435421
5344- if (Conformance->isPreconcurrency () && !usesPreconcurrency) {
5345- auto diag = DC->getASTContext ().Diags .diagnose (
5346- Conformance->getLoc (), diag::preconcurrency_conformance_not_used,
5347- Proto->getDeclaredInterfaceType ());
5348-
5349- SourceLoc preconcurrencyLoc = Conformance->getPreconcurrencyLoc ();
5350- if (preconcurrencyLoc.isValid ()) {
5351- SourceLoc endLoc = preconcurrencyLoc.getAdvancedLoc (1 );
5352- diag.fixItRemove (SourceRange (preconcurrencyLoc, endLoc));
5353- }
5422+ if (Conformance->isPreconcurrency () && usesPreconcurrency) {
5423+ Conformance->setPreconcurrencyEffectful ();
53545424 }
53555425
53565426 // Finally, check some ad-hoc protocol requirements.
@@ -6245,7 +6315,6 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
62456315 ProtocolConformance *SendableConformance = nullptr ;
62466316 bool hasDeprecatedUnsafeSendable = false ;
62476317 bool sendableConformancePreconcurrency = false ;
6248- bool anyInvalid = false ;
62496318 for (auto conformance : conformances) {
62506319 // Check and record normal conformances.
62516320 if (auto normal = dyn_cast<NormalProtocolConformance>(conformance)) {
@@ -6379,12 +6448,6 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
63796448 }
63806449 }
63816450
6382- // Catalog all of members of this declaration context that satisfy
6383- // requirements of conformances in this context.
6384- SmallVector<ValueDecl *, 16 >
6385- unsatisfiedReqs (groupChecker.getUnsatisfiedRequirements ().begin (),
6386- groupChecker.getUnsatisfiedRequirements ().end ());
6387-
63886451 // Diagnose any conflicts attributed to this declaration context.
63896452 for (const auto &diag : idc->takeConformanceDiagnostics ()) {
63906453 // Figure out the declaration of the existing conformance.
@@ -6516,9 +6579,19 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
65166579 diag.ExistingExplicitProtocol ->getName ());
65176580 }
65186581
6582+ if (groupChecker.getConformances ().empty ()) {
6583+ return ;
6584+ }
6585+
6586+ // Catalog all of members of this declaration context that satisfy
6587+ // requirements of conformances in this context.
6588+ SmallVector<ValueDecl *, 16 > unsatisfiedReqs (
6589+ groupChecker.getUnsatisfiedRequirements ().begin (),
6590+ groupChecker.getUnsatisfiedRequirements ().end ());
6591+
65196592 // If there were any unsatisfied requirements, check whether there
65206593 // are any near-matches we should diagnose.
6521- if (!unsatisfiedReqs.empty () && !anyInvalid ) {
6594+ if (!unsatisfiedReqs.empty ()) {
65226595 if (sf->Kind != SourceFileKind::Interface) {
65236596 // Find all of the members that aren't used to satisfy
65246597 // requirements, and check whether they are close to an
0 commit comments