Skip to content

Commit da597be

Browse files
authored
Merge pull request #76075 from gottesmm/rdar133531625
[region-isolation] Treat as Sendable values that are meant to be ignored since they are marked with preconcurrency
2 parents 6b6e9aa + 49eee05 commit da597be

16 files changed

+413
-211
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/DiagnosticEngine.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -428,14 +428,29 @@ namespace swift {
428428

429429
/// Describes the current behavior to take with a diagnostic.
430430
/// Ordered from most severe to least.
431-
enum class DiagnosticBehavior : uint8_t {
432-
Unspecified = 0,
433-
Fatal,
434-
Error,
435-
Warning,
436-
Remark,
437-
Note,
438-
Ignore,
431+
struct DiagnosticBehavior {
432+
enum Kind : uint8_t {
433+
Unspecified = 0,
434+
Fatal,
435+
Error,
436+
Warning,
437+
Remark,
438+
Note,
439+
Ignore,
440+
};
441+
442+
Kind kind;
443+
444+
DiagnosticBehavior() : kind(Unspecified) {}
445+
DiagnosticBehavior(Kind kind) : kind(kind) {}
446+
operator Kind() const { return kind; }
447+
448+
/// Move up the lattice returning the max value.
449+
DiagnosticBehavior merge(DiagnosticBehavior other) const {
450+
auto value = std::max(std::underlying_type<Kind>::type(*this),
451+
std::underlying_type<Kind>::type(other));
452+
return Kind(value);
453+
}
439454
};
440455

441456
struct DiagnosticFormatOptions {

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/Basic/LangOptions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@
4545

4646
namespace swift {
4747

48-
enum class DiagnosticBehavior : uint8_t;
48+
struct DiagnosticBehavior;
4949

5050
/// Kind of implicit platform conditions.
5151
enum class PlatformConditionKind {
52-
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) LABEL,
53-
#include "swift/AST/PlatformConditionKinds.def"
52+
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) LABEL,
53+
#include "swift/AST/PlatformConditionKinds.def"
5454
};
5555

5656
/// Describes how strict concurrency checking should be.

include/swift/SIL/SILType.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,11 @@ class SILType {
964964
bool isAnyActor() const { return getASTType()->isAnyActorType(); }
965965

966966
/// Returns true if this function conforms to the Sendable protocol.
967+
///
968+
/// NOTE: For diagnostics this is not always the correct thing to check since
969+
/// non-Sendable types afflicted with preconcurrency can have different
970+
/// semantic requirements around diagnostics. \see
971+
/// getConcurrencyDiagnosticBehavior.
967972
bool isSendable(SILFunction *fn) const;
968973

969974
/// False if SILValues of this type cannot be used outside the scope of their
@@ -978,6 +983,16 @@ class SILType {
978983
return !isNoEscapeFunction() && isEscapable(function);
979984
}
980985

986+
/// Return the expected concurrency diagnostic behavior for this SILType.
987+
///
988+
/// This allows one to know if the type is marked with preconcurrency and thus
989+
/// should have diagnostics ignored or converted to warnings instead of
990+
/// errors.
991+
///
992+
/// \returns nil if we were unable to find such information for this type.
993+
std::optional<DiagnosticBehavior>
994+
getConcurrencyDiagnosticBehavior(SILFunction *fn) const;
995+
981996
//
982997
// Accessors for types used in SIL instructions:
983998
//

include/swift/Sema/Concurrency.h

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,20 @@ class SourceFile;
2929
class NominalTypeDecl;
3030
class VarDecl;
3131

32-
enum class DiagnosticBehavior: uint8_t;
32+
struct DiagnosticBehavior;
3333

3434
/// If any of the imports in this source file was @preconcurrency but there were
3535
/// no diagnostics downgraded or suppressed due to that @preconcurrency, suggest
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/AST/Type.cpp

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,37 @@
1616

1717
#define DEBUG_TYPE "ast-types"
1818

19-
#include "swift/AST/Types.h"
19+
#include "clang/AST/Type.h"
2020
#include "ForeignRepresentationInfo.h"
2121
#include "swift/AST/ASTContext.h"
2222
#include "swift/AST/ClangModuleLoader.h"
23+
#include "swift/AST/Concurrency.h"
2324
#include "swift/AST/ConformanceLookup.h"
24-
#include "swift/AST/ExistentialLayout.h"
25-
#include "swift/AST/ReferenceCounting.h"
26-
#include "swift/AST/TypeCheckRequests.h"
27-
#include "swift/AST/TypeVisitor.h"
28-
#include "swift/AST/TypeWalker.h"
2925
#include "swift/AST/Decl.h"
26+
#include "swift/AST/ExistentialLayout.h"
3027
#include "swift/AST/GenericEnvironment.h"
3128
#include "swift/AST/LazyResolver.h"
3229
#include "swift/AST/Module.h"
3330
#include "swift/AST/PackConformance.h"
3431
#include "swift/AST/ParameterList.h"
3532
#include "swift/AST/PrettyStackTrace.h"
3633
#include "swift/AST/ProtocolConformance.h"
34+
#include "swift/AST/ReferenceCounting.h"
3735
#include "swift/AST/SILLayout.h"
3836
#include "swift/AST/SubstitutionMap.h"
37+
#include "swift/AST/TypeCheckRequests.h"
3938
#include "swift/AST/TypeLoc.h"
4039
#include "swift/AST/TypeRepr.h"
4140
#include "swift/AST/TypeTransform.h"
41+
#include "swift/AST/TypeVisitor.h"
42+
#include "swift/AST/TypeWalker.h"
43+
#include "swift/AST/Types.h"
4244
#include "swift/Basic/Assertions.h"
4345
#include "swift/Basic/Compiler.h"
44-
#include "clang/AST/Type.h"
4546
#include "llvm/ADT/APFloat.h"
47+
#include "llvm/ADT/STLExtras.h"
4648
#include "llvm/ADT/SmallPtrSet.h"
4749
#include "llvm/ADT/SmallString.h"
48-
#include "llvm/ADT/STLExtras.h"
4950
#include "llvm/Support/Compiler.h"
5051
#include "llvm/Support/Debug.h"
5152
#include "llvm/Support/raw_ostream.h"
@@ -4874,3 +4875,50 @@ StringRef swift::getNameForParamSpecifier(ParamSpecifier specifier) {
48744875
return "implicitly_copyable_consuming";
48754876
}
48764877
}
4878+
4879+
std::optional<DiagnosticBehavior>
4880+
TypeBase::getConcurrencyDiagnosticBehaviorLimit(DeclContext *declCtx) const {
4881+
auto *self = const_cast<TypeBase *>(this);
4882+
4883+
if (auto *nomDecl = self->getNominalOrBoundGenericNominal()) {
4884+
// First try to just grab the exact concurrency diagnostic behavior.
4885+
if (auto result =
4886+
swift::getConcurrencyDiagnosticBehaviorLimit(nomDecl, declCtx)) {
4887+
return result;
4888+
}
4889+
4890+
// But if we get nothing, see if we can come up with diagnostic behavior by
4891+
// merging our fields if we have a struct.
4892+
if (auto *structDecl = dyn_cast<StructDecl>(nomDecl)) {
4893+
std::optional<DiagnosticBehavior> diagnosticBehavior;
4894+
auto substMap = self->getContextSubstitutionMap();
4895+
for (auto storedProperty : structDecl->getStoredProperties()) {
4896+
auto lhs = diagnosticBehavior.value_or(DiagnosticBehavior::Unspecified);
4897+
auto astType = storedProperty->getInterfaceType().subst(substMap);
4898+
auto rhs = astType->getConcurrencyDiagnosticBehaviorLimit(declCtx);
4899+
auto result = lhs.merge(rhs.value_or(DiagnosticBehavior::Unspecified));
4900+
if (result != DiagnosticBehavior::Unspecified)
4901+
diagnosticBehavior = result;
4902+
}
4903+
return diagnosticBehavior;
4904+
}
4905+
}
4906+
4907+
// When attempting to determine the diagnostic behavior limit of a tuple, just
4908+
// merge for each of the elements.
4909+
if (auto *tupleType = self->getAs<TupleType>()) {
4910+
std::optional<DiagnosticBehavior> diagnosticBehavior;
4911+
for (auto tupleType : tupleType->getElements()) {
4912+
auto lhs = diagnosticBehavior.value_or(DiagnosticBehavior::Unspecified);
4913+
4914+
auto type = tupleType.getType()->getCanonicalType();
4915+
auto rhs = type->getConcurrencyDiagnosticBehaviorLimit(declCtx);
4916+
auto result = lhs.merge(rhs.value_or(DiagnosticBehavior::Unspecified));
4917+
if (result != DiagnosticBehavior::Unspecified)
4918+
diagnosticBehavior = result;
4919+
}
4920+
return diagnosticBehavior;
4921+
}
4922+
4923+
return {};
4924+
}

lib/SIL/IR/SILType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/SIL/SILModule.h"
2626
#include "swift/SIL/Test.h"
2727
#include "swift/SIL/TypeLowering.h"
28+
#include "swift/Sema/Concurrency.h"
2829
#include <tuple>
2930

3031
using namespace swift;
@@ -1255,6 +1256,15 @@ bool SILType::isSendable(SILFunction *fn) const {
12551256
return getASTType()->isSendableType();
12561257
}
12571258

1259+
std::optional<DiagnosticBehavior>
1260+
SILType::getConcurrencyDiagnosticBehavior(SILFunction *fn) const {
1261+
auto declRef = fn->getDeclRef();
1262+
if (!declRef)
1263+
return {};
1264+
auto *fromDC = declRef.getInnermostDeclContext();
1265+
return getASTType()->getConcurrencyDiagnosticBehaviorLimit(fromDC);
1266+
}
1267+
12581268
namespace swift::test {
12591269
// Arguments:
12601270
// - SILValue: value

0 commit comments

Comments
 (0)