Skip to content

Commit bbc4816

Browse files
committed
[sema] Move getConcurrencyDiagnosticBehaviorLimit and hasExplicitSendableConformance out of Sema and into libAST.
I am going to expose this on TypeBase, so I am attempting to prevent a layering violation in between AST and Sema.
1 parent f075e4e commit bbc4816

File tree

7 files changed

+134
-81
lines changed

7 files changed

+134
-81
lines changed

include/swift/AST/Concurrency.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===--- Concurrency.h ----------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_AST_CONCURRENCY_H
14+
#define SWIFT_AST_CONCURRENCY_H
15+
16+
#include "swift/AST/DiagnosticEngine.h"
17+
18+
#include <optional>
19+
20+
namespace swift {
21+
22+
/// Determinate the appropriate diagnostic behavior to used when emitting
23+
/// concurrency diagnostics when referencing the given nominal type from the
24+
/// given declaration context.
25+
std::optional<DiagnosticBehavior>
26+
getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
27+
const DeclContext *fromDC,
28+
bool ignoreExplicitConformance = false);
29+
30+
/// Determine whether the given nominal type has an explicit Sendable
31+
/// conformance (regardless of its availability).
32+
bool hasExplicitSendableConformance(NominalTypeDecl *nominal,
33+
bool applyModuleDefault = true);
34+
35+
} // namespace swift
36+
37+
#endif

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/ASTAllocated.h"
2222
#include "swift/AST/AutoDiff.h"
2323
#include "swift/AST/DeclContext.h"
24+
#include "swift/AST/DiagnosticEngine.h"
2425
#include "swift/AST/ExtInfo.h"
2526
#include "swift/AST/GenericParamKey.h"
2627
#include "swift/AST/Identifier.h"
@@ -937,6 +938,11 @@ class alignas(1 << TypeAlignInBits) TypeBase
937938
/// that is @Sendable.
938939
bool isSendableType();
939940

941+
/// Returns the diagnostic behavior for a specific nominal type handling
942+
/// whether or not the type has preconcurrency applied to it.
943+
std::optional<DiagnosticBehavior>
944+
getConcurrencyDiagnosticBehaviorLimit(DeclContext *ctx) const;
945+
940946
/// Determines whether this type conforms or inherits (if it's a protocol
941947
/// type) from `DistributedActor`.
942948
bool isDistributedActor();

include/swift/Sema/Concurrency.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,13 @@ struct DiagnosticBehavior;
3636
/// that the attribute be removed.
3737
void diagnoseUnnecessaryPreconcurrencyImports(SourceFile &sf);
3838

39-
/// Determine whether the given nominal type has an explicit Sendable
40-
/// conformance (regardless of its availability).
41-
bool hasExplicitSendableConformance(NominalTypeDecl *nominal,
42-
bool applyModuleDefault = true);
43-
4439
/// Diagnose the use of an instance property of non-sendable type from an
4540
/// nonisolated deinitializer within an actor-isolated type.
4641
///
4742
/// \returns true iff a diagnostic was emitted for this reference.
4843
bool diagnoseNonSendableFromDeinit(
4944
SourceLoc refLoc, VarDecl *var, DeclContext *dc);
5045

51-
/// Determinate the appropriate diagnostic behavior when referencing
52-
/// the given nominal type from the given declaration context.
53-
std::optional<DiagnosticBehavior>
54-
getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
55-
const DeclContext *fromDC,
56-
bool ignoreExplicitConformance = false);
57-
5846
} // namespace swift
5947

6048
#endif

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ add_swift_host_library(swiftAST STATIC
3232
CaptureInfo.cpp
3333
ClangSwiftTypeCorrespondence.cpp
3434
ClangTypeConverter.cpp
35+
Concurrency.cpp
3536
ConcreteDeclRef.cpp
3637
ConformanceLookup.cpp
3738
ConformanceLookupTable.cpp

lib/AST/Concurrency.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//===--- Concurrency.cpp --------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/AST/Concurrency.h"
14+
#include "swift/AST/ASTContext.h"
15+
#include "swift/AST/ConformanceLookup.h"
16+
#include "swift/AST/Decl.h"
17+
#include "swift/AST/ProtocolConformance.h"
18+
#include "swift/AST/SourceFile.h"
19+
20+
using namespace swift;
21+
22+
std::optional<DiagnosticBehavior>
23+
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
24+
const DeclContext *fromDC,
25+
bool ignoreExplicitConformance) {
26+
ModuleDecl *importedModule = nullptr;
27+
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();
36+
37+
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
38+
return std::nullopt;
39+
40+
if (sourceFile)
41+
sourceFile->setImportUsedPreconcurrency(*import);
42+
43+
importedModule = import->module.importedModule;
44+
}
45+
46+
// When the type is explicitly non-Sendable, @preconcurrency imports
47+
// downgrade the diagnostic to a warning in Swift 6.
48+
if (!ignoreExplicitConformance && hasExplicitSendableConformance(nominal))
49+
return DiagnosticBehavior::Warning;
50+
51+
// When the type is implicitly non-Sendable, `@preconcurrency` suppresses
52+
// diagnostics until the imported module enables Swift 6.
53+
return importedModule->isConcurrencyChecked() ? DiagnosticBehavior::Warning
54+
: DiagnosticBehavior::Ignore;
55+
}
56+
57+
/// Determine whether the given nominal type has an explicit Sendable
58+
/// conformance (regardless of its availability).
59+
bool swift::hasExplicitSendableConformance(NominalTypeDecl *nominal,
60+
bool applyModuleDefault) {
61+
ASTContext &ctx = nominal->getASTContext();
62+
auto nominalModule = nominal->getParentModule();
63+
64+
// In a concurrency-checked module, a missing conformance is equivalent to
65+
// an explicitly unavailable one. If we want to apply this rule, do so now.
66+
if (applyModuleDefault && nominalModule->isConcurrencyChecked())
67+
return true;
68+
69+
// Look for any conformance to `Sendable`.
70+
auto proto = ctx.getProtocol(KnownProtocolKind::Sendable);
71+
if (!proto)
72+
return false;
73+
74+
// Look for a conformance. If it's present and not (directly) missing,
75+
// we're done.
76+
auto conformance = lookupConformance(nominal->getDeclaredInterfaceType(),
77+
proto, /*allowMissing=*/true);
78+
return conformance &&
79+
!(isa<BuiltinProtocolConformance>(conformance.getConcrete()) &&
80+
cast<BuiltinProtocolConformance>(conformance.getConcrete())
81+
->isMissing());
82+
}

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define DEBUG_TYPE "transfer-non-sendable"
1414

1515
#include "swift/AST/ASTWalker.h"
16+
#include "swift/AST/Concurrency.h"
1617
#include "swift/AST/DiagnosticsSIL.h"
1718
#include "swift/AST/Expr.h"
1819
#include "swift/AST/ProtocolConformance.h"

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 7 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,28 @@
1313
// This file implements type checking support for Swift's concurrency model.
1414
//
1515
//===----------------------------------------------------------------------===//
16-
#include "MiscDiagnostics.h"
16+
1717
#include "TypeCheckConcurrency.h"
18+
#include "MiscDiagnostics.h"
1819
#include "TypeCheckDistributed.h"
1920
#include "TypeCheckInvertible.h"
20-
#include "TypeChecker.h"
2121
#include "TypeCheckType.h"
22-
#include "swift/Strings.h"
22+
#include "TypeChecker.h"
2323
#include "swift/AST/ASTWalker.h"
24+
#include "swift/AST/Concurrency.h"
2425
#include "swift/AST/ConformanceLookup.h"
2526
#include "swift/AST/DistributedDecl.h"
27+
#include "swift/AST/ExistentialLayout.h"
2628
#include "swift/AST/GenericEnvironment.h"
2729
#include "swift/AST/ImportCache.h"
2830
#include "swift/AST/Initializer.h"
31+
#include "swift/AST/NameLookupRequests.h"
2932
#include "swift/AST/ParameterList.h"
3033
#include "swift/AST/ProtocolConformance.h"
31-
#include "swift/AST/NameLookupRequests.h"
3234
#include "swift/AST/TypeCheckRequests.h"
33-
#include "swift/AST/ExistentialLayout.h"
3435
#include "swift/Basic/Assertions.h"
3536
#include "swift/Sema/IDETypeChecking.h"
37+
#include "swift/Strings.h"
3638

3739
using namespace swift;
3840

@@ -840,33 +842,6 @@ SendableCheckContext::implicitSendableDiagnosticBehavior() const {
840842
}
841843
}
842844

843-
/// Determine whether the given nominal type has an explicit Sendable
844-
/// conformance (regardless of its availability).
845-
bool swift::hasExplicitSendableConformance(NominalTypeDecl *nominal,
846-
bool applyModuleDefault) {
847-
ASTContext &ctx = nominal->getASTContext();
848-
auto nominalModule = nominal->getParentModule();
849-
850-
// In a concurrency-checked module, a missing conformance is equivalent to
851-
// an explicitly unavailable one. If we want to apply this rule, do so now.
852-
if (applyModuleDefault && nominalModule->isConcurrencyChecked())
853-
return true;
854-
855-
// Look for any conformance to `Sendable`.
856-
auto proto = ctx.getProtocol(KnownProtocolKind::Sendable);
857-
if (!proto)
858-
return false;
859-
860-
// Look for a conformance. If it's present and not (directly) missing,
861-
// we're done.
862-
auto conformance = lookupConformance(
863-
nominal->getDeclaredInterfaceType(), proto, /*allowMissing=*/true);
864-
return conformance &&
865-
!(isa<BuiltinProtocolConformance>(conformance.getConcrete()) &&
866-
cast<BuiltinProtocolConformance>(
867-
conformance.getConcrete())->isMissing());
868-
}
869-
870845
/// Determine the diagnostic behavior for a Sendable reference to the given
871846
/// nominal type.
872847
DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
@@ -887,43 +862,6 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
887862
return defaultBehavior;
888863
}
889864

890-
std::optional<DiagnosticBehavior>
891-
swift::getConcurrencyDiagnosticBehaviorLimit(NominalTypeDecl *nominal,
892-
const DeclContext *fromDC,
893-
bool ignoreExplicitConformance) {
894-
ModuleDecl *importedModule = nullptr;
895-
if (nominal->getAttrs().hasAttribute<PreconcurrencyAttr>()) {
896-
// If the declaration itself has the @preconcurrency attribute,
897-
// respect it.
898-
importedModule = nominal->getParentModule();
899-
} else {
900-
// Determine whether this nominal type is visible via a @preconcurrency
901-
// import.
902-
auto import = nominal->findImport(fromDC);
903-
auto sourceFile = fromDC->getParentSourceFile();
904-
905-
if (!import || !import->options.contains(ImportFlags::Preconcurrency))
906-
return std::nullopt;
907-
908-
if (sourceFile)
909-
sourceFile->setImportUsedPreconcurrency(*import);
910-
911-
importedModule = import->module.importedModule;
912-
}
913-
914-
// When the type is explicitly non-Sendable, @preconcurrency imports
915-
// downgrade the diagnostic to a warning in Swift 6.
916-
if (!ignoreExplicitConformance &&
917-
hasExplicitSendableConformance(nominal))
918-
return DiagnosticBehavior::Warning;
919-
920-
// When the type is implicitly non-Sendable, `@preconcurrency` suppresses
921-
// diagnostics until the imported module enables Swift 6.
922-
return importedModule->isConcurrencyChecked()
923-
? DiagnosticBehavior::Warning
924-
: DiagnosticBehavior::Ignore;
925-
}
926-
927865
std::optional<DiagnosticBehavior>
928866
SendableCheckContext::preconcurrencyBehavior(
929867
Decl *decl,

0 commit comments

Comments
 (0)