Skip to content

Commit 163090d

Browse files
authored
Fix for async closure (pointfreeco#25)
* Fix action closures in async contexts. * more tests * utf8 * fix for implicit
1 parent 4224012 commit 163090d

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

Sources/Perception/PerceptionRegistrar.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ extension PerceptionRegistrar: Hashable {
234234
guard
235235
mangledSymbol.isMangledViewBodyGetter,
236236
let demangled = String(Substring(mangledSymbol)).demangled,
237+
!demangled.isSuspendingClosure,
237238
!demangled.isActionClosure
238239
else {
239240
continue
@@ -247,6 +248,24 @@ extension PerceptionRegistrar: Hashable {
247248
}
248249

249250
extension String {
251+
fileprivate var isSuspendingClosure: Bool {
252+
let fragment = self.utf8.drop(while: { $0 != .init(ascii: ")") }).dropFirst()
253+
return fragment.starts(
254+
with: " suspend resume partial function for closure".utf8
255+
)
256+
|| fragment.starts(
257+
with: " suspend resume partial function for implicit closure".utf8
258+
)
259+
|| fragment.starts(
260+
with: " await resume partial function for partial apply forwarder for closure".utf8
261+
)
262+
|| fragment.starts(
263+
with: " await resume partial function for partial apply forwarder for implicit closure".utf8
264+
)
265+
|| fragment.starts(
266+
with: " await resume partial function for implicit closure".utf8
267+
)
268+
}
250269
fileprivate var isActionClosure: Bool {
251270
var view = self[...].utf8
252271
guard

Tests/PerceptionTests/RuntimeWarningTests.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,55 @@
450450
self.render(FeatureView())
451451
}
452452

453+
func testAccessInOnAppearWithAsyncTask() async throws {
454+
@MainActor
455+
struct FeatureView: View {
456+
let model = Model()
457+
var body: some View {
458+
Text("Hi")
459+
.onAppear {
460+
Task { @MainActor in _ = model.count }
461+
}
462+
}
463+
}
464+
self.render(FeatureView())
465+
try await Task.sleep(for: .milliseconds(100))
466+
}
467+
468+
func testAccessInOnAppearWithAsyncTask_Implicit() async throws {
469+
@MainActor
470+
struct FeatureView: View {
471+
let model = Model()
472+
var body: some View {
473+
Text("Hi")
474+
.onAppear {
475+
Task(operation: self.perform)
476+
}
477+
}
478+
@Sendable
479+
func perform() async {
480+
_ = model.count
481+
}
482+
}
483+
self.render(FeatureView())
484+
try await Task.sleep(for: .milliseconds(100))
485+
}
486+
487+
func testAccessInTask() async throws {
488+
@MainActor
489+
struct FeatureView: View {
490+
let model = Model()
491+
var body: some View {
492+
Text("Hi")
493+
.task { @MainActor in
494+
_ = model.count
495+
}
496+
}
497+
}
498+
self.render(FeatureView())
499+
try await Task.sleep(for: .milliseconds(100))
500+
}
501+
453502
private func render(_ view: some View) {
454503
let image = ImageRenderer(content: view).cgImage
455504
_ = image

0 commit comments

Comments
 (0)