Skip to content

Commit 3b807a4

Browse files
committed
[Concurrency] Handle substitutions into generic global actors.
1 parent 9c983a4 commit 3b807a4

File tree

4 files changed

+82
-17
lines changed

4 files changed

+82
-17
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,10 @@ GlobalActorAttributeRequest::evaluate(
403403
}
404404

405405
/// Determine the isolation rules for a given declaration.
406-
ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(Decl *decl) {
406+
ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(
407+
ConcreteDeclRef declRef) {
408+
auto decl = declRef.getDecl();
409+
407410
switch (decl->getKind()) {
408411
case DeclKind::AssociatedType:
409412
case DeclKind::Class:
@@ -471,8 +474,13 @@ ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(Decl *decl)
471474
// Protected actor instance members can only be accessed on 'self'.
472475
return forActorSelf(isolation.getActor());
473476

474-
case ActorIsolation::GlobalActor:
475-
return forGlobalActor(isolation.getGlobalActor());
477+
case ActorIsolation::GlobalActor: {
478+
Type actorType = isolation.getGlobalActor();
479+
if (auto subs = declRef.getSubstitutions())
480+
actorType = actorType.subst(subs);
481+
482+
return forGlobalActor(actorType);
483+
}
476484

477485
case ActorIsolation::Independent:
478486
// Actor-independent have no restrictions on their access.
@@ -520,14 +528,13 @@ static Optional<PartialApplyThunkInfo> decomposePartialApplyThunk(
520528
}
521529

522530
/// Find the immediate member reference in the given expression.
523-
static Optional<std::pair<ValueDecl *, SourceLoc>>
531+
static Optional<std::pair<ConcreteDeclRef, SourceLoc>>
524532
findMemberReference(Expr *expr) {
525533
if (auto declRef = dyn_cast<DeclRefExpr>(expr))
526-
return std::make_pair(declRef->getDecl(), declRef->getLoc());
534+
return std::make_pair(declRef->getDeclRef(), declRef->getLoc());
527535

528536
if (auto otherCtor = dyn_cast<OtherConstructorDeclRefExpr>(expr)) {
529-
return std::make_pair(
530-
static_cast<ValueDecl *>(otherCtor->getDecl()), otherCtor->getLoc());
537+
return std::make_pair(otherCtor->getDeclRef(), otherCtor->getLoc());
531538
}
532539

533540
return None;
@@ -562,13 +569,13 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
562569
}
563570

564571
if (auto lookup = dyn_cast<LookupExpr>(expr)) {
565-
checkMemberReference(lookup->getBase(), lookup->getMember().getDecl(),
572+
checkMemberReference(lookup->getBase(), lookup->getMember(),
566573
lookup->getLoc());
567574
return { true, expr };
568575
}
569576

570577
if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
571-
checkNonMemberReference(declRef->getDecl(), declRef->getLoc());
578+
checkNonMemberReference(declRef->getDeclRef(), declRef->getLoc());
572579
return { true, expr };
573580
}
574581

@@ -726,6 +733,22 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
726733

727734
/// Get the actor isolation of the innermost relevant context.
728735
ActorIsolation getInnermostIsolatedContext(const DeclContext *constDC) {
736+
// Retrieve the actor isolation for a declaration somewhere in our
737+
// declaration context chain and map it into our own context so that
738+
// the types can be compared.
739+
auto getActorIsolation = [constDC](ValueDecl *value) {
740+
switch (auto isolation = swift::getActorIsolation(value)) {
741+
case ActorIsolation::ActorInstance:
742+
case ActorIsolation::Independent:
743+
case ActorIsolation::Unspecified:
744+
return isolation;
745+
746+
case ActorIsolation::GlobalActor:
747+
return ActorIsolation::forGlobalActor(
748+
constDC->mapTypeIntoContext(isolation.getGlobalActor()));
749+
}
750+
};
751+
729752
auto dc = const_cast<DeclContext *>(constDC);
730753
while (!dc->isModuleScopeContext()) {
731754
// Look through non-escaping closures.
@@ -778,7 +801,7 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
778801
noteIsolatedActorMember(value);
779802
return true;
780803

781-
case ActorIsolation::GlobalActor:
804+
case ActorIsolation::GlobalActor: {
782805
// If the global actor types are the same, we're done.
783806
if (contextIsolation.getGlobalActor()->isEqual(globalActor))
784807
return false;
@@ -789,6 +812,7 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
789812
contextIsolation.getGlobalActor());
790813
noteIsolatedActorMember(value);
791814
return true;
815+
}
792816

793817
case ActorIsolation::Independent:
794818
ctx.Diags.diagnose(
@@ -804,11 +828,13 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
804828
}
805829

806830
/// Check a reference to a local or global.
807-
bool checkNonMemberReference(ValueDecl *value, SourceLoc loc) {
808-
if (!value)
831+
bool checkNonMemberReference(ConcreteDeclRef valueRef, SourceLoc loc) {
832+
if (!valueRef)
809833
return false;
810834

811-
switch (auto isolation = ActorIsolationRestriction::forDeclaration(value)) {
835+
auto value = valueRef.getDecl();
836+
switch (auto isolation =
837+
ActorIsolationRestriction::forDeclaration(valueRef)) {
812838
case ActorIsolationRestriction::Unrestricted:
813839
return false;
814840

@@ -846,12 +872,14 @@ void swift::checkActorIsolation(const Expr *expr, const DeclContext *dc) {
846872

847873
/// Check a reference with the given base expression to the given member.
848874
bool checkMemberReference(
849-
Expr *base, ValueDecl *member, SourceLoc memberLoc,
875+
Expr *base, ConcreteDeclRef memberRef, SourceLoc memberLoc,
850876
bool isEscapingPartialApply = false) {
851-
if (!base || !member)
877+
if (!base || !memberRef)
852878
return false;
853879

854-
switch (auto isolation = ActorIsolationRestriction::forDeclaration(member)) {
880+
auto member = memberRef.getDecl();
881+
switch (auto isolation =
882+
ActorIsolationRestriction::forDeclaration(memberRef)) {
855883
case ActorIsolationRestriction::Unrestricted:
856884
return false;
857885

lib/Sema/TypeCheckConcurrency.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace swift {
2525
class ActorIsolation;
2626
class ASTContext;
2727
class ClassDecl;
28+
class ConcreteDeclRef;
2829
class Decl;
2930
class DeclContext;
3031
class Expr;
@@ -138,7 +139,7 @@ class ActorIsolationRestriction {
138139
}
139140

140141
/// Determine the isolation rules for a given declaration.
141-
static ActorIsolationRestriction forDeclaration(Decl *decl);
142+
static ActorIsolationRestriction forDeclaration(ConcreteDeclRef declRef);
142143

143144
operator Kind() const { return kind; };
144145
};

test/Concurrency/actor_isolation.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ struct SomeOtherGlobalActor {
192192
static let shared = SomeActor()
193193
}
194194

195+
@globalActor
196+
struct GenericGlobalActor<T> {
197+
static var shared: SomeActor { SomeActor() }
198+
}
199+
195200
@SomeGlobalActor func syncGlobalActorFunc() { } // expected-note 3{{only asynchronous methods can be used outside the actor instance; do you want to add 'async'?}}
196201
@SomeGlobalActor func asyncGlobalActorFunc() async { }
197202

@@ -239,6 +244,27 @@ extension MyActor {
239244
}
240245
}
241246

247+
struct GenericStruct<T> {
248+
@GenericGlobalActor<T> func f() { } // expected-note{{only asynchronous methods can be used outside the actor instance; do you want to add 'async'?}}
249+
250+
@GenericGlobalActor<T> func g() {
251+
f() // okay
252+
}
253+
254+
@GenericGlobalActor<String> func h() {
255+
f() // expected-error{{instance method 'f()' isolated to global actor 'GenericGlobalActor<T>' can not be referenced from different global actor 'GenericGlobalActor<String>'}}
256+
}
257+
}
258+
259+
extension GenericStruct where T == String {
260+
@GenericGlobalActor<T>
261+
func h2() {
262+
f()
263+
g()
264+
h()
265+
}
266+
}
267+
242268

243269
// ----------------------------------------------------------------------
244270
// Non-actor code isolation restrictions

test/attr/global_actor.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ struct GA1 {
1515
static let shared = SomeActor()
1616
}
1717

18+
@globalActor
19+
struct GenericGlobalActor<T> {
20+
static var shared: SomeActor { SomeActor() }
21+
}
22+
1823
// Ill-formed global actors.
1924
@globalActor
2025
open class GA2 { // expected-error{{global actor 'GA2' requires a static property 'shared' that produces an actor instance}}{{17-17=\n public static let shared = <#actor instance#>}}
@@ -82,6 +87,11 @@ class SomeClass {
8287

8388
@GA1 @OtherGlobalActor func twoGlobalActors() { } // expected-error{{declaration can not have multiple global actor attributes ('OtherGlobalActor' and 'GA1')}}
8489

90+
struct Container {
91+
// FIXME: Diagnostic could be improved to show the generic arguments.
92+
@GenericGlobalActor<Int> @GenericGlobalActor<String> func twoGenericGlobalActors() { } // expected-error{{declaration can not have multiple global actor attributes ('GenericGlobalActor' and 'GenericGlobalActor')}}
93+
}
94+
8595
// -----------------------------------------------------------------------
8696
// Redundant attributes
8797
// -----------------------------------------------------------------------

0 commit comments

Comments
 (0)