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

The generated initializer doesn't work inside the #Preview macro #26

Open
2 tasks done
kuglee opened this issue Dec 4, 2023 · 3 comments
Open
2 tasks done

The generated initializer doesn't work inside the #Preview macro #26

kuglee opened this issue Dec 4, 2023 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@kuglee
Copy link

kuglee commented Dec 4, 2023

Description

Thanks for making this macro. I'd like to use it unfortunately the generated initializer doesn't work inside the #Preview macro.

Example:

import SwiftUI
import MemberwiseInit

@MemberwiseInit struct Test {
  let test: Int
}

struct ContentView: View {
  init(test: Test) {}

  var body: some View {
    EmptyView()
  }
}

#Preview {
  ContentView(test: Test(test: 1)) // 🛑 'Test' cannot be constructed because it has no accessible initializers
}

Checklist

  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

I've expected the code above to work.

Actual behavior

The code above doesn't compile: 'Test' cannot be constructed because it has no accessible initializers

Steps to reproduce

No response

swift-memberwise-init-macro version information

main

Destination operating system

macOS 14.1.1

Xcode version information

15.0 (15A240d)

Swift Compiler version information

swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.108 clang-1500.0.40.1)
@kuglee kuglee added the bug Something isn't working label Dec 4, 2023
@gohanlon gohanlon self-assigned this Dec 4, 2023
@gohanlon
Copy link
Owner

gohanlon commented Dec 4, 2023

Thanks for the report! This seems to be a rather unfortunate upstream bug; feedback filed: FB13443736. I also reproduced this bug in the latest Xcode 15.1 beta 3 (15C5059c). I think the best we can do for now is fall back to the old PreviewProvider syntax:

#if DEBUG
struct ContentView_Preview: PreviewProvider {
  static var previews: some View {
    ContentView(test: Test(test: 1))
  }
}
#endif

If you inline the #Preview macro in your example using Xcode's "Refactor → Inline Macro" and strip the leading "$" from the generated name, it compiles as expected. That's not a workaround, tho: Xcode won't recognize it as a preview (and the expanded code is unpleasant).

Furthermore, this can be generalized to any closure argument given to a macro:

@MemberwiseInit
public struct ClosureTest {
  @Init(default: { Test(test: 1) }) let name: () -> Test
//                 ┬────────────
//                 ╰─ 🛑 'Test' cannot be constructed because it has no accessible initializers
}

The compiler is type-checking the closure argument without expanding macros first. This presents a complex situation where the dependency between macro expansion and type checking isn't properly resolved by the compiler.

Note
I found a related issue that's since been resolved where #Preview failed similarly when members were added to a type via an extension in the same file. See: #Preview macro can’t find member which is added via an extension and FB 110671628.

@kuglee
Copy link
Author

kuglee commented Dec 5, 2023

Thanks you for your answer 🙏

@gohanlon
Copy link
Owner

gohanlon commented Jul 6, 2024

This issue persists with Xcode 16.0 (16A242d) and Swift 6:

% swift --version      
swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2)
Target: arm64-apple-macosx15.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants