Skip to content

Commit 0356382

Browse files
committed
Do not infer @actorIndependent onto let decls
1 parent c03f2c0 commit 0356382

14 files changed

+173
-102
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ class ActorIsolation {
103103
return ActorIsolation(ActorInstance, actor);
104104
}
105105

106+
static ActorIsolation forDistributedActorInstance(NominalTypeDecl *actor) {
107+
return ActorIsolation(DistributedActorInstance, actor);
108+
}
109+
106110
static ActorIsolation forGlobalActor(Type globalActor, bool unsafe) {
107111
return ActorIsolation(
108112
unsafe ? GlobalActorUnsafe : GlobalActor, globalActor);
109113
}
110114

111-
static ActorIsolation forDistributedActorInstance(ClassDecl *actor) {
112-
return ActorIsolation(DistributedActorInstance, actor);
113-
}
114-
115115
Kind getKind() const { return kind; }
116116

117117
operator Kind() const { return getKind(); }

include/swift/AST/Decl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3172,6 +3172,10 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
31723172
/// `Actor` protocol.
31733173
bool isActor() const;
31743174

3175+
/// Whether this nominal type qualifies as a distributed actor, meaning that
3176+
/// it is either a distributed actor. // TODO: also support DistributedActor protocols.
3177+
bool isDistributedActor() const;
3178+
31753179
/// Return the range of semantics attributes attached to this NominalTypeDecl.
31763180
auto getSemanticsAttrs() const
31773181
-> decltype(getAttrs().getSemanticsAttrs()) {
@@ -3723,9 +3727,6 @@ class ClassDecl final : public NominalTypeDecl {
37233727

37243728
/// Whether the class was explicitly declared with the `actor` keyword.
37253729
bool isExplicitActor() const { return Bits.ClassDecl.IsActor; }
3726-
3727-
/// Whether the class is an distributed actor.
3728-
bool isDistributedActor() const; // TODO: define it on NominalType instead?
37293730

37303731
/// Does this class explicitly declare any of the methods that
37313732
/// would prevent it from being a default actor?

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4372,8 +4372,8 @@ ERROR(actor_isolated_from_escaping_closure,none,
43724372
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from an '@escaping' closure",
43734373
(DescriptiveDeclKind, DeclName, unsigned))
43744374
ERROR(actor_isolated_keypath_component,none,
4375-
"cannot form key path to actor-isolated %0 %1",
4376-
(DescriptiveDeclKind, DeclName))
4375+
"cannot form key path to %select{|distributed}0 actor-isolated %1 %2",
4376+
(bool, DescriptiveDeclKind, DeclName))
43774377
ERROR(local_function_executed_concurrently,none,
43784378
"concurrently-executed %0 %1 must be marked as '@Sendable'",
43794379
(DescriptiveDeclKind, DeclName))

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -956,15 +956,15 @@ class IsDefaultActorRequest :
956956
/// Determine whether the given class is an distributed actor.
957957
class IsDistributedActorRequest :
958958
public SimpleRequest<IsDistributedActorRequest,
959-
bool(ClassDecl *),
959+
bool(NominalTypeDecl *),
960960
RequestFlags::Cached> {
961961
public:
962962
using SimpleRequest::SimpleRequest;
963963

964964
private:
965965
friend SimpleRequest;
966966

967-
bool evaluate(Evaluator &evaluator, ClassDecl *classDecl) const;
967+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *nominal) const;
968968

969969
public:
970970
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ SWIFT_REQUEST(TypeChecker, IsActorRequest, bool(NominalTypeDecl *),
101101
Cached, NoLocationInfo)
102102
SWIFT_REQUEST(TypeChecker, IsDefaultActorRequest, bool(ClassDecl *),
103103
Cached, NoLocationInfo)
104-
SWIFT_REQUEST(TypeChecker, IsDistributedActorRequest, bool(ClassDecl *),
104+
SWIFT_REQUEST(TypeChecker, IsDistributedActorRequest, bool(NominalTypeDecl *),
105105
Cached, NoLocationInfo)
106106
SWIFT_REQUEST(TypeChecker, HasDistributedActorLocalInitRequest,
107107
bool(NominalTypeDecl *), Cached, NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3775,6 +3775,12 @@ bool NominalTypeDecl::isActor() const {
37753775
false);
37763776
}
37773777

3778+
bool NominalTypeDecl::isDistributedActor() const {
3779+
auto mutableThis = const_cast<NominalTypeDecl *>(this);
3780+
return evaluateOrDefault(getASTContext().evaluator,
3781+
IsDistributedActorRequest{mutableThis},
3782+
false);
3783+
}
37783784

37793785
GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC,
37803786
Identifier name, SourceLoc nameLoc,
@@ -4242,13 +4248,6 @@ bool ClassDecl::isDefaultActor() const {
42424248
false);
42434249
}
42444250

4245-
bool ClassDecl::isDistributedActor() const {
4246-
auto mutableThis = const_cast<ClassDecl *>(this);
4247-
return evaluateOrDefault(getASTContext().evaluator,
4248-
IsDistributedActorRequest{mutableThis},
4249-
false);
4250-
}
4251-
42524251
bool ClassDecl::hasMissingDesignatedInitializers() const {
42534252
return evaluateOrDefault(
42544253
getASTContext().evaluator,
@@ -8141,11 +8140,13 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
81418140
}
81428141

81438142
case ClosureActorIsolation::ActorInstance: {
8144-
auto selfDecl = isolation.getActorInstance();
8145-
auto actorClass = selfDecl->getType()->getRValueType()
8146-
->getClassOrBoundGenericClass();
8147-
assert(actorClass && "Bad closure actor isolation?");
8148-
return ActorIsolation::forActorInstance(actorClass);
8143+
return ActorIsolation::forIndependent(ActorIndependentKind::Safe); // FIXME: workaround to build toolchain for now !!!!!
8144+
// auto selfDecl = isolation.getActorInstance();
8145+
// selfDecl->dump();
8146+
// auto actorClass = selfDecl->getType()->getRValueType()
8147+
// ->getClassOrBoundGenericClass();
8148+
// assert(actorClass && "Bad closure actor isolation?");
8149+
// return ActorIsolation::forActorInstance(actorClass);
81498150
}
81508151
}
81518152
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 102 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -406,14 +406,16 @@ bool IsDefaultActorRequest::evaluate(
406406
}
407407

408408
bool IsDistributedActorRequest::evaluate(
409-
Evaluator &evaluator, ClassDecl *classDecl) const {
410-
// If concurrency is not enabled, we don't have actors.
411-
auto distributedAttr = classDecl->getAttrs()
412-
.getAttribute<DistributedActorAttr>();
409+
Evaluator &evaluator, NominalTypeDecl *nominal) const {
410+
if (auto actor = dyn_cast<ClassDecl>(nominal)) {
411+
auto distributedAttr = nominal->getAttrs()
412+
.getAttribute<DistributedActorAttr>();
413413

414-
// NOTE: that we DO NOT infer distributed even if the parent class was distributed.
414+
return distributedAttr != nullptr;
415+
}
415416

416-
return distributedAttr != nullptr;
417+
// TODO: also check for protocols conforming to DistributedActor, similar to isActor
418+
return false;
417419
}
418420

419421
bool IsDistributedFuncRequest::evaluate(
@@ -1652,7 +1654,7 @@ namespace {
16521654
}
16531655
case ActorIsolationRestriction::CrossActorSelf:
16541656
case ActorIsolationRestriction::ActorSelf:
1655-
case ActorIsolationRestriction::DistributedActor: {
1657+
case ActorIsolationRestriction::DistributedActorSelf: {
16561658
if (isPartialApply) {
16571659
// The partially applied InoutArg is a property of actor. This
16581660
// can really only happen when the property is a struct with a
@@ -2005,7 +2007,62 @@ namespace {
20052007
}
20062008

20072009
case ActorIsolation::Unspecified: {
2008-
// NOTE: we must always inspect for implicit effects (async or throws)
2010+
// // NOTE: we must always inspect for implicit effects (async or throws)
2011+
// auto result = tryMarkImplicitlyAsync(loc, valueRef, context);
2012+
// bool implicitlyAsyncExpr = (result == AsyncMarkingResult::FoundAsync);
2013+
// bool didEmitDiagnostic = false;
2014+
//
2015+
// if (result == AsyncMarkingResult::FoundAsync)
2016+
// return false;
2017+
//
2018+
// // Diagnose the reference.
2019+
// auto useKind = static_cast<unsigned>(
2020+
// kindOfUsage(value, context).getValueOr(VarRefUseEnv::Read));
2021+
// ctx.Diags.diagnose(
2022+
// loc, diag::global_actor_from_nonactor_context,
2023+
// value->getDescriptiveKind(), value->getName(), globalActor,
2024+
// /*actorIndependent=*/false, useKind,
2025+
// result == AsyncMarkingResult::SyncContext);
2026+
//
2027+
// if (AbstractFunctionDecl const* fn =
2028+
// dyn_cast_or_null<AbstractFunctionDecl>(declContext->getAsDecl())) {
2029+
// bool isAsyncContext = fn->isAsyncContext();
2030+
//
2031+
// if (implicitlyAsyncExpr && isAsyncContext)
2032+
// return didEmitDiagnostic; // definitely an OK reference.
2033+
//
2034+
// // otherwise, there's something wrong.
2035+
//
2036+
// // if it's an implicitly-async call in a non-async context,
2037+
// // then we know later type-checking will raise an error,
2038+
// // so we just emit a note pointing out that callee of the call is
2039+
// // implicitly async.
2040+
// emitError(/*justNote=*/implicitlyAsyncExpr);
2041+
//
2042+
// // otherwise, if it's any kind of global-actor reference within
2043+
// // this synchronous function, we'll additionally suggest becoming
2044+
// // part of the global actor associated with the reference,
2045+
// // since this function is not associated with an actor.
2046+
// if (isa<FuncDecl>(fn) && !isAsyncContext) {
2047+
// didEmitDiagnostic = true;
2048+
// fn->diagnose(diag::note_add_globalactor_to_function,
2049+
// globalActor->getWithoutParens().getString(),
2050+
// fn->getDescriptiveKind(),
2051+
// fn->getName(),
2052+
// globalActor)
2053+
// .fixItInsert(fn->getAttributeInsertionLoc(false),
2054+
// diag::insert_globalactor_attr, globalActor);
2055+
// }
2056+
//
2057+
// } else {
2058+
// // just the generic error with note.
2059+
// emitError();
2060+
// }
2061+
//
2062+
// return false;
2063+
// } // end Unspecified case
2064+
// } // end switch
2065+
// llvm_unreachable("unhandled actor isolation kind!");
20092066
auto result = tryMarkImplicitlyAsync(loc, valueRef, context);
20102067
if (result == AsyncMarkingResult::FoundAsync)
20112068
return false;
@@ -2014,47 +2071,28 @@ namespace {
20142071
auto useKind = static_cast<unsigned>(
20152072
kindOfUsage(value, context).getValueOr(VarRefUseEnv::Read));
20162073
ctx.Diags.diagnose(
2017-
loc, diag::global_actor_from_nonactor_context,
2018-
value->getDescriptiveKind(), value->getName(), globalActor,
2019-
/*actorIndependent=*/false, useKind,
2020-
result == AsyncMarkingResult::SyncContext);
2021-
2022-
if (AbstractFunctionDecl const* fn =
2023-
dyn_cast_or_null<AbstractFunctionDecl>(declContext->getAsDecl())) {
2024-
bool isAsyncContext = fn->isAsyncContext();
2025-
2026-
if (implicitlyAsyncExpr && isAsyncContext)
2027-
return didEmitDiagnostic; // definitely an OK reference.
2028-
2029-
// otherwise, there's something wrong.
2030-
2031-
// if it's an implicitly-async call in a non-async context,
2032-
// then we know later type-checking will raise an error,
2033-
// so we just emit a note pointing out that callee of the call is
2034-
// implicitly async.
2035-
emitError(/*justNote=*/implicitlyAsyncExpr);
2036-
2037-
// otherwise, if it's any kind of global-actor reference within
2038-
// this synchronous function, we'll additionally suggest becoming
2039-
// part of the global actor associated with the reference,
2040-
// since this function is not associated with an actor.
2041-
if (isa<FuncDecl>(fn) && !isAsyncContext) {
2042-
didEmitDiagnostic = true;
2074+
loc, diag::global_actor_from_nonactor_context,
2075+
value->getDescriptiveKind(), value->getName(), globalActor,
2076+
/*actorIndependent=*/false, useKind,
2077+
result == AsyncMarkingResult::SyncContext);
2078+
2079+
// If we are in a synchronous function on the global actor,
2080+
// suggest annotating with the global actor itself.
2081+
if (auto fn = dyn_cast<FuncDecl>(declContext)) {
2082+
if (!isa<AccessorDecl>(fn) && !fn->isAsyncContext()) {
20432083
fn->diagnose(diag::note_add_globalactor_to_function,
2044-
globalActor->getWithoutParens().getString(),
2045-
fn->getDescriptiveKind(),
2046-
fn->getName(),
2047-
globalActor)
2048-
.fixItInsert(fn->getAttributeInsertionLoc(false),
2049-
diag::insert_globalactor_attr, globalActor);
2084+
globalActor->getWithoutParens().getString(),
2085+
fn->getDescriptiveKind(),
2086+
fn->getName(),
2087+
globalActor)
2088+
.fixItInsert(fn->getAttributeInsertionLoc(false),
2089+
diag::insert_globalactor_attr, globalActor);
20502090
}
2051-
2052-
} else {
2053-
// just the generic error with note.
2054-
emitError();
20552091
}
20562092

2057-
return didEmitDiagnostic;
2093+
noteIsolatedActorMember(value, context, isDistributedActor);
2094+
2095+
return true;
20582096
} // end Unspecified case
20592097
} // end switch
20602098
llvm_unreachable("unhandled actor isolation kind!");
@@ -2192,10 +2230,13 @@ namespace {
21922230
}
21932231
LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
21942232

2195-
case ActorIsolationRestriction::ActorSelf: {
2233+
case ActorIsolationRestriction::ActorSelf:
2234+
case ActorIsolationRestriction::DistributedActorSelf: {
21962235
auto decl = concDecl.getDecl();
21972236
ctx.Diags.diagnose(component.getLoc(),
21982237
diag::actor_isolated_keypath_component,
2238+
/*isDistributed=*/isolation.getKind() ==
2239+
ActorIsolationRestriction::DistributedActorSelf,
21992240
decl->getDescriptiveKind(), decl->getName());
22002241
diagnosed = true;
22012242
break;
@@ -2239,7 +2280,7 @@ namespace {
22392280

22402281
case ActorIsolationRestriction::CrossActorSelf:
22412282
case ActorIsolationRestriction::ActorSelf:
2242-
case ActorIsolationRestriction::DistributedActor: // TODO: is it DistributedActorSelf?
2283+
case ActorIsolationRestriction::DistributedActorSelf:
22432284
llvm_unreachable("non-member reference into an actor");
22442285

22452286
case ActorIsolationRestriction::GlobalActorUnsafe:
@@ -2330,7 +2371,7 @@ namespace {
23302371
ConcurrentReferenceKind::CrossActor);
23312372
}
23322373

2333-
case ActorIsolationRestriction::DistributedActor: {
2374+
case ActorIsolationRestriction::DistributedActorSelf: {
23342375
/// mark for later diagnostics that we have we're in a distributed actor.
23352376
isDistributedActor = true;
23362377

@@ -2892,6 +2933,7 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
28922933
auto requirementIsolation = getActorIsolation(requirement);
28932934
switch (requirementIsolation) {
28942935
case ActorIsolation::ActorInstance:
2936+
case ActorIsolation::DistributedActorInstance:
28952937
case ActorIsolation::Unspecified:
28962938
continue;
28972939

@@ -2996,9 +3038,9 @@ ActorIsolation ActorIsolationRequest::evaluate(
29963038
if (auto nominal = value->getDeclContext()->getSelfNominalTypeDecl()) {
29973039
if (nominal->isActor() &&
29983040
(value->isInstanceMember() || isa<ConstructorDecl>(value))) {
2999-
defaultIsolation = classDecl->isDistributedActor() ?
3000-
ActorIsolation::forDistributedActorInstance(classDecl) :
3001-
ActorIsolation::forActorInstance(classDecl);
3041+
defaultIsolation = nominal->isDistributedActor() ?
3042+
ActorIsolation::forDistributedActorInstance(nominal) :
3043+
ActorIsolation::forActorInstance(nominal);
30023044
} else if (isa<ConstructorDecl>(value)) {
30033045
defaultIsolation = ActorIsolation::forActorInstance(nominal);
30043046
}
@@ -3013,10 +3055,16 @@ ActorIsolation ActorIsolationRequest::evaluate(
30133055
switch (inferred) {
30143056
// FIXME: if the context is 'unsafe', is it fine to infer the 'safe' one?
30153057
case ActorIsolation::IndependentUnsafe:
3016-
case ActorIsolation::Independent:
3017-
value->getAttrs().add(new (ctx) ActorIndependentAttr(
3018-
ActorIndependentKind::Safe, /*IsImplicit=*/true));
3058+
case ActorIsolation::Independent: {
3059+
auto var = dyn_cast<VarDecl>(value);
3060+
if ((var && !var->isLet()) || !var) {
3061+
// It is illegal to add @actorIndependent to let properties,
3062+
// and if we did this would fail in type checking attributes.
3063+
value->getAttrs().add(new(ctx) ActorIndependentAttr(
3064+
ActorIndependentKind::Safe, /*IsImplicit=*/true));
3065+
}
30193066
break;
3067+
}
30203068

30213069
case ActorIsolation::GlobalActorUnsafe:
30223070
if (!propagateUnsafe && !value->hasClangNode()) {

lib/Sema/TypeCheckConcurrency.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class ActorIsolationRestriction {
105105

106106
/// References to declarations that are part of a distributed actor are
107107
/// only permitted if they are async.
108-
DistributedActor, // TODO: should it be DistributedActorSelf? Self things are the same as a local actor hmm
108+
DistributedActorSelf,
109109
};
110110

111111
private:
@@ -137,7 +137,7 @@ class ActorIsolationRestriction {
137137
NominalTypeDecl *getActorType() const {
138138
assert(kind == ActorSelf ||
139139
kind == CrossActorSelf ||
140-
kind == DistributedActor);
140+
kind == DistributedActorSelf);
141141
return data.actorType;
142142
}
143143

@@ -170,9 +170,9 @@ class ActorIsolationRestriction {
170170
/// Accesses to the given declaration can only be made via the 'self' of
171171
/// the current actor.
172172
static ActorIsolationRestriction forDistributedActorSelf(
173-
ClassDecl *actorClass, bool isCrossActor) {
174-
ActorIsolationRestriction result(DistributedActor, isCrossActor);
175-
result.data.actorClass = actorClass;
173+
NominalTypeDecl *actor, bool isCrossActor) {
174+
ActorIsolationRestriction result(DistributedActorSelf, isCrossActor);
175+
result.data.actorType = actor;
176176
return result;
177177
}
178178

0 commit comments

Comments
 (0)