Skip to content

Commit

Permalink
Fix for async closure (#25)
Browse files Browse the repository at this point in the history
* Fix action closures in async contexts.

* more tests

* utf8

* fix for implicit
  • Loading branch information
mbrandonw committed Jan 22, 2024
1 parent 4224012 commit 163090d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Sources/Perception/PerceptionRegistrar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ extension PerceptionRegistrar: Hashable {
guard
mangledSymbol.isMangledViewBodyGetter,
let demangled = String(Substring(mangledSymbol)).demangled,
!demangled.isSuspendingClosure,
!demangled.isActionClosure
else {
continue
Expand All @@ -247,6 +248,24 @@ extension PerceptionRegistrar: Hashable {
}

extension String {
fileprivate var isSuspendingClosure: Bool {
let fragment = self.utf8.drop(while: { $0 != .init(ascii: ")") }).dropFirst()
return fragment.starts(
with: " suspend resume partial function for closure".utf8
)
|| fragment.starts(
with: " suspend resume partial function for implicit closure".utf8
)
|| fragment.starts(
with: " await resume partial function for partial apply forwarder for closure".utf8
)
|| fragment.starts(
with: " await resume partial function for partial apply forwarder for implicit closure".utf8
)
|| fragment.starts(
with: " await resume partial function for implicit closure".utf8
)
}
fileprivate var isActionClosure: Bool {
var view = self[...].utf8
guard
Expand Down
49 changes: 49 additions & 0 deletions Tests/PerceptionTests/RuntimeWarningTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,55 @@
self.render(FeatureView())
}

func testAccessInOnAppearWithAsyncTask() async throws {
@MainActor
struct FeatureView: View {
let model = Model()
var body: some View {
Text("Hi")
.onAppear {
Task { @MainActor in _ = model.count }
}
}
}
self.render(FeatureView())
try await Task.sleep(for: .milliseconds(100))
}

func testAccessInOnAppearWithAsyncTask_Implicit() async throws {
@MainActor
struct FeatureView: View {
let model = Model()
var body: some View {
Text("Hi")
.onAppear {
Task(operation: self.perform)
}
}
@Sendable
func perform() async {
_ = model.count
}
}
self.render(FeatureView())
try await Task.sleep(for: .milliseconds(100))
}

func testAccessInTask() async throws {
@MainActor
struct FeatureView: View {
let model = Model()
var body: some View {
Text("Hi")
.task { @MainActor in
_ = model.count
}
}
}
self.render(FeatureView())
try await Task.sleep(for: .milliseconds(100))
}

private func render(_ view: some View) {
let image = ImageRenderer(content: view).cgImage
_ = image
Expand Down

0 comments on commit 163090d

Please sign in to comment.