@@ -2010,6 +2010,9 @@ class MultiConformanceChecker {
2010
2010
// / Determine whether the given requirement was left unsatisfied.
2011
2011
bool isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req);
2012
2012
2013
+ // / Diagnose redundant `@preconcurrency` attributes on conformances.
2014
+ void diagnoseRedundantPreconcurrency ();
2015
+
2013
2016
public:
2014
2017
MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
2015
2018
@@ -2020,6 +2023,11 @@ class MultiConformanceChecker {
2020
2023
AllConformances.push_back (conformance);
2021
2024
}
2022
2025
2026
+ // / Get the conformances associated with this checker.
2027
+ ArrayRef<NormalProtocolConformance *> getConformances () const {
2028
+ return AllConformances;
2029
+ }
2030
+
2023
2031
// / Peek the unsatisfied requirements collected during conformance checking.
2024
2032
ArrayRef<ValueDecl*> getUnsatisfiedRequirements () {
2025
2033
return llvm::ArrayRef (UnsatisfiedReqs);
@@ -2082,7 +2090,74 @@ static void diagnoseProtocolStubFixit(
2082
2090
NormalProtocolConformance *conformance,
2083
2091
ArrayRef<ASTContext::MissingWitness> missingWitnesses);
2084
2092
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
+
2085
2156
void MultiConformanceChecker::checkAllConformances () {
2157
+ if (AllConformances.empty ()) {
2158
+ return ;
2159
+ }
2160
+
2086
2161
llvm::SmallVector<ASTContext::MissingWitness, 2 > MissingWitnesses;
2087
2162
2088
2163
bool anyInvalid = false ;
@@ -2147,6 +2222,9 @@ void MultiConformanceChecker::checkAllConformances() {
2147
2222
}
2148
2223
}
2149
2224
2225
+ // Diagnose any redundant preconcurrency.
2226
+ this ->diagnoseRedundantPreconcurrency ();
2227
+
2150
2228
// Emit diagnostics at the very end.
2151
2229
for (auto *conformance : AllConformances) {
2152
2230
emitDelayedDiags (conformance);
@@ -5341,16 +5419,8 @@ void ConformanceChecker::resolveValueWitnesses() {
5341
5419
}
5342
5420
}
5343
5421
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 ();
5354
5424
}
5355
5425
5356
5426
// Finally, check some ad-hoc protocol requirements.
@@ -6245,7 +6315,6 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
6245
6315
ProtocolConformance *SendableConformance = nullptr ;
6246
6316
bool hasDeprecatedUnsafeSendable = false ;
6247
6317
bool sendableConformancePreconcurrency = false ;
6248
- bool anyInvalid = false ;
6249
6318
for (auto conformance : conformances) {
6250
6319
// Check and record normal conformances.
6251
6320
if (auto normal = dyn_cast<NormalProtocolConformance>(conformance)) {
@@ -6379,12 +6448,6 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
6379
6448
}
6380
6449
}
6381
6450
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
-
6388
6451
// Diagnose any conflicts attributed to this declaration context.
6389
6452
for (const auto &diag : idc->takeConformanceDiagnostics ()) {
6390
6453
// Figure out the declaration of the existing conformance.
@@ -6516,9 +6579,19 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
6516
6579
diag.ExistingExplicitProtocol ->getName ());
6517
6580
}
6518
6581
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
+
6519
6592
// If there were any unsatisfied requirements, check whether there
6520
6593
// are any near-matches we should diagnose.
6521
- if (!unsatisfiedReqs.empty () && !anyInvalid ) {
6594
+ if (!unsatisfiedReqs.empty ()) {
6522
6595
if (sf->Kind != SourceFileKind::Interface) {
6523
6596
// Find all of the members that aren't used to satisfy
6524
6597
// requirements, and check whether they are close to an
0 commit comments