Skip to content

Commit c085cb7

Browse files
authored
Merge pull request #83405 from gottesmm/pr-fc0af1c444a7961af452c813a9bdc4cc2b5adbd8
[concurrency] Emit nonisolated(nonsending) async throw initializers correctly
2 parents 7a9b77d + 4614854 commit c085cb7

File tree

6 files changed

+373
-74
lines changed

6 files changed

+373
-74
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,10 @@ class SILFunction
14631463
return actorIsolation;
14641464
}
14651465

1466+
bool isNonisolatedNonsending() const {
1467+
return actorIsolation && actorIsolation->isCallerIsolationInheriting();
1468+
}
1469+
14661470
/// Return the source file that this SILFunction belongs to if it exists.
14671471
SourceFile *getSourceFile() const;
14681472

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5857,8 +5857,7 @@ ApplyOptions CallEmission::emitArgumentsForNormalApply(
58575857
// Now, actually handle the implicit parameters.
58585858
if (auto isolated = substFnType->maybeGetIsolatedParameter();
58595859
isolated && isolated->hasOption(SILParameterInfo::ImplicitLeading)) {
5860-
auto executor =
5861-
ManagedValue::forBorrowedObjectRValue(SGF.ExpectedExecutor.getEager());
5860+
auto executor = SGF.emitExpectedExecutor(callSite->Loc);
58625861
args.push_back({});
58635862
// NOTE: Even though this calls emitActorInstanceIsolation, this also
58645863
// handles glboal actor isolated cases.

lib/SILGen/SILGenConstructor.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,15 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
947947
args.push_back(arg);
948948
}
949949

950+
if (F.isNonisolatedNonsending()) {
951+
auto paramTy = F.mapTypeIntoContext(
952+
SILType::getOpaqueIsolationType(F.getASTContext()));
953+
auto inContextParamTy = F.getLoweredType(paramTy.getASTType())
954+
.getCategoryType(paramTy.getCategory());
955+
SILArgument *arg = F.begin()->createFunctionArgument(inContextParamTy);
956+
args.push_back(arg);
957+
}
958+
950959
bindParametersForForwarding(ctor->getParameters(), args);
951960

952961
if (ctor->requiresUnavailableDeclABICompatibilityStubs())
@@ -1002,6 +1011,12 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
10021011
}
10031012
args.push_back(selfValue);
10041013

1014+
// For now, just do this if we have a nonisolated(nonsending) function so we
1015+
// do not change the semantics of non-nonisolated(nonsending) functions.
1016+
if (F.isNonisolatedNonsending()) {
1017+
emitExpectedExecutorProlog();
1018+
}
1019+
10051020
// Call the initializer. Always use the Swift entry point, which will be a
10061021
// bridging thunk if we're calling ObjC.
10071022
auto initConstant = SILDeclRef(ctor, SILDeclRef::Kind::Initializer);

lib/SILGen/SILGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,10 +742,17 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
742742
assert(Value != invalid() && Value != unnecessary());
743743
return Value != lazy();
744744
}
745+
746+
/// WARNING: Please do not call this unless you are completely sure that one
747+
/// will always have an eager executor (i.e.: you are not emitting for an
748+
/// initializer and more cases). To be safe please use
749+
/// SILGenFunction::emitExpectedExecutor instead which handles the lazy case
750+
/// correctly.
745751
SILValue getEager() const {
746752
assert(isEager());
747753
return Value;
748754
}
755+
749756
void set(SILValue value) {
750757
assert(Value == invalid());
751758
assert(value != nullptr);
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// RUN: %target-swift-frontend -enable-experimental-concurrency -target %target-swift-5.1-abi-triple -emit-silgen -o - -strict-concurrency=complete -enable-upcoming-feature NonisolatedNonsendingByDefault %s | %FileCheck --implicit-check-not=hop_to_executor %s
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault
5+
6+
// This file contains tests specifically for async initializers that do not
7+
// include type checker errors so we can test the SIL part of the pipeline. Put type checker errors into
8+
// async_initializer.swift.
9+
10+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer1fyyYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> () {
11+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>):
12+
// CHECK: hop_to_executor [[ACTOR]]
13+
// CHECK: } // end sil function '$s11initializer1fyyYaF'
14+
func f() async {}
15+
func g() {}
16+
17+
class Fruit {
18+
// Fruit.__allocating_init()
19+
// Isolation: caller_isolation_inheriting
20+
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s11initializer5FruitCACyYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thick Fruit.Type) -> @owned Fruit {
21+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>
22+
// CHECK: hop_to_executor [[ACTOR]]
23+
// CHECK: } // end sil function '$s11initializer5FruitCACyYacfC'
24+
25+
// Fruit.init()
26+
// Isolation: caller_isolation_inheriting
27+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer5FruitCACyYacfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @owned Fruit) -> @owned Fruit {
28+
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional<any Actor>,
29+
// CHECK: hop_to_executor [[ARG]]
30+
// CHECK: } // end sil function '$s11initializer5FruitCACyYacfc'
31+
init() async {}
32+
33+
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s11initializer5FruitC4nameACSS_tcfC : $@convention(method) (@owned String, @thick Fruit.Type) -> @owned Fruit {
34+
// CHECK: } // end sil function '$s11initializer5FruitC4nameACSS_tcfC'
35+
36+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer5FruitC4nameACSS_tcfc : $@convention(method) (@owned String, @owned Fruit) -> @owned Fruit {
37+
// CHECK: } // end sil function '$s11initializer5FruitC4nameACSS_tcfc'
38+
init(name: String) {}
39+
}
40+
41+
class Banana: Fruit {
42+
// TODO: Make this not async. We currently miscompile if this is sync.
43+
//
44+
// class Fruit {
45+
// required init() async {}
46+
// init(name: String) {}
47+
// }
48+
//
49+
// class Banana: Fruit {
50+
// override required init() {
51+
// super.init(name: "banana")
52+
// }
53+
// }
54+
//
55+
// func test(_ x: Fruit.Type) async {
56+
// await print(x.init())
57+
// }
58+
//
59+
// await test(Banana.self)
60+
61+
// Banana.__allocating_init()
62+
// Isolation: caller_isolation_inheriting
63+
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s11initializer6BananaCACyYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thick Banana.Type) -> @owned Banana {
64+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
65+
// CHECK: hop_to_executor [[ACTOR]]
66+
// CHECK: } // end sil function '$s11initializer6BananaCACyYacfC'
67+
68+
// Banana.init()
69+
// Isolation: caller_isolation_inheriting
70+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer6BananaCACyYacfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @owned Banana) -> @owned Banana {
71+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
72+
// CHECK: hop_to_executor [[ACTOR]]
73+
// CHECK: } // end sil function '$s11initializer6BananaCACyYacfc'
74+
override init() async {
75+
super.init(name: "banana")
76+
}
77+
}
78+
79+
class MyType {
80+
// MyType.__allocating_init(_:)
81+
// Isolation: caller_isolation_inheriting
82+
//
83+
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s11initializer6MyTypeCyACyyYaYCXEYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> (), @thick MyType.Type) -> @owned MyType {
84+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>, [[ARG:%.*]] : @guaranteed $@noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> ()
85+
// CHECK: hop_to_executor [[ACTOR]]
86+
// CHECK: [[FUNC:%.*]] = function_ref @$s11initializer6MyTypeCyACyyYaYCXEYacfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> (), @owned MyType) -> @owned MyType
87+
// CHECK: apply [[FUNC]]([[ACTOR]], [[ARG]], {{%.*}}) :
88+
// CHECK: } // end sil function '$s11initializer6MyTypeCyACyyYaYCXEYacfC'
89+
90+
// MyType.init(_:)
91+
// Isolation: caller_isolation_inheriting
92+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer6MyTypeCyACyyYaYCXEYacfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> (), @owned MyType) -> @owned MyType {
93+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>, [[ARG:%.*]] : @guaranteed $@noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> (), [[SELF:%.*]] : @owned $MyType):
94+
// CHECK: hop_to_executor [[ACTOR]]
95+
// CHECK: [[ARG_C:%.*]] = copy_value [[ARG]]
96+
// CHECK: [[ARG_B:%.*]] = begin_borrow [[ARG_C]]
97+
// CHECK: apply [[ARG_B]]([[ACTOR]])
98+
// CHECK: hop_to_executor [[ACTOR]]
99+
// CHECK: } // end sil function '$s11initializer6MyTypeCyACyyYaYCXEYacfc'
100+
init(_ f: () async -> Void) reasync {
101+
await f()
102+
}
103+
}
104+
105+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer4beepyyYaF : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> () {
106+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>):
107+
// CHECK: hop_to_executor [[ACTOR]]
108+
// CHECK: [[FUNC:%.*]] = function_ref @$s11initializer6MyTypeCyACyyYaYCXEYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>) -> (), @thick MyType.Type) -> @owned MyType
109+
// CHECK: apply [[FUNC]]([[ACTOR]], {{%.*}}, {{%.*}})
110+
// CHECK: hop_to_executor [[ACTOR]]
111+
// CHECK: hop_to_executor [[ACTOR]]
112+
// CHECK: } // end sil function '$s11initializer4beepyyYaF'
113+
func beep() async {
114+
let _ = await MyType(f)
115+
let _ = MyType(g)
116+
}
117+
118+
// thunk for @escaping @callee_guaranteed () -> ()
119+
// CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$sIeg_ScA_pSgIegHgIL_TR : $@convention(thin) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @guaranteed @callee_guaranteed () -> ()) -> () {
120+
// CHECK: hop_to_executor
121+
// CHECK: } // end sil function '$sIeg_ScA_pSgIegHgIL_TR'
122+
123+
actor A {
124+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A {
125+
// CHECK: hop_to_executor
126+
// CHECK: hop_to_executor
127+
// CHECK: } // end sil function '$s11initializer1ACACyYacfc'
128+
init() async {
129+
await f()
130+
}
131+
132+
init() {
133+
}
134+
}
135+
136+
protocol AsyncDefaultConstructable {
137+
init() async
138+
}
139+
140+
struct Location {
141+
var x : Int
142+
var y : Int
143+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer8LocationVACyYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thin Location.Type) -> Location {
144+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
145+
// CHECK: hop_to_executor [[ACTOR]]
146+
// CHECK: } // end sil function '$s11initializer8LocationVACyYacfC'
147+
init() async {
148+
self.x = 0
149+
self.y = 0
150+
}
151+
}
152+
153+
extension Location: AsyncDefaultConstructable {}
154+
155+
// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s11initializer8LocationVAA25AsyncDefaultConstructableA2aDPxyYacfCTW : $@convention(witness_method: AsyncDefaultConstructable) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thick Location.Type) -> @out Location {
156+
// CHECK: bb0([[INDIRECT_RESULT:%.*]] : $*Location, [[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
157+
// CHECK: [[FUNC:%.*]] = function_ref @$s11initializer8LocationVACyYacfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thin Location.Type) -> Location
158+
// CHECK: apply [[FUNC]]([[ACTOR]],
159+
// CHECK: hop_to_executor [[ACTOR]]
160+
// CHECK: } // end sil function '$s11initializer8LocationVAA25AsyncDefaultConstructableA2aDPxyYacfCTW'
161+
162+
// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s11initializer12ExplicitTestCACyYaKcfC : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @thick ExplicitTest.Type) -> (@owned ExplicitTest, @error any Error) {
163+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
164+
// CHECK: hop_to_executor [[ACTOR]]
165+
// CHECK: [[FUNC:%.*]] = function_ref @$s11initializer12ExplicitTestCACyYaKcfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @owned ExplicitTest) -> (@owned ExplicitTest, @error any Error)
166+
// CHECK: try_apply [[FUNC]]([[ACTOR]], {{%.*}})
167+
// CHECK: } // end sil function '$s11initializer12ExplicitTestCACyYaKcfC'
168+
169+
// CHECK-LABEL: sil hidden [ossa] @$s11initializer12ExplicitTestCACyYaKcfc : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Optional<any Actor>, @owned ExplicitTest) -> (@owned ExplicitTest, @error any Error) {
170+
// CHECK: bb0([[ACTOR:%.*]] : @guaranteed $Optional<any Actor>,
171+
// CHECK: hop_to_executor [[ACTOR]]
172+
// CHECK: } // end sil function '$s11initializer12ExplicitTestCACyYaKcfc'
173+
class ExplicitTest {
174+
nonisolated(nonsending) init() async throws {
175+
}
176+
}

0 commit comments

Comments
 (0)