Skip to content

Commit 719fb9c

Browse files
authored
Merge pull request #82848 from DougGregor/isolated-conformance-to-sendablemetatype-proto-error-6.2
[6.2] Diagnose isolated conformance to SendableMetatype-inheriting protocol
2 parents c0db6b6 + 6b4271c commit 719fb9c

File tree

6 files changed

+85
-23
lines changed

6 files changed

+85
-23
lines changed

include/swift/AST/Concurrency.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
namespace swift {
2121

22+
/// Find the imported module that treats the given nominal type as "preconcurrency", or return `nullptr`
23+
/// if there is no such module.
24+
ModuleDecl *moduleImportForPreconcurrency(NominalTypeDecl *nominal,
25+
const DeclContext *fromDC);
26+
2227
/// Determinate the appropriate diagnostic behavior to used when emitting
2328
/// concurrency diagnostics when referencing the given nominal type from the
2429
/// given declaration context.

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8591,6 +8591,9 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none,
85918591
GROUPED_WARNING(isolated_conformance_will_become_nonisolated,IsolatedConformances,none,
85928592
"conformance of %0 to %1 should be marked 'nonisolated' to retain its behavior with upcoming feature 'InferIsolatedConformances'",
85938593
(const ValueDecl *, const ValueDecl *))
8594+
GROUPED_ERROR(isolated_conformance_to_sendable_metatype,IsolatedConformances,none,
8595+
"cannot form %0 conformance of %1 to SendableMetatype-inheriting %kind2",
8596+
(ActorIsolation, Type, const ValueDecl *))
85948597
85958598
//===----------------------------------------------------------------------===//
85968599
// MARK: @_inheritActorContext

lib/AST/Concurrency.cpp

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,35 @@
1919

2020
using namespace swift;
2121

22-
std::optional<DiagnosticBehavior>
23-
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
24-
const DeclContext *fromDC,
25-
bool ignoreExplicitConformance) {
26-
ModuleDecl *importedModule = nullptr;
22+
ModuleDecl *swift::moduleImportForPreconcurrency(
23+
NominalTypeDecl *nominal, const DeclContext *fromDC) {
24+
// If the declaration itself has the @preconcurrency attribute,
25+
// respect it.
2726
if (nominal->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
28-
// If the declaration itself has the @preconcurrency attribute,
29-
// respect it.
30-
importedModule = nominal->getParentModule();
31-
} else {
32-
// Determine whether this nominal type is visible via a @preconcurrency
33-
// import.
34-
auto import = nominal->findImport(fromDC);
35-
auto sourceFile = fromDC->getParentSourceFile();
27+
return nominal->getParentModule();
28+
}
3629

37-
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
38-
return std::nullopt;
30+
// Determine whether this nominal type is visible via a @preconcurrency
31+
// import.
32+
auto import = nominal->findImport(fromDC);
33+
auto sourceFile = fromDC->getParentSourceFile();
3934

40-
if (sourceFile)
41-
sourceFile->setImportUsedPreconcurrency(*import);
35+
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
36+
return nullptr;
4237

43-
importedModule = import->module.importedModule;
44-
}
38+
if (sourceFile)
39+
sourceFile->setImportUsedPreconcurrency(*import);
40+
41+
return import->module.importedModule;
42+
}
43+
44+
std::optional<DiagnosticBehavior>
45+
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
46+
const DeclContext *fromDC,
47+
bool ignoreExplicitConformance) {
48+
ModuleDecl *importedModule = moduleImportForPreconcurrency(nominal, fromDC);
49+
if (!importedModule)
50+
return std::nullopt;
4551

4652
// When the type is explicitly non-Sendable, @preconcurrency imports
4753
// downgrade the diagnostic to a warning in Swift 6.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8281,6 +8281,10 @@ RawConformanceIsolationRequest::evaluate(
82818281
if (rootNormal->getOptions().contains(ProtocolConformanceFlags::Nonisolated))
82828282
return ActorIsolation::forNonisolated(false);
82838283

8284+
auto dc = conformance->getDeclContext();
8285+
ASTContext &ctx = dc->getASTContext();
8286+
auto proto = conformance->getProtocol();
8287+
82848288
// If there is an explicitly-specified global actor on the isolation,
82858289
// resolve it and report it.
82868290
if (auto globalActorTypeExpr = rootNormal->getExplicitGlobalActorIsolation()) {
@@ -8300,16 +8304,29 @@ RawConformanceIsolationRequest::evaluate(
83008304
globalActorTypeExpr->setType(MetatypeType::get(globalActorType));
83018305
}
83028306

8307+
// Cannot form an isolated conformance to a SendableMetatype-inheriting
8308+
// protocol. Diagnose it.
8309+
if (auto sendableMetatype =
8310+
ctx.getProtocol(KnownProtocolKind::SendableMetatype)) {
8311+
if (proto->inheritsFrom(sendableMetatype)) {
8312+
bool isPreconcurrency = moduleImportForPreconcurrency(
8313+
proto, conformance->getDeclContext()) != nullptr;
8314+
ctx.Diags.diagnose(
8315+
rootNormal->getLoc(),
8316+
diag::isolated_conformance_to_sendable_metatype,
8317+
ActorIsolation::forGlobalActor(globalActorType),
8318+
conformance->getType(),
8319+
proto)
8320+
.limitBehaviorIf(isPreconcurrency, DiagnosticBehavior::Warning);
8321+
}
8322+
}
8323+
83038324
// FIXME: Make sure the type actually is a global actor type, map it into
83048325
// context, etc.
83058326

83068327
return ActorIsolation::forGlobalActor(globalActorType);
83078328
}
83088329

8309-
auto dc = rootNormal->getDeclContext();
8310-
ASTContext &ctx = dc->getASTContext();
8311-
auto proto = rootNormal->getProtocol();
8312-
83138330
// If the protocol itself is isolated, don't infer isolation for the
83148331
// conformance.
83158332
if (getActorIsolation(proto).isActorIsolated())

test/Concurrency/isolated_conformance.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ struct PSendableS: @MainActor PSendable { // expected-note{{requirement specifie
147147
func f() { }
148148
}
149149

150+
protocol R: SendableMetatype {
151+
func f()
152+
}
153+
154+
// expected-error@+1{{cannot form main actor-isolated conformance of 'RSendableSMainActor' to SendableMetatype-inheriting protocol 'R'}}
155+
@MainActor struct RSendableSMainActor: @MainActor R {
156+
func f() { }
157+
}
158+
150159
// ----------------------------------------------------------------------------
151160
// Use checking of isolated conformances.
152161
// ----------------------------------------------------------------------------
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 %s
2+
3+
// REQUIRES: concurrency
4+
5+
protocol P: SendableMetatype {
6+
func f()
7+
}
8+
9+
@preconcurrency
10+
protocol Q: SendableMetatype {
11+
func f()
12+
}
13+
14+
// expected-error@+1{{cannot form main actor-isolated conformance of 'PSendableSMainActor' to SendableMetatype-inheriting protocol 'P'}}
15+
@MainActor struct PSendableSMainActor: @MainActor P {
16+
func f() { }
17+
}
18+
19+
// expected-warning@+1{{cannot form main actor-isolated conformance of 'QSendableSMainActor' to SendableMetatype-inheriting protocol 'Q'}}
20+
@MainActor struct QSendableSMainActor: @MainActor Q {
21+
func f() { }
22+
}

0 commit comments

Comments
 (0)