Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-14764] @MainActor ignored by the compiler #57114

Closed
DevAndArtist mannequin opened this issue Jun 11, 2021 · 3 comments
Closed

[SR-14764] @MainActor ignored by the compiler #57114

DevAndArtist mannequin opened this issue Jun 11, 2021 · 3 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@DevAndArtist
Copy link
Mannequin

DevAndArtist mannequin commented Jun 11, 2021

Previous ID SR-14764
Radar rdar://problem/79352544
Original Reporter @DevAndArtist
Type Bug
Status Resolved
Resolution Done
Environment

Version 13.0 beta (13A5154h)
swift-driver version: 1.26 Apple Swift version 5.5 (swiftlang-1300.0.19.104 clang-1300.0.18.4)
Target: arm64-apple-macosx11.0

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 489030d069b5154dcc245685ee400a89

Issue Description:

Compiler seems to ignore `@MainActor` in the following code example:

import SwiftUI

class Model: ObservableObject {
  @Published
  var data: Data?
}

struct TestView: View {
  @ObservedObject
  var _model = Model()

  @MainActor
  func apply(_ data: Data) {
    // runtime warning:
    // Publishing changes from background threads is not allowed; make
    // sure to publish values from the main thread (via operators like
    // receive(on:)) on model updates.

    _model.data = data

    // runtime crash
    dispatchPrecondition(condition: .onQueue(.main))
  }

  func fetchData() async throws {
    let urlString = "https://google.com"
    guard case let url? = URL(string: urlString) else {
      return
    }
    let (data, response) = try await URLSession.shared.data(from: url)
    guard
      case let httpResponse? = response as? HTTPURLResponse,
      httpResponse.statusCode == 200
    else {
      return
    }

    // note there is NO `await` here as the compiler does not ask for it at all
    apply(data)
  }

  var body: some View {
    Text("\(_model.data.map(\.count) ?? 0)")
      .task {
        do {
          try await fetchData()
        } catch {
          print(error)
        }
      }
  }
}

I can try adding `await` infant of the `apply` call, but this results into a `No 'async' operations occur within 'await' expression` warning.

I can apply two workarounds:

  • Make `apply(_: )` method `async` and add `await` infant of it as the compiler correctly would ask for, but this doesn't make sense as this should be a non-suspendible synchronous method just to hop back to the main thread and sign the value.

  • I can move `@MainActor` to the entire type and make `fetchData` as `nonisolated`, which works as intended, but the original example should also work and require the `await` keyword.

Discussion on the forum: https://forums.swift.org/t/mainactor-ignored-by-the-compiler/49533

@typesanitizer
Copy link

@swift-ci create

@DougGregor
Copy link
Member

This was fixed by #40388 and I'm adding a more-specific test in #40522

@swift-ci
Copy link
Collaborator

Comment by Erik Aigner (JIRA)

I have the same issue, @MainActory should either make the method async implicitly or require the async keyword

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

3 participants