Skip to content

Commit 2f78ba8

Browse files
committed
Sema: Extend _unsafeInheritExecutor_ hack to Clock.measure().
Fixes the bug in `swift::introduceUnsafeInheritExecutorReplacements()` that prevented the hack from working with `Clock.measure()`. It isn't sufficient to just check whether the nominal for the type base of a qualified lookup belongs to the Concurrency module because that type may reference multiple types. Instead, check all of the directly referenced types to match the behavior of qualified lookup. Resolves rdar://132581483.
1 parent 97b249b commit 2f78ba8

File tree

3 files changed

+46
-13
lines changed

3 files changed

+46
-13
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,8 +2199,11 @@ void swift::introduceUnsafeInheritExecutorReplacements(
21992199
if (lookup.empty())
22002200
return;
22012201

2202-
auto baseNominal = base->getAnyNominal();
2203-
if (!baseNominal || !inConcurrencyModule(baseNominal))
2202+
SmallVector<NominalTypeDecl *, 4> nominalTypes;
2203+
namelookup::tryExtractDirectlyReferencedNominalTypes(base, nominalTypes);
2204+
if (llvm::none_of(nominalTypes, [](NominalTypeDecl *baseNominal) {
2205+
return inConcurrencyModule(baseNominal);
2206+
}))
22042207
return;
22052208

22062209
auto isReplaceable = [&](ValueDecl *decl) {

stdlib/public/Concurrency/Clock.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,22 @@ extension Clock {
7272
isolation: isolated (any Actor)? = #isolation,
7373
_ work: () async throws -> Void
7474
) async rethrows -> Instant.Duration {
75-
try await measure(work)
75+
let start = now
76+
try await work()
77+
let end = now
78+
return start.duration(to: end)
7679
}
7780

81+
// Note: hack to stage out @_unsafeInheritExecutor forms of various functions
82+
// in favor of #isolation. The _unsafeInheritExecutor_ prefix is meaningful
83+
// to the type checker.
84+
//
85+
// This function also doubles as an ABI-compatibility shim predating the
86+
// introduction of #isolation.
7887
@available(SwiftStdlib 5.7, *)
88+
@_silgen_name("$ss5ClockPsE7measurey8DurationQzyyYaKXEYaKF")
7989
@_unsafeInheritExecutor // for ABI compatibility
80-
@usableFromInline
81-
internal func measure(
90+
public func _unsafeInheritExecutor_measure(
8291
_ work: () async throws -> Void
8392
) async rethrows -> Instant.Duration {
8493
let start = now

test/Concurrency/unsafe_inherit_executor.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,10 @@ enum MyError: Error {
9292
case fail
9393
}
9494

95+
protocol P {}
96+
9597
@_unsafeInheritExecutor
96-
func unsafeCallerAvoidsNewLoop(clock: some Clock) async throws {
98+
func unsafeCallerAvoidsNewLoop() async throws {
9799
// expected-warning@-1{{@_unsafeInheritExecutor attribute is deprecated; consider an 'isolated' parameter defaulted to '#isolation' instead}}
98100

99101
_ = await withUnsafeContinuation { (continuation: UnsafeContinuation<Int, Never>) in
@@ -129,13 +131,6 @@ func unsafeCallerAvoidsNewLoop(clock: some Clock) async throws {
129131
func operation() async throws -> Int { 7 }
130132
try await TL.$string.withValue("hello", operation: operation)
131133

132-
// FIXME: Clock.measure does not currently support this hack.
133-
// expected-error@+1{{#isolation (introduced by a default argument) cannot be used within an '@_unsafeInheritExecutor' function}}
134-
_ = try! await clock.measure {
135-
print("so very slow")
136-
try await Task.sleep(nanoseconds: 500)
137-
}
138-
139134
_ = await withDiscardingTaskGroup(returning: Int.self) { group in
140135
group.addTask {
141136
print("hello")
@@ -173,6 +168,32 @@ func unsafeCallerAvoidsNewLoop(clock: some Clock) async throws {
173168
}
174169
}
175170

171+
@_unsafeInheritExecutor
172+
func unsafeClockCaller(
173+
specificClock: ContinuousClock,
174+
genericClock: some Clock,
175+
existentialClock: any Clock,
176+
existentialCompositionClock: any P & Clock,
177+
) async throws {
178+
// expected-warning@-6{{@_unsafeInheritExecutor attribute is deprecated; consider an 'isolated' parameter defaulted to '#isolation' instead}}
179+
180+
_ = try! await specificClock.measure {
181+
try await Task.sleep(nanoseconds: 500)
182+
}
183+
184+
_ = try! await genericClock.measure {
185+
try await Task.sleep(nanoseconds: 500)
186+
}
187+
188+
_ = try! await existentialClock.measure {
189+
try await Task.sleep(nanoseconds: 500)
190+
}
191+
192+
_ = try! await existentialCompositionClock.measure {
193+
try await Task.sleep(nanoseconds: 500)
194+
}
195+
}
196+
176197
@_unsafeInheritExecutor
177198
func _unsafeInheritExecutor_hacky() async { }
178199
// expected-warning@-1{{@_unsafeInheritExecutor attribute is deprecated; consider an 'isolated' parameter defaulted to '#isolation' instead}}

0 commit comments

Comments
 (0)