Skip to content

Commit 2928459

Browse files
authored
Merge pull request #40652 from kavon/defaultvalue-isolation
2 parents e5118fc + 51f8cd1 commit 2928459

File tree

7 files changed

+134
-12
lines changed

7 files changed

+134
-12
lines changed

lib/AST/Decl.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8743,10 +8743,23 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
87438743
if (auto *vd = dyn_cast_or_null<ValueDecl>(dc->getAsDecl()))
87448744
return getActorIsolation(vd);
87458745

8746+
// In the context of the initializing or default-value expression of a
8747+
// stored property, the isolation varies between global and type members:
8748+
// - For a static stored property, the isolation matches the VarDecl.
8749+
// - For a field of a nominal type, the expression is not isolated.
8750+
// Without this distinction, a nominal can have non-async initializers
8751+
// with various kinds of isolation, so an impossible constraint can be
8752+
// created. See SE-0327 for details.
87468753
if (auto *init = dyn_cast<PatternBindingInitializer>(dc)) {
8747-
if (auto *var = init->getBinding()->getAnchoringVarDecl(
8748-
init->getBindingIndex()))
8754+
if (auto *var =
8755+
init->getBinding()->getAnchoringVarDecl(init->getBindingIndex())) {
8756+
8757+
if (var->isInstanceMember() &&
8758+
!var->getAttrs().hasAttribute<LazyAttr>())
8759+
return ActorIsolation::forUnspecified();
8760+
87498761
return getActorIsolation(var);
8762+
}
87508763
}
87518764

87528765
if (auto *closure = dyn_cast<AbstractClosureExpr>(dc)) {

lib/SILGen/SILGenFunction.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
704704
/// Generate an ObjC-compatible destructor (-dealloc).
705705
void emitObjCDestructor(SILDeclRef dtor);
706706

707-
ManagedValue emitGlobalVariableRef(SILLocation loc, VarDecl *var);
707+
/// Generate code to obtain the address of the given global variable.
708+
ManagedValue emitGlobalVariableRef(SILLocation loc, VarDecl *var,
709+
Optional<ActorIsolation> actorIso);
708710

709711
/// Generate a lazy global initializer.
710712
void emitLazyGlobalInitializer(PatternBindingDecl *binding,

lib/SILGen/SILGenGlobalVariable.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "SILGenFunction.h"
14+
#include "ExecutorBreadcrumb.h"
1415
#include "ManagedValue.h"
1516
#include "Scope.h"
1617
#include "swift/AST/ASTMangler.h"
@@ -66,7 +67,8 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl,
6667
}
6768

6869
ManagedValue
69-
SILGenFunction::emitGlobalVariableRef(SILLocation loc, VarDecl *var) {
70+
SILGenFunction::emitGlobalVariableRef(SILLocation loc, VarDecl *var,
71+
Optional<ActorIsolation> actorIso) {
7072
assert(!VarLocs.count(var));
7173

7274
if (var->isLazilyInitializedGlobal()) {
@@ -75,7 +77,21 @@ SILGenFunction::emitGlobalVariableRef(SILLocation loc, VarDecl *var) {
7577
SILDeclRef(var, SILDeclRef::Kind::GlobalAccessor),
7678
NotForDefinition);
7779
SILValue accessor = B.createFunctionRefFor(loc, accessorFn);
80+
81+
// The accessor to obtain a global's address may need to initialize the
82+
// variable first. So, we must call this accessor with the same
83+
// isolation that the variable itself requires during access.
84+
ExecutorBreadcrumb prevExecutor = emitHopToTargetActor(loc, actorIso,
85+
/*base=*/None);
86+
7887
SILValue addr = B.createApply(loc, accessor, SubstitutionMap(), {});
88+
89+
// FIXME: often right after this, we will again hop to the actor to
90+
// read from this address. it would be better to merge these two hops
91+
// pairs of hops together. Alternatively, teaching optimizations to
92+
// expand the scope of two nearly-adjacent pairs would be good.
93+
prevExecutor.emit(*this, loc); // hop back after call.
94+
7995
// FIXME: It'd be nice if the result of the accessor was natively an
8096
// address.
8197
addr = B.createPointerToAddress(

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2813,7 +2813,7 @@ void LValue::addNonMemberVarComponent(SILGenFunction &SGF, SILLocation loc,
28132813

28142814
// The only other case that should get here is a global variable.
28152815
if (!address) {
2816-
address = SGF.emitGlobalVariableRef(Loc, Storage);
2816+
address = SGF.emitGlobalVariableRef(Loc, Storage, ActorIso);
28172817
} else {
28182818
assert(!ActorIso && "local var should not be actor isolated!");
28192819
}

test/Concurrency/Runtime/mainactor.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ actor A {
6868
return await enterMainActor(0) + 1
6969
}
7070

71+
@MainActor func mainActorFn() -> Int {
72+
checkIfMainQueue(expectedAnswer: true)
73+
return 10
74+
}
75+
76+
@MainActor
77+
struct S {
78+
static var bacteria: Int = mainActorFn()
79+
}
80+
81+
@MainActor
82+
class C {
83+
static var bacteria: Int = mainActorFn()
84+
lazy var amoeba: Int = mainActorFn()
85+
nonisolated init() {}
86+
}
7187

7288
// CHECK: starting
7389
// CHECK-NOT: ERROR
@@ -115,5 +131,15 @@ actor A {
115131
}
116132
}
117133
_ = await task.value
134+
135+
// Check that initializers for stored properties are on the right actor
136+
let t1 = Task.detached { () -> Int in
137+
let c = C()
138+
return await c.amoeba
139+
}
140+
let t2 = Task.detached { () -> Int in
141+
return await S.bacteria + C.bacteria
142+
}
143+
_ = await t1.value + t2.value
118144
}
119145
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -warn-concurrency
2+
// REQUIRES: concurrency
3+
4+
5+
@MainActor
6+
func mainActorFn() -> Int { return 0 } // expected-note 2 {{calls to global function 'mainActorFn()' from outside of its actor context are implicitly asynchronous}}
7+
8+
@MainActor
9+
class C {
10+
var x: Int = mainActorFn() // expected-error {{call to main actor-isolated global function 'mainActorFn()' in a synchronous nonisolated context}}
11+
12+
lazy var y: Int = mainActorFn()
13+
14+
static var z: Int = mainActorFn()
15+
}
16+
17+
@MainActor
18+
var x: Int = mainActorFn() // expected-error {{call to main actor-isolated global function 'mainActorFn()' in a synchronous nonisolated context}}

test/SILGen/hop_to_executor_async_prop.swift

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,10 @@ struct Container {
488488
}
489489

490490
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV12accessTuple3SfyYaF : $@convention(method) @async (@guaranteed Container) -> Float {
491+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV12staticCircleSi_SitSg_Sftvau : $@convention(thin) () -> Builtin.RawPointer
492+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
493+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
494+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
491495
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
492496
// CHECK: [[ACCESS:%[0-9]+]] = begin_access [read] [dynamic] {{%[0-9]+}} : $*(Optional<(Int, Int)>, Float)
493497
// CHECK: [[ADDR:%[0-9]+]] = tuple_element_addr [[ACCESS]] : $*(Optional<(Int, Int)>, Float), 1
@@ -500,6 +504,10 @@ struct Container {
500504
}
501505

502506
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV12accessTuple4SiSgyYaFZ : $@convention(method) @async (@thin Container.Type) -> Optional<Int> {
507+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV12staticCircleSi_SitSg_Sftvau : $@convention(thin) () -> Builtin.RawPointer
508+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
509+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
510+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
503511
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
504512
// CHECK: [[ACCESS:%[0-9]+]] = begin_access [read] [dynamic] {{%[0-9]+}} : $*(Optional<(Int, Int)>, Float)
505513
// CHECK: [[ADDR:%[0-9]+]] = tuple_element_addr [[ACCESS]] : $*(Optional<(Int, Int)>, Float), 0
@@ -522,6 +530,10 @@ struct Container {
522530

523531

524532
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV8getCountSiyYaFZ : $@convention(method) @async (@thin Container.Type) -> Int {
533+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV7counterSivau : $@convention(thin) () -> Builtin.RawPointer
534+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
535+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
536+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
525537
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
526538
// CHECK: {{%[0-9]+}} = begin_access [read] [dynamic] {{%[0-9]+}} : $*Int
527539
// CHECK: {{%[0-9]+}} = load [trivial] {{%[0-9]+}} : $*Int
@@ -534,6 +546,10 @@ struct Container {
534546

535547
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV8getValueSiSgyYaFZ : $@convention(method) @async (@thin Container.Type) -> Optional<Int> {
536548
// CHECK: bb0(%0 : $@thin Container.Type):
549+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV4thisACSgvau : $@convention(thin) () -> Builtin.RawPointer
550+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
551+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
552+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
537553
// CHECK: [[MAIN:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MainActor
538554
// CHECK: [[PREV:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
539555
// CHECK: hop_to_executor [[MAIN]] : $MainActor
@@ -556,19 +572,23 @@ struct Container {
556572

557573
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV10getOrCrashSfyYaFZ : $@convention(method) @async (@thin Container.Type) -> Float {
558574
// CHECK: bb0({{%[0-9]+}} : $@thin Container.Type):
575+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV4thisACSgvau : $@convention(thin) () -> Builtin.RawPointer
576+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
577+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
578+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
559579
// CHECK: [[MAIN:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MainActor
560580
// CHECK: [[PREV:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
561581
// CHECK: hop_to_executor [[MAIN]] : $MainActor
562582
// CHECK: [[ACCESS:%[0-9]+]] = begin_access [read] [dynamic] {{%[0-9]+}} : $*Optional<Container>
563-
// CHECK: switch_enum_addr %11 : $*Optional<Container>, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[CRASH_BB:bb[0-9]+]]
583+
// CHECK: switch_enum_addr [[ACCESS]] : $*Optional<Container>, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[CRASH_BB:bb[0-9]+]]
564584
//
565585
// CHECK: [[CRASH_BB]]:
566586
// CHECK-NOT: hop_to_executor {{%[0-9]+}}
567587
// CHECK: unreachable
568588
//
569589
// CHECK: [[SOME_BB]]:
570-
// CHECK: [[DATA_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr %11 : $*Optional<Container>, #Optional.some!enumelt
571-
// CHECK: [[ELEM_ADDR:%[0-9]+]] = struct_element_addr %22 : $*Container, #Container.iso
590+
// CHECK: [[DATA_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[ACCESS]] : $*Optional<Container>, #Optional.some!enumelt
591+
// CHECK: [[ELEM_ADDR:%[0-9]+]] = struct_element_addr [[DATA_ADDR]] : $*Container, #Container.iso
572592
// CHECK: [[PREV_AGAIN:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
573593
// CHECK: hop_to_executor {{%[0-9]+}} : $Cat
574594
// CHECK: {{%[0-9]+}} = load [trivial] [[ELEM_ADDR]] : $*Float
@@ -581,19 +601,22 @@ struct Container {
581601

582602
// CHECK-LABEL: sil hidden [ossa] @$s4test9ContainerV13getRefOrCrashAA6CatBoxCyYaFZ : $@convention(method) @async (@thin Container.Type) -> @owned CatBox {
583603
// CHECK: bb0({{%[0-9]+}} : $@thin Container.Type):
604+
// CHECK: [[ADDRESS_ACCESSOR:%[0-9]+]] = function_ref @$s4test9ContainerV4thisACSgvau : $@convention(thin) () -> Builtin.RawPointer
605+
// CHECK: hop_to_executor {{%[0-9]+}} : $MainActor
606+
// CHECK: = apply [[ADDRESS_ACCESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
607+
// CHECK: hop_to_executor {{%[0-9]+}} : $Optional<Builtin.Executor>
584608
// CHECK: [[MAIN:%[0-9]+]] = begin_borrow {{%[0-9]+}} : $MainActor
585609
// CHECK: [[PREV:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
586610
// CHECK: hop_to_executor [[MAIN]] : $MainActor
587611
// CHECK: [[ACCESS:%[0-9]+]] = begin_access [read] [dynamic] {{%[0-9]+}} : $*Optional<Container>
588-
// CHECK: switch_enum_addr %11 : $*Optional<Container>, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[CRASH_BB:bb[0-9]+]]
612+
// CHECK: switch_enum_addr [[ACCESS]] : $*Optional<Container>, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[CRASH_BB:bb[0-9]+]]
589613
//
590614
// CHECK: [[CRASH_BB]]:
591-
// CHECK-NOT: hop_to_executor {{%[0-9]+}}
592615
// CHECK: unreachable
593616
//
594617
// CHECK: [[SOME_BB]]:
595-
// CHECK: [[DATA_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr %11 : $*Optional<Container>, #Optional.some!enumelt
596-
// CHECK: [[ELEM_ADDR:%[0-9]+]] = struct_element_addr %22 : $*Container, #Container.iso
618+
// CHECK: [[DATA_ADDR:%[0-9]+]] = unchecked_take_enum_data_addr [[ACCESS]] : $*Optional<Container>, #Optional.some!enumelt
619+
// CHECK: [[ELEM_ADDR:%[0-9]+]] = struct_element_addr [[DATA_ADDR]] : $*Container, #Container.iso
597620
// CHECK: [[PREV_AGAIN:%[0-9]+]] = builtin "getCurrentExecutor"() : $Optional<Builtin.Executor>
598621
// CHECK: hop_to_executor {{%[0-9]+}} : $Cat
599622
// CHECK: {{%[0-9]+}} = load [copy] [[ELEM_ADDR]] : $*CatBox
@@ -644,3 +667,27 @@ struct Blah {
644667
}
645668
}
646669
}
670+
671+
@MainActor
672+
func getTemperature() -> Int { return 0 }
673+
674+
@MainActor
675+
class Polar {
676+
static var temperature: Int = getTemperature()
677+
}
678+
679+
680+
// CHECK-LABEL: sil hidden{{.*}} @$s4test20accessStaticIsolatedSiyYaF : $@convention(thin) @async () -> Int {
681+
// CHECK: [[ADDRESSOR:%[0-9]+]] = function_ref @$s4test5PolarC11temperatureSivau : $@convention(thin) () -> Builtin.RawPointer
682+
// CHECK: hop_to_executor {{%.*}} : $MainActor
683+
// CHECK-NEXT: [[RAW_ADDR:%[0-9]+]] = apply [[ADDRESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
684+
// CHECK-NEXT: hop_to_executor {{%.*}} : $Optional<Builtin.Executor>
685+
// CHECK: [[ADDR:%[0-9]+]] = pointer_to_address [[RAW_ADDR]] : $Builtin.RawPointer to [strict] $*Int
686+
// CHECK: hop_to_executor {{%.*}} : $MainActor
687+
// CHECK: {{%.*}} = load [trivial] {{%.*}} : $*Int
688+
// CHECK: hop_to_executor {{%.*}} : $Optional<Builtin.Executor>
689+
func accessStaticIsolated() async -> Int {
690+
return await Polar.temperature
691+
}
692+
693+

0 commit comments

Comments
 (0)