Skip to content

Commit a3279af

Browse files
authored
Merge pull request #81450 from DougGregor/isolated-conformances-in-default-value-expressions
[SE-0470] Include isolated conformance checks for default value expressions
2 parents 9e24563 + 2dacde1 commit a3279af

5 files changed

+100
-18
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1723,7 +1723,8 @@ bool swift::hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) {
17231723
});
17241724
}
17251725

1726-
/// Determine whether a synth
1726+
/// Determine whether a synthesized requirement for the given conformance
1727+
/// should be explicitly marked as 'nonisolated'.
17271728
static bool synthesizedRequirementIsNonIsolated(
17281729
const NormalProtocolConformance *conformance) {
17291730
// @preconcurrency suppresses this.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,6 +2823,29 @@ namespace {
28232823
}
28242824
}
28252825

2826+
/// Function object that refines isolation for each actor isolation it is
2827+
/// given, returning true if all of the provided isolations have been
2828+
/// accounted for, or false if the caller should handle them.
2829+
class RefineConformances {
2830+
ActorIsolationChecker &self;
2831+
2832+
public:
2833+
RefineConformances(ActorIsolationChecker &self) : self(self) { }
2834+
2835+
bool operator()(ArrayRef<ActorIsolation> isolations) const {
2836+
bool anyRefined = false;
2837+
bool anyUnrefined = false;
2838+
for (const auto &isolation : isolations) {
2839+
if (self.refineRequiredIsolation(isolation))
2840+
anyRefined = true;
2841+
else
2842+
anyUnrefined = true;
2843+
}
2844+
2845+
return anyRefined && !anyUnrefined;
2846+
}
2847+
};
2848+
28262849
bool refineRequiredIsolation(ActorIsolation refinedIsolation) {
28272850
if (requiredIsolationLoc.isInvalid())
28282851
return false;
@@ -3332,13 +3355,13 @@ namespace {
33323355
if (auto erasureExpr = dyn_cast<ErasureExpr>(expr)) {
33333356
checkIsolatedConformancesInContext(
33343357
erasureExpr->getConformances(), erasureExpr->getLoc(),
3335-
getDeclContext());
3358+
getDeclContext(), RefineConformances{*this});
33363359
}
33373360

33383361
if (auto *underlyingToOpaque = dyn_cast<UnderlyingToOpaqueExpr>(expr)) {
33393362
checkIsolatedConformancesInContext(
33403363
underlyingToOpaque->substitutions, underlyingToOpaque->getLoc(),
3341-
getDeclContext());
3364+
getDeclContext(), RefineConformances{*this});
33423365
}
33433366

33443367
return Action::Continue(expr);
@@ -4447,7 +4470,8 @@ namespace {
44474470
return false;
44484471

44494472
// Make sure isolated conformances are formed in the right context.
4450-
checkIsolatedConformancesInContext(declRef, loc, getDeclContext());
4473+
checkIsolatedConformancesInContext(declRef, loc, getDeclContext(),
4474+
RefineConformances{*this});
44514475

44524476
auto *const decl = declRef.getDecl();
44534477

@@ -8015,11 +8039,14 @@ namespace {
80158039
class MismatchedIsolatedConformances {
80168040
llvm::TinyPtrVector<ProtocolConformance *> badIsolatedConformances;
80178041
DeclContext *fromDC;
8042+
HandleConformanceIsolationFn handleBad;
80188043
mutable std::optional<ActorIsolation> fromIsolation;
80198044

80208045
public:
8021-
MismatchedIsolatedConformances(const DeclContext *fromDC)
8022-
: fromDC(const_cast<DeclContext *>(fromDC)) { }
8046+
MismatchedIsolatedConformances(const DeclContext *fromDC,
8047+
HandleConformanceIsolationFn handleBad)
8048+
: fromDC(const_cast<DeclContext *>(fromDC)),
8049+
handleBad(handleBad) { }
80238050

80248051
ActorIsolation getContextIsolation() const {
80258052
if (!fromIsolation)
@@ -8059,6 +8086,16 @@ namespace {
80598086
if (badIsolatedConformances.empty())
80608087
return false;
80618088

8089+
if (handleBad) {
8090+
// Capture all of the actor isolations from the conformances.
8091+
std::vector<ActorIsolation> badIsolations;
8092+
for (auto conformance : badIsolatedConformances)
8093+
badIsolations.push_back(conformance->getIsolation());
8094+
8095+
if (handleBad(badIsolations))
8096+
return false;
8097+
}
8098+
80628099
ASTContext &ctx = fromDC->getASTContext();
80638100
auto firstConformance = badIsolatedConformances.front();
80648101
ctx.Diags.diagnose(
@@ -8074,32 +8111,40 @@ namespace {
80748111

80758112
}
80768113

8114+
bool swift::doNotDiagnoseConformanceIsolation(ArrayRef<ActorIsolation>) {
8115+
return false;
8116+
}
8117+
80778118
bool swift::checkIsolatedConformancesInContext(
8078-
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc) {
8079-
MismatchedIsolatedConformances mismatched(dc);
8119+
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc,
8120+
HandleConformanceIsolationFn handleBad) {
8121+
MismatchedIsolatedConformances mismatched(dc, handleBad);
80808122
forEachConformance(declRef, mismatched);
80818123
return mismatched.diagnose(loc);
80828124
}
80838125

80848126
bool swift::checkIsolatedConformancesInContext(
80858127
ArrayRef<ProtocolConformanceRef> conformances, SourceLoc loc,
8086-
const DeclContext *dc) {
8087-
MismatchedIsolatedConformances mismatched(dc);
8128+
const DeclContext *dc,
8129+
HandleConformanceIsolationFn handleBad) {
8130+
MismatchedIsolatedConformances mismatched(dc, handleBad);
80888131
for (auto conformance: conformances)
80898132
forEachConformance(conformance, mismatched);
80908133
return mismatched.diagnose(loc);
80918134
}
80928135

80938136
bool swift::checkIsolatedConformancesInContext(
8094-
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc) {
8095-
MismatchedIsolatedConformances mismatched(dc);
8137+
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc,
8138+
HandleConformanceIsolationFn handleBad) {
8139+
MismatchedIsolatedConformances mismatched(dc, handleBad);
80968140
forEachConformance(subs, mismatched);
80978141
return mismatched.diagnose(loc);
80988142
}
80998143

81008144
bool swift::checkIsolatedConformancesInContext(
8101-
Type type, SourceLoc loc, const DeclContext *dc) {
8102-
MismatchedIsolatedConformances mismatched(dc);
8145+
Type type, SourceLoc loc, const DeclContext *dc,
8146+
HandleConformanceIsolationFn handleBad) {
8147+
MismatchedIsolatedConformances mismatched(dc, handleBad);
81038148
forEachConformance(type, mismatched);
81048149
return mismatched.diagnose(loc);
81058150
}

lib/Sema/TypeCheckConcurrency.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,12 +734,22 @@ void introduceUnsafeInheritExecutorReplacements(
734734
void introduceUnsafeInheritExecutorReplacements(
735735
const DeclContext *dc, Type base, SourceLoc loc, LookupResult &result);
736736

737+
/// Function that attempts to handle all of the "bad" conformance isolation
738+
/// found somewhere, and returns true if it handled them. If not, returns
739+
/// false so that the conformances can be diagnose.
740+
using HandleConformanceIsolationFn =
741+
llvm::function_ref<bool(ArrayRef<ActorIsolation>)>;
742+
743+
/// Function used as a default HandleConformanceIsolationFn.
744+
bool doNotDiagnoseConformanceIsolation(ArrayRef<ActorIsolation>);
745+
737746
/// Check for correct use of isolated conformances in the given reference.
738747
///
739748
/// This checks that any isolated conformances that occur in the given
740749
/// declaration reference match the isolated of the context.
741750
bool checkIsolatedConformancesInContext(
742-
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc);
751+
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc,
752+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
743753

744754
/// Check for correct use of isolated conformances in the set given set of
745755
/// protocol conformances.
@@ -748,22 +758,25 @@ bool checkIsolatedConformancesInContext(
748758
/// declaration reference match the isolated of the context.
749759
bool checkIsolatedConformancesInContext(
750760
ArrayRef<ProtocolConformanceRef> conformances, SourceLoc loc,
751-
const DeclContext *dc);
761+
const DeclContext *dc,
762+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
752763

753764
/// Check for correct use of isolated conformances in the given substitution
754765
/// map.
755766
///
756767
/// This checks that any isolated conformances that occur in the given
757768
/// substitution map match the isolated of the context.
758769
bool checkIsolatedConformancesInContext(
759-
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc);
770+
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc,
771+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
760772

761773
/// Check for correct use of isolated conformances in the given type.
762774
///
763775
/// This checks that any isolated conformances that occur in the given
764776
/// type match the isolated of the context.
765777
bool checkIsolatedConformancesInContext(
766-
Type type, SourceLoc loc, const DeclContext *dc);
778+
Type type, SourceLoc loc, const DeclContext *dc,
779+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
767780

768781
} // end namespace swift
769782

test/Concurrency/isolated_conformance_default_actor.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class CodableClass: Codable {
6060
var state: Int = 0
6161
}
6262

63+
class OtherClass {
64+
var otherState: any Encodable.Type = CodableClass.self
65+
}
66+
6367
func acceptSendablePMeta<T: Sendable & P>(_: T.Type) { }
6468
func acceptSendableQMeta<T: Sendable & Q>(_: T.Type) { }
6569

test/Concurrency/isolated_conformance_inference.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,22 @@ nonisolated func testConformancesFromNonisolated(tdc: TestDerivedCodable) {
7373

7474
let _: any Codable = tdc
7575
}
76+
77+
protocol P2 {
78+
func g()
79+
}
80+
81+
struct DifferingConformances: @MainActor P {
82+
@MainActor func f() { }
83+
}
84+
85+
extension DifferingConformances: @SomeGlobalActor P2 {
86+
@SomeGlobalActor func g() { }
87+
}
88+
89+
@MainActor
90+
class InferMeDefaults {
91+
var mainState: any P.Type = DifferingConformances.self
92+
var someGlobalActorState: any P2.Type = DifferingConformances.self // expected-error{{global actor 'SomeGlobalActor'-isolated default value in a main actor-isolated context}}
93+
var bothState: any (P & P2).Type = DifferingConformances.self // expected-error{{default argument cannot be both main actor-isolated and global actor 'SomeGlobalActor'-isolated}}
94+
}

0 commit comments

Comments
 (0)