Skip to content

Commit 601cde3

Browse files
authored
Merge pull request #81451 from DougGregor/isolated-conformances-in-default-value-expressions-6.2
[SE-0470] Include isolated conformance checks for default value expressions
2 parents 1072dbe + 760d0a3 commit 601cde3

File tree

5 files changed

+100
-18
lines changed

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
@@ -1728,7 +1728,8 @@ bool swift::hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) {
17281728
});
17291729
}
17301730

1731-
/// Determine whether a synth
1731+
/// Determine whether a synthesized requirement for the given conformance
1732+
/// should be explicitly marked as 'nonisolated'.
17321733
static bool synthesizedRequirementIsNonIsolated(
17331734
const NormalProtocolConformance *conformance) {
17341735
// @preconcurrency suppresses this.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,6 +2839,29 @@ namespace {
28392839
}
28402840
}
28412841

2842+
/// Function object that refines isolation for each actor isolation it is
2843+
/// given, returning true if all of the provided isolations have been
2844+
/// accounted for, or false if the caller should handle them.
2845+
class RefineConformances {
2846+
ActorIsolationChecker &self;
2847+
2848+
public:
2849+
RefineConformances(ActorIsolationChecker &self) : self(self) { }
2850+
2851+
bool operator()(ArrayRef<ActorIsolation> isolations) const {
2852+
bool anyRefined = false;
2853+
bool anyUnrefined = false;
2854+
for (const auto &isolation : isolations) {
2855+
if (self.refineRequiredIsolation(isolation))
2856+
anyRefined = true;
2857+
else
2858+
anyUnrefined = true;
2859+
}
2860+
2861+
return anyRefined && !anyUnrefined;
2862+
}
2863+
};
2864+
28422865
bool refineRequiredIsolation(ActorIsolation refinedIsolation) {
28432866
if (requiredIsolationLoc.isInvalid())
28442867
return false;
@@ -3348,13 +3371,13 @@ namespace {
33483371
if (auto erasureExpr = dyn_cast<ErasureExpr>(expr)) {
33493372
checkIsolatedConformancesInContext(
33503373
erasureExpr->getConformances(), erasureExpr->getLoc(),
3351-
getDeclContext());
3374+
getDeclContext(), RefineConformances{*this});
33523375
}
33533376

33543377
if (auto *underlyingToOpaque = dyn_cast<UnderlyingToOpaqueExpr>(expr)) {
33553378
checkIsolatedConformancesInContext(
33563379
underlyingToOpaque->substitutions, underlyingToOpaque->getLoc(),
3357-
getDeclContext());
3380+
getDeclContext(), RefineConformances{*this});
33583381
}
33593382

33603383
return Action::Continue(expr);
@@ -4463,7 +4486,8 @@ namespace {
44634486
return false;
44644487

44654488
// Make sure isolated conformances are formed in the right context.
4466-
checkIsolatedConformancesInContext(declRef, loc, getDeclContext());
4489+
checkIsolatedConformancesInContext(declRef, loc, getDeclContext(),
4490+
RefineConformances{*this});
44674491

44684492
auto *const decl = declRef.getDecl();
44694493

@@ -8039,11 +8063,14 @@ namespace {
80398063
class MismatchedIsolatedConformances {
80408064
llvm::TinyPtrVector<ProtocolConformance *> badIsolatedConformances;
80418065
DeclContext *fromDC;
8066+
HandleConformanceIsolationFn handleBad;
80428067
mutable std::optional<ActorIsolation> fromIsolation;
80438068

80448069
public:
8045-
MismatchedIsolatedConformances(const DeclContext *fromDC)
8046-
: fromDC(const_cast<DeclContext *>(fromDC)) { }
8070+
MismatchedIsolatedConformances(const DeclContext *fromDC,
8071+
HandleConformanceIsolationFn handleBad)
8072+
: fromDC(const_cast<DeclContext *>(fromDC)),
8073+
handleBad(handleBad) { }
80478074

80488075
ActorIsolation getContextIsolation() const {
80498076
if (!fromIsolation)
@@ -8083,6 +8110,16 @@ namespace {
80838110
if (badIsolatedConformances.empty())
80848111
return false;
80858112

8113+
if (handleBad) {
8114+
// Capture all of the actor isolations from the conformances.
8115+
std::vector<ActorIsolation> badIsolations;
8116+
for (auto conformance : badIsolatedConformances)
8117+
badIsolations.push_back(conformance->getIsolation());
8118+
8119+
if (handleBad(badIsolations))
8120+
return false;
8121+
}
8122+
80868123
ASTContext &ctx = fromDC->getASTContext();
80878124
auto firstConformance = badIsolatedConformances.front();
80888125
ctx.Diags.diagnose(
@@ -8098,32 +8135,40 @@ namespace {
80988135

80998136
}
81008137

8138+
bool swift::doNotDiagnoseConformanceIsolation(ArrayRef<ActorIsolation>) {
8139+
return false;
8140+
}
8141+
81018142
bool swift::checkIsolatedConformancesInContext(
8102-
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc) {
8103-
MismatchedIsolatedConformances mismatched(dc);
8143+
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc,
8144+
HandleConformanceIsolationFn handleBad) {
8145+
MismatchedIsolatedConformances mismatched(dc, handleBad);
81048146
forEachConformance(declRef, mismatched);
81058147
return mismatched.diagnose(loc);
81068148
}
81078149

81088150
bool swift::checkIsolatedConformancesInContext(
81098151
ArrayRef<ProtocolConformanceRef> conformances, SourceLoc loc,
8110-
const DeclContext *dc) {
8111-
MismatchedIsolatedConformances mismatched(dc);
8152+
const DeclContext *dc,
8153+
HandleConformanceIsolationFn handleBad) {
8154+
MismatchedIsolatedConformances mismatched(dc, handleBad);
81128155
for (auto conformance: conformances)
81138156
forEachConformance(conformance, mismatched);
81148157
return mismatched.diagnose(loc);
81158158
}
81168159

81178160
bool swift::checkIsolatedConformancesInContext(
8118-
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc) {
8119-
MismatchedIsolatedConformances mismatched(dc);
8161+
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc,
8162+
HandleConformanceIsolationFn handleBad) {
8163+
MismatchedIsolatedConformances mismatched(dc, handleBad);
81208164
forEachConformance(subs, mismatched);
81218165
return mismatched.diagnose(loc);
81228166
}
81238167

81248168
bool swift::checkIsolatedConformancesInContext(
8125-
Type type, SourceLoc loc, const DeclContext *dc) {
8126-
MismatchedIsolatedConformances mismatched(dc);
8169+
Type type, SourceLoc loc, const DeclContext *dc,
8170+
HandleConformanceIsolationFn handleBad) {
8171+
MismatchedIsolatedConformances mismatched(dc, handleBad);
81278172
forEachConformance(type, mismatched);
81288173
return mismatched.diagnose(loc);
81298174
}

lib/Sema/TypeCheckConcurrency.h

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

705+
/// Function that attempts to handle all of the "bad" conformance isolation
706+
/// found somewhere, and returns true if it handled them. If not, returns
707+
/// false so that the conformances can be diagnose.
708+
using HandleConformanceIsolationFn =
709+
llvm::function_ref<bool(ArrayRef<ActorIsolation>)>;
710+
711+
/// Function used as a default HandleConformanceIsolationFn.
712+
bool doNotDiagnoseConformanceIsolation(ArrayRef<ActorIsolation>);
713+
705714
/// Check for correct use of isolated conformances in the given reference.
706715
///
707716
/// This checks that any isolated conformances that occur in the given
708717
/// declaration reference match the isolated of the context.
709718
bool checkIsolatedConformancesInContext(
710-
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc);
719+
ConcreteDeclRef declRef, SourceLoc loc, const DeclContext *dc,
720+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
711721

712722
/// Check for correct use of isolated conformances in the set given set of
713723
/// protocol conformances.
@@ -716,22 +726,25 @@ bool checkIsolatedConformancesInContext(
716726
/// declaration reference match the isolated of the context.
717727
bool checkIsolatedConformancesInContext(
718728
ArrayRef<ProtocolConformanceRef> conformances, SourceLoc loc,
719-
const DeclContext *dc);
729+
const DeclContext *dc,
730+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
720731

721732
/// Check for correct use of isolated conformances in the given substitution
722733
/// map.
723734
///
724735
/// This checks that any isolated conformances that occur in the given
725736
/// substitution map match the isolated of the context.
726737
bool checkIsolatedConformancesInContext(
727-
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc);
738+
SubstitutionMap subs, SourceLoc loc, const DeclContext *dc,
739+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
728740

729741
/// Check for correct use of isolated conformances in the given type.
730742
///
731743
/// This checks that any isolated conformances that occur in the given
732744
/// type match the isolated of the context.
733745
bool checkIsolatedConformancesInContext(
734-
Type type, SourceLoc loc, const DeclContext *dc);
746+
Type type, SourceLoc loc, const DeclContext *dc,
747+
HandleConformanceIsolationFn handleBad = doNotDiagnoseConformanceIsolation);
735748

736749
} // end namespace swift
737750

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)