diff --git a/include/swift/AST/Concurrency.h b/include/swift/AST/Concurrency.h index 3d19fa40bbe80..c5e0de233c4b4 100644 --- a/include/swift/AST/Concurrency.h +++ b/include/swift/AST/Concurrency.h @@ -19,6 +19,11 @@ namespace swift { +/// Find the imported module that treats the given nominal type as "preconcurrency", or return `nullptr` +/// if there is no such module. +ModuleDecl *moduleImportForPreconcurrency(NominalTypeDecl *nominal, + const DeclContext *fromDC); + /// Determinate the appropriate diagnostic behavior to used when emitting /// concurrency diagnostics when referencing the given nominal type from the /// given declaration context. diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 537f65b69a202..9a5ef27378953 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8681,9 +8681,9 @@ GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, GROUPED_WARNING(isolated_conformance_will_become_nonisolated,IsolatedConformances,none, "conformance of %0 to %1 should be marked 'nonisolated' to retain its behavior with upcoming feature 'InferIsolatedConformances'", (const ValueDecl *, const ValueDecl *)) -GROUPED_WARNING(isolated_conformance_to_sendable_metatype,IsolatedConformances,none, - "%0 conformance of %1 to SendableMetatype-inheriting %kind2 can never " - "be used with generic code", (ActorIsolation, Type, const ValueDecl *)) +GROUPED_ERROR(isolated_conformance_to_sendable_metatype,IsolatedConformances,none, + "cannot form %0 conformance of %1 to SendableMetatype-inheriting %kind2", + (ActorIsolation, Type, const ValueDecl *)) //===----------------------------------------------------------------------===// // MARK: @_inheritActorContext diff --git a/lib/AST/Concurrency.cpp b/lib/AST/Concurrency.cpp index 958ac706c692e..c2929dcf2c0dc 100644 --- a/lib/AST/Concurrency.cpp +++ b/lib/AST/Concurrency.cpp @@ -19,29 +19,35 @@ using namespace swift; -std::optional -swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal, - const DeclContext *fromDC, - bool ignoreExplicitConformance) { - ModuleDecl *importedModule = nullptr; +ModuleDecl *swift::moduleImportForPreconcurrency( + NominalTypeDecl *nominal, const DeclContext *fromDC) { + // If the declaration itself has the @preconcurrency attribute, + // respect it. if (nominal->getAttrs().hasAttribute()) { - // If the declaration itself has the @preconcurrency attribute, - // respect it. - importedModule = nominal->getParentModule(); - } else { - // Determine whether this nominal type is visible via a @preconcurrency - // import. - auto import = nominal->findImport(fromDC); - auto sourceFile = fromDC->getParentSourceFile(); + return nominal->getParentModule(); + } - if (!import || !import->options.contains(ImportFlags::Preconcurrency)) - return std::nullopt; + // Determine whether this nominal type is visible via a @preconcurrency + // import. + auto import = nominal->findImport(fromDC); + auto sourceFile = fromDC->getParentSourceFile(); - if (sourceFile) - sourceFile->setImportUsedPreconcurrency(*import); + if (!import || !import->options.contains(ImportFlags::Preconcurrency)) + return nullptr; - importedModule = import->module.importedModule; - } + if (sourceFile) + sourceFile->setImportUsedPreconcurrency(*import); + + return import->module.importedModule; +} + +std::optional +swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal, + const DeclContext *fromDC, + bool ignoreExplicitConformance) { + ModuleDecl *importedModule = moduleImportForPreconcurrency(nominal, fromDC); + if (!importedModule) + return std::nullopt; // When the type is explicitly non-Sendable, @preconcurrency imports // downgrade the diagnostic to a warning in Swift 6. diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index af6f0f4d9d7ba..beb691c5830cb 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -8303,18 +8303,20 @@ RawConformanceIsolationRequest::evaluate( globalActorTypeExpr->setType(MetatypeType::get(globalActorType)); } - // Isolated conformance to a SendableMetatype-inheriting protocol can - // never be used generically. Warn about it. + // Cannot form an isolated conformance to a SendableMetatype-inheriting + // protocol. Diagnose it. if (auto sendableMetatype = ctx.getProtocol(KnownProtocolKind::SendableMetatype)) { - if (proto->inheritsFrom(sendableMetatype) && - !getActorIsolation(proto).preconcurrency()) { + if (proto->inheritsFrom(sendableMetatype)) { + bool isPreconcurrency = moduleImportForPreconcurrency( + proto, conformance->getDeclContext()) != nullptr; ctx.Diags.diagnose( conformance->getLoc(), diag::isolated_conformance_to_sendable_metatype, ActorIsolation::forGlobalActor(globalActorType), conformance->getType(), - proto); + proto) + .limitBehaviorIf(isPreconcurrency, DiagnosticBehavior::Warning); } } diff --git a/test/Concurrency/isolated_conformance.swift b/test/Concurrency/isolated_conformance.swift index 3b1ef6430f70a..8f71f601b24be 100644 --- a/test/Concurrency/isolated_conformance.swift +++ b/test/Concurrency/isolated_conformance.swift @@ -151,7 +151,7 @@ protocol R: SendableMetatype { func f() } -// expected-warning@+1{{main actor-isolated conformance of 'RSendableSMainActor' to SendableMetatype-inheriting protocol 'R' can never be used with generic code}} +// expected-error@+1{{cannot form main actor-isolated conformance of 'RSendableSMainActor' to SendableMetatype-inheriting protocol 'R'}} @MainActor struct RSendableSMainActor: @MainActor R { func f() { } } diff --git a/test/Concurrency/isolated_conformance_6.swift b/test/Concurrency/isolated_conformance_6.swift new file mode 100644 index 0000000000000..c77dad3f1520b --- /dev/null +++ b/test/Concurrency/isolated_conformance_6.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 %s + +// REQUIRES: concurrency + +protocol P: SendableMetatype { + func f() +} + +@preconcurrency +protocol Q: SendableMetatype { + func f() +} + +// expected-error@+1{{cannot form main actor-isolated conformance of 'PSendableSMainActor' to SendableMetatype-inheriting protocol 'P'}} +@MainActor struct PSendableSMainActor: @MainActor P { + func f() { } +} + +// expected-warning@+1{{cannot form main actor-isolated conformance of 'QSendableSMainActor' to SendableMetatype-inheriting protocol 'Q'}} +@MainActor struct QSendableSMainActor: @MainActor Q { + func f() { } +}