-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency] Suggest adding a method, when mutating actor property cross isolation #75922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11651,6 +11651,10 @@ ActorIsolation::ActorIsolation(Kind kind, Expr *actor, | |
: actorInstance(actor), kind(kind), isolatedByPreconcurrency(false), | ||
silParsed(false), parameterIndex(parameterIndex) {} | ||
|
||
ActorIsolation::ActorIsolation(Kind kind, Type globalActor) | ||
: globalActor(globalActor), kind(kind), isolatedByPreconcurrency(false), | ||
silParsed(false), parameterIndex(0) {} | ||
|
||
ActorIsolation | ||
ActorIsolation::forActorInstanceParameter(Expr *actor, | ||
unsigned parameterIndex) { | ||
|
@@ -11701,51 +11705,29 @@ ActorIsolation ActorIsolation::forActorInstanceSelf(NominalTypeDecl *selfDecl) { | |
} | ||
|
||
NominalTypeDecl *ActorIsolation::getActor() const { | ||
assert(getKind() == ActorInstance || | ||
getKind() == GlobalActor); | ||
assert(getKind() == ActorInstance || getKind() == GlobalActor); | ||
|
||
if (silParsed) | ||
return nullptr; | ||
|
||
Type actorType; | ||
|
||
if (auto *instance = actorInstance.dyn_cast<VarDecl *>()) { | ||
actorType = instance->getTypeInContext(); | ||
} else if (auto *instance = actorInstance.dyn_cast<Expr *>()) { | ||
actorType = instance->getType(); | ||
} | ||
|
||
if (actorType) { | ||
if (auto wrapped = actorType->getOptionalObjectType()) { | ||
actorType = wrapped; | ||
} | ||
return actorType | ||
->getReferenceStorageReferent()->getAnyActor(); | ||
if (getKind() == GlobalActor) { | ||
return getGlobalActor()->getAnyNominal(); | ||
} | ||
|
||
return actorInstance.get<NominalTypeDecl *>(); | ||
} | ||
|
||
NominalTypeDecl *ActorIsolation::getActorOrNullPtr() const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You added this one recently but it seems to be a copy paste of the other and it is not used so I removed it @gottesmm if we should keep it let me know. |
||
if (getKind() != ActorInstance || getKind() != GlobalActor) | ||
return nullptr; | ||
|
||
if (silParsed) | ||
return nullptr; | ||
|
||
Type actorType; | ||
|
||
if (auto *instance = actorInstance.dyn_cast<VarDecl *>()) { | ||
actorType = instance->getTypeInContext(); | ||
} else if (auto *instance = actorInstance.dyn_cast<Expr *>()) { | ||
actorType = instance->getType(); | ||
} else if (auto *expr = actorInstance.dyn_cast<Expr *>()) { | ||
actorType = expr->getType(); | ||
} | ||
|
||
if (actorType) { | ||
if (auto wrapped = actorType->getOptionalObjectType()) { | ||
actorType = wrapped; | ||
} | ||
return actorType->getReferenceStorageReferent()->getAnyActor(); | ||
return actorType | ||
->getReferenceStorageReferent()->getAnyActor(); | ||
} | ||
|
||
return actorInstance.get<NominalTypeDecl *>(); | ||
|
@@ -11785,7 +11767,10 @@ bool ActorIsolation::isDistributedActor() const { | |
if (silParsed) | ||
return false; | ||
|
||
return getKind() == ActorInstance && getActor()->isDistributedActor(); | ||
if (getKind() != ActorInstance) | ||
return false; | ||
|
||
return getActor()->isDistributedActor(); | ||
} | ||
|
||
bool ActorIsolation::isEqual(const ActorIsolation &lhs, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1823,6 +1823,54 @@ static bool wasLegacyEscapingUseRestriction(AbstractFunctionDecl *fn) { | |
return !(fn->hasAsync()); // basic case: not async = had restriction. | ||
} | ||
|
||
/// Note that while a direct access to the actor isolated property is not legal | ||
/// you may want to consider introducing an accessing method for a mutation. | ||
static void | ||
maybeNoteMutatingMethodSuggestion(ASTContext &C, | ||
ValueDecl const *member, | ||
SourceLoc memberLoc, | ||
DeclContext const *refCxt, | ||
ActorIsolation isolation, | ||
std::optional<VarRefUseEnv> useKind) { | ||
if (!member || !isa<VarDecl>(member)) | ||
return; // we only offer the note property mutations | ||
|
||
if (!(isolation.getKind() == ActorIsolation::Kind::ActorInstance || | ||
isolation.getKind() == ActorIsolation::Kind::GlobalActor)) { | ||
return; | ||
} | ||
|
||
if (useKind != VarRefUseEnv::Mutating) { | ||
// This note is tailored for the 'mutating' access, i.e. when | ||
// attempting to mutate a property, they should instead make an actor method to perform the mutation. Reading properties does not have the same restriction. | ||
return; | ||
} | ||
|
||
if (!refCxt->isAsyncContext()) { | ||
// don't suggest creating method when in sync context, as we won't be able | ||
// to invoke it anyway so this would not be helpful to suggest | ||
return; | ||
} | ||
|
||
if (auto actor = isolation.getActor()) { | ||
NominalTypeDecl *actorTy = | ||
actor; | ||
// (isolation.getKind() == swift::ActorIsolation::ActorInstance ? | ||
//) | ||
|
||
C.Diags.diagnose( | ||
memberLoc, | ||
diag::note_consider_method_for_isolated_property_mutation, | ||
actor); | ||
// } else if (isolation.getKind() == swift::ActorIsolation::GlobalActor) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was the commented out code here and above meant to be left in? |
||
// C.Diags.diagnose( | ||
// memberLoc, | ||
// diag::note_consider_method_for_global_actor_isolated_property_mutation, | ||
// isolation.getGlobalActor()); | ||
// } | ||
} | ||
} | ||
|
||
/// Note that the given actor member is isolated. | ||
static void noteIsolatedActorMember(ValueDecl const *decl, | ||
std::optional<VarRefUseEnv> useKind) { | ||
|
@@ -1944,20 +1992,23 @@ static bool memberAccessHasSpecialPermissionInSwift5( | |
} | ||
|
||
// Otherwise, it's definitely going to be illegal, so warn and permit. | ||
auto &diags = refCxt->getASTContext().Diags; | ||
auto &C = refCxt->getASTContext(); | ||
auto &diags = C.Diags; | ||
auto useKindInt = static_cast<unsigned>( | ||
useKind.value_or(VarRefUseEnv::Read)); | ||
|
||
auto isolation = getActorIsolation(const_cast<ValueDecl *>(member)); | ||
diags.diagnose( | ||
memberLoc, diag::actor_isolated_non_self_reference, | ||
member, | ||
useKindInt, | ||
baseActor.kind + 1, | ||
baseActor.globalActor, | ||
getActorIsolation(const_cast<ValueDecl *>(member))) | ||
isolation) | ||
.warnUntilSwiftVersion(6); | ||
|
||
noteIsolatedActorMember(member, useKind); | ||
maybeNoteMutatingMethodSuggestion(C, member, memberLoc, refCxt, isolation, useKind); | ||
return true; | ||
} | ||
|
||
|
@@ -4438,6 +4489,8 @@ namespace { | |
refKind + 1, refGlobalActor, | ||
result.isolation) | ||
.warnUntilSwiftVersionIf(preconcurrencyContext, 6); | ||
maybeNoteMutatingMethodSuggestion(ctx, decl, loc, getDeclContext(), result.isolation, | ||
kindOfUsage(decl, context).value_or(VarRefUseEnv::Read)); | ||
|
||
if (derivedConformanceType) { | ||
auto *decl = dyn_cast<ValueDecl>(getDeclContext()->getAsDecl()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ public struct Globals { | |
public static let integerConstant = 0 | ||
public static var integerMutable = 0 | ||
|
||
public static nonisolated(unsafe) let nonisolatedUnsafeIntegerConstant = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this caused an un-necessary warning we're not testing for; removed the warning |
||
public static let nonisolatedUnsafeIntegerConstant = 0 | ||
public static nonisolated(unsafe) var nonisolatedUnsafeIntegerMutable = 0 | ||
|
||
@MainActor public static var actorInteger = 0 | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ActorIsolation::getActor()
used to return garbage if it contained aGlobalActor
before this fix.We initialize the
globalActor
property but fall through to returning theactorInstance.get<NominalTypeDecl *>();
which is just some uninitialized memory for the global actor case.This is fixed now, we properly handle both kinds of isolations the method claimed to support.
Just FYI @hborla