swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.64k stars 10.38k forks source link

Custom trait with closure causes `@Test` macro to fail #76409

Open stephencelis opened 2 months ago

stephencelis commented 2 months ago

Description

When a custom trait takes a closure as an argument, the compiler crashes when the trait is used with @Test.

Expected behavior

I expect the compiler to not crash, and for the code to compile.

Actual behavior

The compiler crashes:

Stack dump… ``` 0. Program arguments: /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -emit-module -experimental-skip-non-inlinable-function-bodies-without-types "/Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift" -target arm64-apple-ios16.0-simulator -Xllvm -aarch64-use-tbi -enable-objc-interop -sdk /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.1.sdk -I /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Products/Debug-iphonesimulator -I /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/lib -F /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Products/Debug-iphonesimulator/PackageFrameworks -F /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Products/Debug-iphonesimulator/PackageFrameworks -F /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Products/Debug-iphonesimulator -F /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks -F /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.1.sdk/Developer/Library/Frameworks -no-color-diagnostics -enable-testing -g -debug-info-format=dwarf -dwarf-version=4 -module-cache-path /Users/stephen/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -profile-generate -profile-coverage-mapping -swift-version 6 -enforce-exclusivity=checked -Onone -D SWIFT_PACKAGE -D DEBUG -D Xcode -serialize-debugging-options -const-gather-protocols-file /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests_const_extract_protocols.json -enable-experimental-feature DebugDescriptionMacro -enable-experimental-feature OpaqueTypeErasure -empty-abi-descriptor -plugin-path /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins/testing -validate-clang-modules-once -clang-build-session-file /Users/stephen/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -working-directory -Xcc "/Users/stephen/Downloads/MyLibrary 2/.swiftpm/xcode" -resource-dir /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -enable-anonymous-context-mangled-names -file-compilation-dir "/Users/stephen/Downloads/MyLibrary 2/.swiftpm/xcode" -Xcc -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG -Xcc -ivfsstatcache -Xcc /Users/stephen/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.1-22B5023b-8bf8a4fc9b83a339b06f5e973931c9c1.sdkstatcache -Xcc -I/Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/DerivedSources-normal/arm64 -Xcc -I/Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/DerivedSources/arm64 -Xcc -I/Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/DerivedSources -Xcc -DSWIFT_PACKAGE -Xcc -DDEBUG=1 -module-name MyLibraryTests -package-name mylibrary_2 -frontend-parseable-output -disable-clang-spi -target-sdk-version 18.1 -target-sdk-name iphonesimulator18.1 -external-plugin-path /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/swift/host/plugins#/Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/local/lib/swift/host/plugins#/Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -plugin-path /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Applications/Xcode-16.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/lib/swift/host/plugins -emit-module-doc-path /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests.swiftdoc -emit-module-source-info-path /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests.swiftsourceinfo -serialize-diagnostics-path /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests-master-emit-module.dia -emit-dependencies-path /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests-master-emit-module.d -parse-as-library -o /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests.swiftmodule -emit-abi-descriptor-path /Users/stephen/Library/Developer/Xcode/DerivedData/MyLibrary_2-bksjtmcywreeqmfgaexuldssityr/Build/Intermediates.noindex/MyLibrary.build/Debug-iphonesimulator/MyLibraryTests.build/Objects-normal/arm64/MyLibraryTests.abi.json 1. Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1) 2. Compiling with the current language version 3. While evaluating request TypeCheckSourceFileRequest(source_file "/Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift") 4. While evaluating request ExpandPeerMacroRequest(MyLibraryTests.(file).example()@/Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift:8:6) 5. While evaluating request ResolveMacroRequest(custom-attr, 0x13b8e2208 FileUnit file="/Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift") 6. While type-checking expression at [/Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift:7:1 - line:7:17] RangeText="@Test(MyTrait {}" 7. While type-checking-target starting at /Users/stephen/Downloads/MyLibrary 2/Tests/MyLibraryTests/MyLibraryTests.swift:7:1 8. While evaluating request FragileFunctionKindRequest(0x13c8c8b48 AbstractClosureExpr line=7 : @Sendable () -> ()) Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): 0 swift-frontend 0x0000000106705194 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56 1 swift-frontend 0x00000001067033e8 llvm::sys::RunSignalHandlers() + 112 2 swift-frontend 0x0000000106705760 SignalHandler(int) + 292 3 libsystem_platform.dylib 0x00000001870b6584 _sigtramp + 56 4 swift-frontend 0x000000010294a8b0 swift::FragileFunctionKindRequest::OutputType swift::Evaluator::getResultCached(swift::Evaluator&, swift::FragileFunctionKindRequest, swift::FragileFunctionKindRequest::OutputType)::'lambda'(), (void*)0>(swift::FragileFunctionKindRequest const&, swift::FragileFunctionKindRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::FragileFunctionKindRequest, swift::FragileFunctionKindRequest::OutputType)::'lambda'()) + 1256 5 swift-frontend 0x000000010294a8b0 swift::FragileFunctionKindRequest::OutputType swift::Evaluator::getResultCached(swift::Evaluator&, swift::FragileFunctionKindRequest, swift::FragileFunctionKindRequest::OutputType)::'lambda'(), (void*)0>(swift::FragileFunctionKindRequest const&, swift::FragileFunctionKindRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::FragileFunctionKindRequest, swift::FragileFunctionKindRequest::OutputType)::'lambda'()) + 1256 6 swift-frontend 0x00000001023e7b14 swift::ExportContext::forFunctionBody(swift::DeclContext*, swift::SourceLoc) + 208 7 swift-frontend 0x00000001023f7888 (anonymous namespace)::ExprAvailabilityWalker::walkToExprPre(swift::Expr*) + 2880 8 swift-frontend 0x00000001023f7e90 (anonymous namespace)::ExprAvailabilityWalker::walkToArgumentPre(swift::Argument const&) + 52 9 swift-frontend 0x000000010280efbc (anonymous namespace)::Traversal::visit(swift::ArgumentList*) + 208 10 swift-frontend 0x000000010280bba4 (anonymous namespace)::Traversal::visitApplyExpr(swift::ApplyExpr*) + 196 11 swift-frontend 0x00000001028090c8 (anonymous namespace)::Traversal::visit(swift::Expr*) + 88 12 swift-frontend 0x00000001023f7eb4 (anonymous namespace)::ExprAvailabilityWalker::walkToArgumentPre(swift::Argument const&) + 88 13 swift-frontend 0x000000010280efbc (anonymous namespace)::Traversal::visit(swift::ArgumentList*) + 208 14 swift-frontend 0x000000010280be7c (anonymous namespace)::Traversal::visitFreestandingMacroArgs(swift::FreestandingMacroExpansion*) + 152 15 swift-frontend 0x000000010280b864 (anonymous namespace)::Traversal::visitMacroExpansionExpr(swift::MacroExpansionExpr*) + 164 16 swift-frontend 0x000000010280954c (anonymous namespace)::Traversal::visit(swift::Expr*) + 1244 17 swift-frontend 0x00000001023f057c swift::diagnoseExprAvailability(swift::Expr const*, swift::DeclContext*) + 252 18 swift-frontend 0x0000000102368e38 swift::performSyntacticExprDiagnostics(swift::Expr const*, swift::DeclContext const*, std::__1::optional, bool, bool, bool) + 3584 19 swift-frontend 0x000000010242c4d8 swift::TypeChecker::typeCheckTarget(swift::constraints::SyntacticElementTarget&, swift::optionset::OptionSet) + 720 20 swift-frontend 0x000000010242c0e4 swift::TypeChecker::typeCheckExpression(swift::constraints::SyntacticElementTarget&, swift::optionset::OptionSet) + 416 21 swift-frontend 0x00000001024c8688 swift::ResolveMacroRequest::evaluate(swift::Evaluator&, swift::UnresolvedMacroReference, swift::DeclContext*) const + 1760 22 swift-frontend 0x00000001024a24c0 swift::ResolveMacroRequest::OutputType swift::Evaluator::getResultUncached(swift::Evaluator&, swift::ResolveMacroRequest, swift::ResolveMacroRequest::OutputType)::'lambda'()>(swift::ResolveMacroRequest const&, swift::ResolveMacroRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::ResolveMacroRequest, swift::ResolveMacroRequest::OutputType)::'lambda'()) + 600 23 swift-frontend 0x00000001024a2220 swift::ResolveMacroRequest::OutputType swift::Evaluator::getResultCached(swift::Evaluator&, swift::ResolveMacroRequest, swift::ResolveMacroRequest::OutputType)::'lambda'(), (void*)0>(swift::ResolveMacroRequest const&, swift::ResolveMacroRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::ResolveMacroRequest, swift::ResolveMacroRequest::OutputType)::'lambda'()) + 260 24 swift-frontend 0x000000010286bf58 swift::Decl::forEachAttachedMacro(swift::MacroRole, llvm::function_ref) const + 372 25 swift-frontend 0x00000001024c480c swift::ExpandPeerMacroRequest::evaluate(swift::Evaluator&, swift::Decl*) const + 84 26 swift-frontend 0x000000010252f4c8 swift::ExpandPeerMacroRequest::OutputType swift::Evaluator::getResultUncached(swift::Evaluator&, swift::ExpandPeerMacroRequest, swift::ExpandPeerMacroRequest::OutputType)::'lambda'()>(swift::ExpandPeerMacroRequest const&, swift::ExpandPeerMacroRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::ExpandPeerMacroRequest, swift::ExpandPeerMacroRequest::OutputType)::'lambda'()) + 612 27 swift-frontend 0x000000010252f1c8 swift::ExpandPeerMacroRequest::OutputType swift::Evaluator::getResultCached(swift::Evaluator&, swift::ExpandPeerMacroRequest, swift::ExpandPeerMacroRequest::OutputType)::'lambda'(), (void*)0>(swift::ExpandPeerMacroRequest const&, swift::ExpandPeerMacroRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::ExpandPeerMacroRequest, swift::ExpandPeerMacroRequest::OutputType)::'lambda'()) + 328 28 swift-frontend 0x000000010286bb70 swift::Decl::visitAuxiliaryDecls(llvm::function_ref, bool) const + 264 29 swift-frontend 0x000000010247f9a8 (anonymous namespace)::DeclChecker::visit(swift::Decl*) + 148 30 swift-frontend 0x000000010247f904 swift::TypeChecker::typeCheckDecl(swift::Decl*) + 152 31 swift-frontend 0x000000010256694c swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&, swift::SourceFile*) const + 660 32 swift-frontend 0x000000010256dfdc swift::TypeCheckSourceFileRequest::OutputType swift::Evaluator::getResultUncached(swift::Evaluator&, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()>(swift::TypeCheckSourceFileRequest const&, swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefault(swift::Evaluator&, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()) + 620 33 swift-frontend 0x000000010256669c swift::performTypeChecking(swift::SourceFile&) + 328 34 swift-frontend 0x000000010148c030 swift::CompilerInstance::performSema() + 332 35 swift-frontend 0x00000001010ba690 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1528 36 swift-frontend 0x00000001010b9458 swift::performFrontend(llvm::ArrayRef, char const*, void*, swift::FrontendObserver*) + 3572 37 swift-frontend 0x000000010104050c swift::mainEntry(int, char const**) + 3680 38 dyld ```

Steps to reproduce

Paste the following into a test file and build tests:

import Testing

struct MyTrait: TestTrait, SuiteTrait {
  let operation: @Sendable () -> Void
}

@Test(MyTrait {})
func example() async throws {
}

swift-testing version/commit hash

Xcode 16 RC

Swift & OS version (output of swift --version ; uname -a)

swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2) Target: arm64-apple-macosx14.0 Darwin Stephens-MacBook-Pro.lan 23.6.0 Darwin Kernel Version 23.6.0: Mon Jul 29 21:13:04 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6020 arm64

stmontgomery commented 2 months ago

Thanks for the report. Seems like this ought to work, but it's almost definitely an issue somewhere in the compiler so I'll transfer it there.

stephencelis commented 2 months ago

Surprisingly this does not cause a problem when defining a similar #Preview trait, so it might be specific to attached macros.

stephencelis commented 2 months ago

@stmontgomery While this may be a Swift bug in macros, could it be that there's problematic macro code in Swift Testing that is exacerbating the problem? We've encountered our fair share of Swift macro crashes but have found ways to work around the majority of them by tweaking our own macro code.

stmontgomery commented 1 month ago

@stmontgomery While this may be a Swift bug in macros, could it be that there's problematic macro code in Swift Testing that is exacerbating the problem?

To rule that out, I created a minimal Swift package with an attached, peer macro and was still able to reproduce this crash when one of the arguments to the attached macro is an expression containing a closure.

See AttachedMacroTrailingClosure.zip to view the full source of my small example package, but here's the code:

struct Trait {
  init(_: () -> Void) {}
}

@attached(peer) macro trait(_ trait: Trait) = #externalMacro(module: "ExampleMacros", type: "TraitMacro")

@trait(Trait {})  // 💥 compiler crash
func example() {}

Relevant backtrace:

3.  While evaluating request TypeCheckSourceFileRequest(source_file ".../AttachedMacroTrailingClosure/Sources/ExampleClient/main.swift")
4.  While evaluating request ExpandPeerMacroRequest(ExampleClient.(file).example()@.../AttachedMacroTrailingClosure/Sources/ExampleClient/main.swift:8:6)
5.  While evaluating request ResolveMacroRequest(custom-attr, 0x13e057808 FileUnit file=".../AttachedMacroTrailingClosure/Sources/ExampleClient/main.swift")
6.  While type-checking expression at [.../AttachedMacroTrailingClosure/Sources/ExampleClient/main.swift:7:1 - line:7:16] RangeText="@trait(Trait {}"
7.  While type-checking-target starting at .../AttachedMacroTrailingClosure/Sources/ExampleClient/main.swift:7:1
8.  While evaluating request FragileFunctionKindRequest(0x13c83fca8 AbstractClosureExpr line=7 : () -> ())
stmontgomery commented 1 month ago

Tracked internally as rdar://136997841